CUDA实例系列四:利用GPU加速Sobel边缘检测

先简单的介绍一下Sobel边缘检测:

Sobel算子是图像处理中常用的算子之一, 在计算机视觉中常用来做边缘检测. 它是一个比较小并且是整数的filter, 所需要的计算相对较少, 但是对于图像中频率变化较高的地方,他所得的梯度近似值会比较粗糙.

它包含两组 3 x 3的矩阵,分别为横向和纵向与图像做平面卷积. 即:

即可分别得出横向及纵向的亮度差分近似值. 如果A代表原始图像, GxG_xGx​和GyG_yGy​分别代表横向及纵向边缘检测的图像, 公式如下:

图像的每一个像素的横向及纵向梯度近似值可用以下公式结合, 来计算梯度大小.

简单点说用个动画来表示可能更清晰:

而用CUDA解决这个问题的原理就是, 每个线程处理一个像素.每个线程读取一个像素周围的数值(下面代码注释中的x0~x8), 然后进行计算

代码如下:

#include "cuda_runtime.h"
#include <cudnn.h>
#include <cuda.h>
#include <device_functions.h>
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;//GPU实现Sobel边缘检测
//             x0 x1 x2
//             x3 x4 x5
//             x6 x7 x8
__global__ void sobel_gpu(unsigned char* in, unsigned char* out, int imgHeight, int imgWidth)
{int x = threadIdx.x + blockDim.x * blockIdx.x;int y = threadIdx.y + blockDim.y * blockIdx.y;int index = y * imgWidth + x;int Gx = 0;int Gy = 0;unsigned char x0, x1, x2, x3, x4, x5, x6, x7, x8;if (x > 0 && x < imgWidth-1 && y > 0 && y < imgHeight-1){x0 = in[(y - 1) * imgWidth + x - 1];x1 = in[(y - 1) * imgWidth + x ];x2 = in[(y - 1) * imgWidth + x + 1];x3 = in[(y ) * imgWidth + x - 1];x4 = in[(y ) * imgWidth + x ];x5 = in[(y ) * imgWidth + x + 1];x6 = in[(y + 1) * imgWidth + x - 1];x7 = in[(y + 1) * imgWidth + x ];x8 = in[(y + 1) * imgWidth + x + 1];Gx = (x0 + 2 * x3 + x6) - (x2 + 2 * x5 + x8);Gy = (x0 + 2 * x1 + x2) - (x6 + 2 * x7 + x8);out[index] = (abs(Gx) + abs(Gy)) / 2;//printf("out[%d]: %d", index, out[index]);}
}//CPU实现Sobel边缘检测
void sobel_cpu(Mat srcImg, Mat dstImg, int imgHeight, int imgWidth)
{int Gx = 0;int Gy = 0;for (int i = 1; i < imgHeight - 1; i++){uchar* dataUp = srcImg.ptr<uchar>(i - 1);uchar* data = srcImg.ptr<uchar>(i);uchar* dataDown = srcImg.ptr<uchar>(i + 1);uchar* out = dstImg.ptr<uchar>(i);for (int j = 1; j < imgWidth - 1; j++){Gx = (dataUp[j + 1] + 2 * data[j + 1] + dataDown[j + 1]) - (dataUp[j - 1] + 2 * data[j - 1] + dataDown[j - 1]);Gy = (dataUp[j - 1] + 2 * dataUp[j] + dataUp[j + 1]) - (dataDown[j - 1] + 2 * dataDown[j] + dataDown[j + 1]);out[j] = (abs(Gx) + abs(Gy)) / 2;}}
}int main()
{//利用opencv的接口读取图片Mat img = imread("1.jpg",0);int imgWidth = img.cols;int imgHeight = img.rows;//int imgChannel = img.channels();//利用opencv的接口对读入的grayImg进行去噪Mat gaussImg;GaussianBlur(img, gaussImg, Size(3, 3), 0, 0, BORDER_DEFAULT);//CPU结果为dst_cpu, GPU结果为dst_gpuMat dst_cpu(imgHeight, imgWidth, CV_8UC1, Scalar(0));Mat dst_gpu(imgHeight, imgWidth, CV_8UC1, Scalar(0,0,0));   //调用sobel_cpu处理图像sobel_cpu(gaussImg, dst_cpu, imgHeight, imgWidth);//申请指针并将它指向GPU空间size_t num = imgHeight * imgWidth * sizeof(unsigned char);unsigned char* in_gpu;unsigned char* out_gpu;cudaMalloc((void**)&in_gpu, num);cudaMalloc((void**)&out_gpu, num);//定义grid和block的维度(形状)dim3 threadsPerBlock(32, 32);dim3 blocksPerGrid((imgWidth + threadsPerBlock.x - 1) / threadsPerBlock.x,(imgHeight + threadsPerBlock.y - 1) / threadsPerBlock.y);//将数据从CPU传输到GPUcudaMemcpy(in_gpu, img.data, num, cudaMemcpyHostToDevice);//调用在GPU上运行的核函数sobel_gpu <<<blocksPerGrid, threadsPerBlock>> > (in_gpu, out_gpu, imgHeight, imgWidth);//将计算结果传回CPU内存cudaMemcpy(dst_gpu.data, out_gpu, num, cudaMemcpyDeviceToHost);/*for (int i = 0; i < num; i++){printf("%d ", dst_gpu.data[i]);if (i % imgWidth == 0) printf("\n");}*///显示处理结果imshow("gpu", dst_gpu);imshow("cpu", img);waitKey(0);//释放GPU内存空间cudaFree(in_gpu);cudaFree(out_gpu);return 0;
}

CUDA实例系列四:利用GPU加速Sobel边缘检测(含源码)相关推荐

  1. CUDA实例系列三:利用GPU优化向量规约问题

    CUDA实例系列三:利用GPU优化向量规约问题 先简单的描述一下题目中说的向量规约问题. 这里举个例子, 比如: 我要求出1+2+3-+100的和 我要求出123-*100的积 我要找到a[100]中 ...

  2. 利用汇编和C语言实现Exynos4412裸机开发系列之实现LED跑马灯(含源码)

    一.前言 本篇使用华清远见的FS4412开发板,对开发板的LED进行操作,来实现流水灯的效果,知识包含GPIO寄存器介绍.与ubuntu下linux操作系统通过进行交叉编译生成开发板可执行代码,通过本 ...

  3. CUDA实例系列一: 矩阵乘法优化

    CUDA实例系列一----矩阵乘法优化 很多朋友在学习CUDA的时候都会面临一个题目----矩阵乘法, 这也是CUDA最广泛的应用之一. 本文将详细讲解如何利用GPU加速矩阵乘法的计算. 话不多说, ...

  4. 利用 GPU 加速人工智能:新型计算模式

    纽约大学本周有一场探讨 "人工智能的未来" 的年度座谈会,Yann LeCun 邀请NVIDIA 联合创始人兼首席执行官黄仁勋 (Jen-Hsun Huang)先生在座谈会上发言. ...

  5. (含源码)利用NVIDIA VPI之透视变换

    (含源码)利用NVIDIA VPI之透视变换 更多精彩内容: https://www.nvidia.cn/gtc-global/?ncid=ref-dev-876561 文章目录 (含源码)利用NVI ...

  6. 低CUDA算力显卡用上高版本pytorch(ubuntu18.04源码编译特定版本pytorch(v1.10.0))

    低CUDA算力显卡用上高版本pytorch(ubuntu18.04源码编译特定版本pytorch(v1.10.0)) 一 电脑配置 二 正常情况下源码编译步骤 三 我的编译过程及出现的问题 首先 安装 ...

  7. 基于JAVA四六级在线考试系统计算机毕业设计源码+数据库+lw文档+系统+部署

    基于JAVA四六级在线考试系统计算机毕业设计源码+数据库+lw文档+系统+部署 基于JAVA四六级在线考试系统计算机毕业设计源码+数据库+lw文档+系统+部署 本源码技术栈: 项目架构:B/S架构 开 ...

  8. android 原生开发 3d地图 下载_arcgis api 3.x for js 入门开发系列二不同地图服务展示(附源码下载)...

    前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...

  9. php调用接口搜索的网页源代码,PHP用户管理中常用接口调用实例及解析(含源码)...

    掌握用户的第一步就是将已经关注的粉丝信息保存起来,这个时候就用到获取用户列表接口.公众号可通过本接口来获取帐号的关注者列表,关注者列表由一串OpenID(加密后的微信号,每个用户对每个公众号的Open ...

  10. 微信公众平台开发4-长链接转短链接口调用实例(含源码)

    微信公众平台开发-access_token获取及应用(含源码) 作者: 孟祥磊-<微信公众平台开发实例教程> 将一条长链接转成短链接.开发者用于生成二维码的原链接(商品.支付二维码等)太长 ...

最新文章

  1. 另类vs2015+xamarin 的android界面乱码 解决
  2. 写时复制就这么几行代码,还是不会?
  3. 整理JavaScript中,数组和字符的操作方法
  4. mysql 跨服务器 etl_mysql数据库跨服务器查询【需要确定mysql支持FEDERATED ,可以参照文章内容自己配置】...
  5. ORA-600 各个参数含义说明
  6. oozie的常见错误
  7. IT桌面运维常识系列 - MDT
  8. 偏光太阳镜测试图片软件,[专题]真假偏光太阳镜简单、实用辨别方法!
  9. Qt5+STM32F407+步进电机 | 通过电脑控制步进电机实现:6+2通道、速度可变、运动精确步数的教程——基础知识(2/4)
  10. MAXHUB会议平板的无线投屏怎么用?
  11. ros中odometry数据生成方式与分发去向
  12. python包导入细节
  13. 为什么域名还会被DNS污染?域名被污染清洗方法!
  14. 一个具有多个组件的在线平面图设计 平面图 在线制图
  15. 报警:Component 'MSCOMCTLOCX' or one of its dependencies .....及解决方法
  16. python整形怎么切片_遥感影像切分切片
  17. 层次分析法原理分析及Python实现层析分析法
  18. 安卓使用WebView清除缓存
  19. 20222948 2022-2023-2 《网络攻防实践》第4周作业
  20. 单目深度估计 | Learning Depth from Monocular Videos using Direct Methods 学习笔记

热门文章

  1. 银行家算法C++代码实现
  2. 【图像处理】色彩空间 YUV 420 SP / YUV 420 P 含义 RGB转换 YUV 黑色怎么表示
  3. Java单例模式实现方式
  4. c语言考试中操作题文件,计算机二级考试C语言操作题题库(21页)-原创力文档...
  5. 计算机二级Office选择题考题大全【掌握】
  6. 2015计算机二级office真题,2015年计算机二级office题库及答案
  7. 基于MATLAB的有源三相滤波器的设计,基于MATLAB的电力系统有源滤波器设计
  8. Python导入Excel名单实现随机抽取
  9. matlab指派问题求法,matlab求解指派问题
  10. UVA 10480 Sabotage (最大流最小割)