引言

关于图像边缘检测,记得刚开始接触图像处理时,第一个自己实现的程序是通过笔记本摄像头采集图像,利用OpenCV自带的算法库进行Canny算子边缘检测,那时候当看到程序运行后,视频窗口实时显示经Canny算子边缘分割后的图像,觉得十分有科技感,后来慢慢开始自己写边缘检测的源代码,本博客以Sobel算子为例,将边缘检测通过CUDA实现。

任务要求

输入一张图片,将其转为灰度图后,通过CUDA在GPU中对图片实现Sobel算子边缘检测,最后将结果输出至CPU并进行显示,要求输出图与用CPU内实现后的结果一致。

实现思路

关于Sobel算子的边缘检测原理,可看此博客Sobel边缘检测算法 
由于检测的原理是通过对Gx和Gy两个方向的卷积,故在CUDA实现时我们需要正确索引到以目标像素点为中心的3*3的小方格中各个元素的位置,由于图像从CPU端传给GPU是一段一维连续的内存,增大了我们索引的难度,故在block和grid的设计上,我把整张图像完整的映射到了grid中,每个thread即对应一个像素,通过二维索引的方法将一维的内存准确映射。

实现环境

VS2013 + CUDA7.5 + Opencv2.4.13

实现代码

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <cuda.h>
#include <device_functions.h>
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;//Sobel算子边缘检测核函数
__global__ void sobelInCuda(unsigned char *dataIn, unsigned char *dataOut, int imgHeight, int imgWidth)
{int xIndex = threadIdx.x + blockIdx.x * blockDim.x;int yIndex = threadIdx.y + blockIdx.y * blockDim.y;int index = yIndex * imgWidth + xIndex;int Gx = 0;int Gy = 0;if (xIndex > 0 && xIndex < imgWidth - 1 && yIndex > 0 && yIndex < imgHeight - 1){Gx = dataIn[(yIndex - 1) * imgWidth + xIndex + 1] + 2 * dataIn[yIndex * imgWidth + xIndex + 1] + dataIn[(yIndex + 1) * imgWidth + xIndex + 1]- (dataIn[(yIndex - 1) * imgWidth + xIndex - 1] + 2 * dataIn[yIndex * imgWidth + xIndex - 1] + dataIn[(yIndex + 1) * imgWidth + xIndex - 1]);Gy = dataIn[(yIndex - 1) * imgWidth + xIndex - 1] + 2 * dataIn[(yIndex - 1) * imgWidth + xIndex] + dataIn[(yIndex - 1) * imgWidth + xIndex + 1]- (dataIn[(yIndex + 1) * imgWidth + xIndex - 1] + 2 * dataIn[(yIndex + 1) * imgWidth + xIndex] + dataIn[(yIndex + 1) * imgWidth + xIndex + 1]);dataOut[index] = (abs(Gx) + abs(Gy)) / 2;}
}//Sobel算子边缘检测CPU函数
void sobel(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()
{Mat grayImg = imread("1.jpg", 0);int imgHeight = grayImg.rows;int imgWidth = grayImg.cols;Mat gaussImg;//高斯滤波GaussianBlur(grayImg, gaussImg, Size(3, 3), 0, 0, BORDER_DEFAULT);//Sobel算子CPU实现Mat dst(imgHeight, imgWidth, CV_8UC1, Scalar(0));sobel(gaussImg, dst, imgHeight, imgWidth);//CUDA实现后的传回的图像Mat dstImg(imgHeight, imgWidth, CV_8UC1, Scalar(0));//创建GPU内存unsigned char *d_in;unsigned char *d_out;cudaMalloc((void**)&d_in, imgHeight * imgWidth * sizeof(unsigned char));cudaMalloc((void**)&d_out, imgHeight * imgWidth * sizeof(unsigned char));//将高斯滤波后的图像从CPU传入GPUcudaMemcpy(d_in, gaussImg.data, imgHeight * imgWidth * sizeof(unsigned char), cudaMemcpyHostToDevice);dim3 threadsPerBlock(32, 32);dim3 blocksPerGrid((imgWidth + threadsPerBlock.x - 1) / threadsPerBlock.x, (imgHeight + threadsPerBlock.y - 1) / threadsPerBlock.y);//调用核函数sobelInCuda << <blocksPerGrid, threadsPerBlock >> >(d_in, d_out, imgHeight, imgWidth);//将图像传回GPUcudaMemcpy(dstImg.data, d_out, imgHeight * imgWidth * sizeof(unsigned char), cudaMemcpyDeviceToHost);//释放GPU内存cudaFree(d_in);cudaFree(d_out);return 0;
}

实现结果

原图 
 

CPU实现后图像 

CUDA实现后图像 
 

通过比对发现CUDA输出结果与CPU实现输出结果一致~

CUDA精进之路(四):图像处理——Sobel算子边缘检测相关推荐

  1. FPGA图像处理——sobel算子边缘检测

    一.sobel算子边缘检测理论 sobel算子是广泛应用的微分算子之一,可以计算图像处理中的边缘检测,计算图像的灰度地图.在技术上,它是一个离散的一阶差分算子,用来计算图像亮度函数的一阶梯度之近似值. ...

  2. dsp图像处理Prewitt算子边缘检测

    --(完整工程文件到我的资源下载) Prewitt算子边缘检测 一.实验背景与意义 图像处理就是对信息加工以满足人的视觉心理或应用需求的方法.图像处理的方法有光学方法和电子学方法.从20世纪60年代起 ...

  3. 【8】python-opencv3教程:边缘检测(Roberts算子边缘检测,Prewitt算子边缘检测,Sobel算子边缘检测)

    第八节:边缘检测 边缘检测:边缘检测指的是灰度值发生急剧变化的位置,边缘检测的目的是制作一个线图,在不会损害理解图像内容的情况下, 有大大减少了图像的数据量,提供了对图像数据的合适概述. 一:Robe ...

  4. CUDA精进之路(二):图像处理——形态学滤波(膨胀、腐蚀、开闭运算)

    引言 从这篇文章起,开始将一些较为典型的OpenCV算法通过CUDA进行实现,本文实现的为图像处理中最为常见的形态学腐蚀以及膨胀,由于本文目的在于算法移植后的验证,故在图片的选择上用小图像作为输入的示 ...

  5. CUDA精进之路(一):图像处理——大图像分块处理(包括求均值、最大值)

    引言 在我的第一篇文章中我简单介绍了CUDA以及我的一些个人学习见解,在本文中我将开始正式开始CUDA实践之旅,众做周知CUDA目前应用的领域十分广泛,它能把一些普通的CPU代码提速几十倍甚至几百倍. ...

  6. CUDA精进之路(五):图像处理——OTSU二值算法(最大类间方差法、大津法)

    引言 最近在做医疗设备相关的项目,故在项目中大量用到了各类图像分割的算法,为了在图像中分割出特定目标,用到的算法可以有很多,比如阈值分割,多通道分割,边缘分割以及一些前沿的组合分割.而对大多数图像来说 ...

  7. CUDA精进之路(三):图像处理——图像灰度化、灰度直方图统计

    引言 在大部分的图像处理程序中,其中必不可少的一步就是对传入的彩图进行灰度处理,将三个通道的RGB图片转化为单通道的Gray图,而对于灰度图进行直方图统计同样是观察检测图像特征的常用方法.在OpenC ...

  8. CUDA精进之路(零):CUDA开篇

    前言 着手机器视觉项目时接触到了并行编程这一概念,那时候的目的是为了在图像识别的时候通过多个线程同时对多张传入的图片进行并行处理以达到加速程序运行速度,运用的方法主要是利用了C++自带的future库 ...

  9. Nexys4DDR+OV7670实现sobel算子边缘检测系统

    在之前发布的实验中,已经实现Nexys4DDR+OV7670实时视频采集系统,在此基础上进行sobel边缘检测处理与显示 硬件环境:Nexys4 DDR 软件环境 :vivado 2018.2 编程语 ...

最新文章

  1. Mantis 缺陷管理系统配置与安装
  2. css设置元素继承父元素宽度_前端新手必知-5种新型的CSS长度单位
  3. 用python解“逆序三位数”问题
  4. 用户吐槽:Azure DevOps CI 体验太差
  5. facebook海量图片存储系统与淘宝TFS系统比较
  6. 关于会计科目表,科目组,字段状态组
  7. mysql如果数据不存在,则插入新数据,否则更新
  8. 在容器上构建持续部署及最佳实践初探
  9. pythonstdin_python 笔试输入:sys.stdin.readline和input
  10. C# log4net纯代码设置参数
  11. 阿里云2017财年:营收66.63亿 同比增长121%
  12. pdf417条形码开发
  13. Three.js-物理引擎(Physics)
  14. HTTP长连接和WebSocket长连接的区别
  15. 阿里天池大数据竞赛——口碑商家客流量预测 A1
  16. 问题解决--npm install 安装依赖一直失败
  17. win7计算机无法最大化,win7系统窗口老是以最大化显示且不能还原的具体方法
  18. ios 去除字符串首尾空格、换行
  19. ActivityManagerService解读之Activity启动时间闲聊--Android Framework层时间计算介绍
  20. Spark数据清洗案例

热门文章

  1. 讲座笔记:图匹配 Graph Matching 问题 | 机器学习组合优化
  2. 佛祖保佑代码无bug图片_程序员都有哪些奇趣的代码注释,细思极恐
  3. webhooks php,GitHub和WebHooks自动部署PHP项目
  4. java实时检测_JAVA 实时检测二进制流字符集
  5. MyEclipse的代码提示功能
  6. HTML基本语法九 会移动的文字
  7. 买不买D50的N个理由
  8. Arcgis javascript那些事儿(十五)——影像服务的发布与使用
  9. ArcGIS水文分析实战教程(12)河网分级流程
  10. Modelbuilder快速入门