OpenCV/CUDA—Sobel边缘检测

一、OpenCV-Sobel边缘检测

在这里插入图片描述

#include <opencv2/opencv.hpp>
#include <math.h>
#include <iostream>

using namespace cv;

/*
	 OpenCV中的namedWindow函数
	 WINDOW_NORMAL	显示图像后,允许用户随意调整窗口大小
	 WINDOW_AUTOSIZE	根据图像大小显示窗口,不允许用户调整大小(默认)
	 WINDOW_FREERATIO	窗口大小自适应比例
	 WINDOW_KEEPRATIO	保持图像的比例
 */

int main()
{
	//-----------读取原图像-------------
	Mat srcImage = imread("sobel_test01.jpg");
	if (srcImage.empty())
	{
		printf("could not load this srcImage!\n");
		return -1;
	}
	namedWindow("原图像", 1);
	imshow("原图像", srcImage);
	//-----------对原图像进行高斯模糊,降噪-------------
	Mat gauImage;
	GaussianBlur(srcImage, gauImage, Size(3, 3), 0, 0, 4);
	//------------将降噪后的图像转换为灰度图像------------
	Mat grayImage;
	cvtColor(gauImage, grayImage, COLOR_BGR2GRAY);
	namedWindow("灰度图",1);
	imshow("灰度图", grayImage);
	//-----------------OpenCV-Sobel边缘检测--------------------
	double timeStart = (double)getTickCount();//程序计时-开始时间
	Mat xGrand, yGrand;
	/*x方向的一阶边缘检测—水平梯度Gx*/
	Sobel(grayImage, xGrand, CV_16S, 1, 0, 3);
	convertScaleAbs(xGrand, xGrand);
	/*y方向的一阶边缘检测—垂直梯度Gy*/
	Sobel(grayImage, yGrand, CV_16S, 0, 1, 3);
	convertScaleAbs(yGrand, yGrand);
	/*叠加x,y方向的边缘—最终图像梯度G*/
	Mat dst = Mat::zeros(xGrand.size(), yGrand.type());
	//根据公式,使用勾股定理求出图像近似梯度G
	int colsImage = srcImage.cols;
	int rowsImage = srcImage.rows;
	for (int row = 0; row < rowsImage; row++) {
		for (int col = 0; col < colsImage; col++) {
			uchar xValue = xGrand.at<uchar>(row, col);
			uchar yValue = yGrand.at<uchar>(row, col);
			dst.at<uchar>(row, col) = saturate_cast<uchar>(sqrt(xValue * xValue + yValue * yValue));
		}
	}
	double TotalTime = ((double)getTickCount() - timeStart) / getTickFrequency();//程序计时-结束时间
	namedWindow("x,y方向叠加的最终图像", 1);
	imshow("x,y方向叠加的最终图像", dst);

	printf("使用OpenCV做Sobel算子,消耗的时间:%f毫秒\n", TotalTime*1000);
	//imwrite("finalImage.jpg", dst);//导出最终图像
	waitKey(0);
	return 0;
}



二、CUDA-Sobel边缘检测

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <cuda.h>
#include <device_functions.h>
#include <opencv2\opencv.hpp>
#include <math.h>

#include <iostream>

using namespace cv;

/*
     OpenCV中的namedWindow函数
     WINDOW_NORMAL	显示图像后,允许用户随意调整窗口大小
     WINDOW_AUTOSIZE	根据图像大小显示窗口,不允许用户调整大小(默认)
     WINDOW_FREERATIO	窗口大小自适应比例
     WINDOW_KEEPRATIO	保持图像的比例
 */

//-------------------------------------------------------------------------------------------------
//             x0 x1 x2 
//             x3 x4 x5 
//             x6 x7 x8 
// GPU实现Sobel边缘检测,Sobel算子边缘检测核函数
//-------------------------------------------------------------------------------------------------
__global__ void sobelInCuda(unsigned char* dataIn, unsigned char* dataOut, int imgHeight, int imgWidth)
{
    int xIndex = threadIdx.x + blockDim.x * blockIdx.x;//X方向的线程索引
    int yIndex = threadIdx.y + blockDim.y * blockIdx.y;//Y方向的线程索引
    int index = yIndex * imgWidth + xIndex;//一维的全局索引
    
    int Gx = 0;
    int Gy = 0;
    //unsigned char x0, x1, x2, x3, x4, x5, x6, x7, x8;

    if (xIndex > 0 && xIndex < imgWidth - 1 && yIndex > 0 && yIndex < imgHeight - 1)//防止索引越界
    {
        //水平方向的边缘检测—计算图像水平梯度Gx
        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
        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]);
       
        //根据公式,求出最终的图像梯度G
        dataOut[index] = (abs(Gx) + abs(Gy)) / 2;

        以x4为中心,寻找其他像素点的坐标位置
        //x0 = dataIn[(yIndex - 1) * imgWidth + xIndex - 1];
        //x1 = dataIn[(yIndex - 1) * imgWidth + xIndex];
        //x2 = dataIn[(yIndex - 1) * imgWidth + xIndex + 1];
        //x3 = dataIn[(yIndex)*imgWidth + xIndex - 1];
        //x4 = dataIn[(yIndex)*imgWidth + xIndex];
        //x5 = dataIn[(yIndex)*imgWidth + xIndex + 1];
        //x6 = dataIn[(yIndex + 1) * imgWidth + xIndex - 1];
        //x7 = dataIn[(yIndex + 1) * imgWidth + xIndex];
        //x8 = dataIn[(yIndex + 1) * imgWidth + xIndex + 1];
        //水平方向的边缘检测—计算图像水平梯度Gx
        //Gx = (x0 + 2 * x3 + x6) - (x2 + 2 * x5 + x8);
        //垂直方向的边缘检测—计算图像垂直梯度Gy
        //Gy = (x0 + 2 * x1 + x2) - (x6 + 2 * x7 + x8);
        //根据公式,求出最终的图像梯度G
        //dataOut[index] = (abs(Gx) + abs(Gy)) / 2;

        //printf("out[%d]: %d", index, out[index]);
    }
}


int main()
{
    //-----------------读取原图像--------------------
    Mat srcImg = imread("sobel_test01.jpg", 1);
    if (srcImg.empty())
    {
        printf("could not load this srcImage!\n");
        return -1;
    }
    namedWindow("原图像", 1);
    imshow("原图像", srcImg);
    //--------------对原图像进行高斯模糊,降噪-----------------
    Mat gauImg;
    GaussianBlur(srcImg, gauImg, Size(3, 3), 0, 0, 4);
    //------------将降噪后的图像转换为灰度图像------------
    Mat grayImg;
    cvtColor(gauImg, grayImg, COLOR_BGR2GRAY);
    namedWindow("灰度图", 1);
    imshow("灰度图", grayImg);
    //-----------------使用CUDA进行Sobel边缘检测--------------------
    int imgHeight = grayImg.rows;
    int imgWidth = grayImg.cols;
    //使用CUDA进行Sobel边缘检测的最终结果图像
    Mat dstGpuImg(imgHeight, imgWidth, CV_8UC1, Scalar(0, 0, 0));
    //创建GPU内存,申请指针并将它指向GPU空间
    size_t num = imgHeight * imgWidth * sizeof(unsigned char);
    unsigned char* d_in;
    unsigned char* d_out;
    cudaMalloc((void**)&d_in, num);
    cudaMalloc((void**)&d_out, num);
    //--------------将灰度图像从CPU传输到GPU---------------------
    cudaMemcpy(d_in, grayImg.data, num, cudaMemcpyHostToDevice);
    //-----------------定义CUDA中grid和block的维度---------------
    dim3 threadsPerBlock(32, 32);
    dim3 blocksPerGrid((imgWidth + threadsPerBlock.x - 1) / threadsPerBlock.x,
        (imgHeight + threadsPerBlock.y - 1) / threadsPerBlock.y);
    
    //--------------------记录核函数起始时间---------------------
    //double timeStart = (double)getTickCount();//程序计时-开始时间
    cudaEvent_t start, stop;
    cudaEventCreate(&start);
    cudaEventCreate(&stop);
    cudaEventRecord(start, 0);//避免gpu线程没有完全执行结束
    //--------------------调用在GPU上运行的核函数--------------------
    //sobelInCuda<<<每个Grid中的block数,每个block中的thread数>>>
    //每个thread都会执行核函数
    sobelInCuda << <blocksPerGrid, threadsPerBlock >> > (d_in, d_out, imgHeight, imgWidth);
    //-------------------记录核函数结束时间-------------------
    cudaEventRecord(stop, 0);
    cudaEventSynchronize(stop);
    float elapsedTime;
    cudaEventElapsedTime(&elapsedTime, start, stop);

    //--------------------将计算以后的图像传回到CPU内存--------------------
    //double TotalTime = ((double)getTickCount() - timeStart) / getTickFrequency();//程序计时-结束时间
    cudaMemcpy(dstGpuImg.data, d_out, num, cudaMemcpyDeviceToHost);
    //------------------------显示处理结果-------------------------
    namedWindow("CUDA_Soble的结果图像", 1);
    imshow("CUDA_Soble的结果图像", dstGpuImg);

    printf("使用CUDA做Sobel算子,消耗的时间:%f毫秒\n", elapsedTime);
	//printf("使用CUDA做Sobel算子,消耗的时间:%f毫秒\n", TotalTime*1000);
    //imwrite("finalImage.jpg", dstGpuImg);//导出最终图像
    
    //-------------------------释放GPU内存-------------------------
    cudaFree(d_in);
    cudaFree(d_out);
    //-------------------------释放CUDA计时内存--------------------
    cudaEventDestroy(start);
    cudaEventDestroy(stop);

    waitKey(0);
    return 0;
}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值