您的位置:首页 > 其它

cuda实践之sobel边缘检测实现

2017-08-15 11:05 323 查看

1. Sobel算法

Sobel是一个离散的一阶差分算子,用来计算图像亮度函数的一阶梯度之近似值。在图像的任何一点使用此算子,将会产生该点对应的梯度矢量或是其法矢量

该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以A代表原始图像,Gx及Gy分别代表经横向及纵向边缘检测的图像,其公式如下:



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



可用以下公式计算梯度方向:



2.cuda编程实现:

1.sobel.hpp文件

#include<opencv2/opencv.hpp>
void sobel_func(uchar *img,uchar *sobel);


2.sobel.cu文件

#include <cuda_runtime.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <opencv2/opencv.hpp>
#include "sobel.hpp"

//此处本例程处理的图片大小为640x480
const int W =640;
const int H =480;

uchar *cuda_sobelin,*cuda_sobel;
__device__ int sobel_gpu(uchar a, uchar b, uchar c, uchar d, uchar e, uchar f){
return ((a + 2*b + c) - (d + 2*e + f));
}
void setCudaDevice(int devNum)
{
cudaDeviceProp devProp;
cudaGetDeviceProperties(&devProp, devNum);
cudaSetDevice(devNum);
}
//核函数
__global__ void sobel_gpu(uchar * img_in, uchar * img_out,int img_w, int img_h)
{
int row = blockDim.y * blockIdx.y + threadIdx.y;
int col = blockDim.x * blockIdx.x + threadIdx.x;

if((row >= 1) && (row < (img_h-1)) && (col >= 1) && (col < (img_w-1)))
{
uchar x1, x2, x3, x4,  x6, x7, x8,x9;
x1=img_in[(row-1)*img_w+(col-1)];
x2=img_in[(row-1)*img_w+col];
x3=img_in[(row-1)*img_w+col+1];
x4=img_in[row*img_w+col-1];
x6=img_in[row*img_w+col+1];
x7=img_in[(row+1)*img_w+col-1];
x8=img_in[(row+1)*img_w+col];
x9=img_in[(row+1)*img_w+col+1];
int dfdy= sobel_gpu(x1, x2, x3, x7, x8, x9);
int dfdx= sobel_gpu(x1, x4, x7, x3, x6, x9);
int gradient= sqrtf(dfdy*dfdy+dfdx*dfdx);
img_out[row*img_w+col] = gradient;
}
}

void sobel_func(uchar *img,uchar *sobelout)
{
setCudaDevice(0);
cudaMalloc((void**)&cuda_sobelin, sizeof(uchar)* W*H);
cudaMalloc((void**)&cuda_sobel, sizeof(uchar)* W*H);
cudaMemcpy(cuda_sobelin, img, sizeof(uchar)* W * H, cudaMemcpyHostToDevice);
dim3 threadsPerBlock(16,16);
dim3 blocksPerGrid((W+15)/16,(H+15)/16);
sobel_gpu<<<blocksPerGrid,threadsPerBlock>>>(cuda_sobelin,cuda_sobel,W,H);
cudaThreadSynchronize();
cudaMemcpy(sobelout, cuda_sobel, sizeof(uchar)* W * H, cudaMemcpyDeviceToHost);
}


3.main.cpp文件

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <iostream>
#include <opencv2/opencv.hpp>
#include "sobel.hpp"
using namespace cv;
using namespace std;
int main()
{
Mat detect_img=imread("detect_img.jpg");
//resize到640x480大小再处理
cv::resize(detect_img, detect_img, cv::Size(640, 480), (0, 0), (0, 0), cv::INTER_LINEAR);
cvtColor(detect_img,detect_imggray,CV_BGR2GRAY);
//cuda实现
if(detect_imggray.isContinuous()) sobelin=detect_imggray.data;
sobel_func(sobelin,sobelout);
Mat sobel(480,640,CV_8UC1,(uchar*)sobelout);
imshow("sobel",sobel);
//opencv函数Sobel实现
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y;
Sobel( detect_imggray, grad_x, CV_16S, 1, 0, 3, 1, 0, BORDER_DEFAULT );
convertScaleAbs( grad_x, abs_grad_x );
Sobel( detect_imggray, grad_y, CV_16S, 0, 1, 3, 1, 0, BORDER_DEFAULT );
convertScaleAbs( grad_y, abs_grad_y );
Mat sobel1;
addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, sobel1);
imshow("opencv",sobel1);
waitKey(1);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: