使用OpenCV对图像作边缘检测(Canny、Sobel、Laplace)

    xiaoxiao2022-07-03  136

    边缘检测是图像处理和计算机视觉中的基本问题边缘检测的目的是标识数字图像中亮度变化明显的点。图像属性中的显著变化通常反映了属性的重要事件和变化。 这些包括(i)深度上的不连续、(ii)表面方向不连续、(iii)物质属性变化和(iv)场景照明变化。 边缘检测是图像处理和计算机视觉中,尤其是特征提取中的一个研究领域。图像边缘检测大幅度地减少了数据量,并且剔除了可以认为不相关的信息,保留了图像重要的结构属性。 OpenCV提供了相关函数来实现各种边缘检测算子,具体的各种边缘检测的算子的算法原理请大家自行百度,下面分别介绍并给出示例代码。一、Canny边缘检测算子OpenCV提供了Canny函数来实现Canny边缘检测算子,函数原型如下: C++: void Canny(InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize=3, bool L2gradient=false )参数意义如下image:输入图像,其类型要求只能是8位的edges:边缘输出,其类型要求是单通道的8位图像,和输入图像有相同的大小。threshold1:第一个滞后性阈值。threshold2:第二个滞后性阈值。apertureSize:使用Sobel算子的孔径大小,有默认值为3。L2gradient:是否使用 L_2 norm  =\sqrt{(dI/dx)^2 + (dI/dy)^2来计算图像的梯度幅值,默认值为false,表示不使用L_2 norm来计算梯度幅值,此时使用L_1 norm来计算梯度幅值。补充说明:两个滞后性阈值中较小的那个用来确定边缘连接,较大的那个用来初始化强边缘的检测,详细原理可参见链接:http://en.wikipedia.org/wiki/Canny_edge_detector使用Canny函数进行边缘检测的代码如下: 代码中用到的图像下载链接:https://pan.baidu.com/s/1hs8ImVU 密码:irnd

    //opencv版本:OpenCV3.0 //VS版本:VS2013 #include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/imgproc/types_c.h> #include <opencv2/highgui/highgui.hpp> #include <opencv2/highgui/highgui_c.h> #include <iostream> using namespace cv; using namespace std; int main() { //载入原始图 Mat src = imread("20.jpg"); Mat src_1 = imread("20.jpg", 0); Mat gray = imread("20.jpg", 0); imshow("原图", src); //---------------------------------------------------------------------------------- // 一、最简单的canny用法,拿到原图后直接用。 //---------------------------------------------------------------------------------- Canny(src_1, src_1, 100, 150, 3); imshow("简单用法的Canny边缘检测结果", src_1); //---------------------------------------------------------------------------------- // 二、高阶的canny用法,转成灰度图,降噪,用canny,最后将得到的边缘作为掩码,拷贝原图到效果图上,得到彩色的边缘图 //---------------------------------------------------------------------------------- Mat dst, edge; // 【1】创建与src同类型和大小的矩阵(dst) dst.create(gray.size(), gray.type()); // 【2】先用使用 3x3内核来降噪 blur(gray, edge, Size(3, 3)); // 【3】运行Canny算子 Canny(edge, edge, 100, 150, 3); imshow("高阶用法的Canny边缘检测结果", edge); //【4】将g_dstImage内的所有元素设置为0 dst = Scalar::all(0); //【5】使用Canny算子输出的边缘图g_cannyDetectedEdges作为掩码,来将原图g_srcImage拷到目标图g_dstImage中 src.copyTo(dst, edge); //【6】显示效果图 imshow("高阶用法的合成图", dst); waitKey(0); return 0; }

    代码运行截果如下图所示

    二、Sobel算子 OpecnCV提供了Sobel函数来计算图像的一阶,二阶,三阶导数,使用的算子是扩展了的Sobel算子。函数原型如下: C++: void Sobel(InputArray src, OutputArray dst, int ddepth, int dx, int dy, int ksize=3, double scale=1, double delta=0, int borderType=BORDER_DEFAULT )参数意义如下src:源图像dst:目标图像,和源图的大小和通道数一样。ddepth:目标图像的深度,支持的深度如下:     src.depth() = CV_8U, ddepth = -1/CV_16S/CV_32F/CV_64F     src.depth() = CV_16U/CV_16S, ddepth = -1/CV_32F/CV_64F     src.depth() = CV_32F, ddepth = -1/CV_32F/CV_64F     src.depth() = CV_64F, ddepth = -1/CV_64F     当 ddepth = -1时,目标图像和源图像的深度一样,当深度是8位时,程序会对数作截断处理。dx:x方向的求导阶数dy:y方向的求导阶数ksize:扩展Sobel算子的大小,可以的取值为1,3,5,7,值得注意的是,当ksize=CV_SCHARR (-1)时,使用3×3的Scharr 滤波器进行计算,这样精度更高。Scharr在x方向和y方向上的核算子矩阵为:Scharr函数的原型如下: C++: void Scharr(InputArray src, OutputArray dst, int ddepth, int dx, int dy, double scale=1, double delta=0, int borderType=BORDER_DEFAULT ) 这里就不对Scharr的参数多做介绍了,也不单独给Scharr的使用示例,因为它就是Sobel算子的一个特例,和Sobel算子的使用上,除了没有ksize这个参数外,其它都一样。scale:可选的导数计算比例因子,默认不使用比例因子。borderType:边界处理方法,具体的详见帖子thread-177-1-1.html值得注意的是:Sobel算子在计算中进行了高斯平滑和差分运算,这样或多或少对噪声有消除作用。可以设置(xorder = 1, yorder = 0, ksize = 3)或(xorder = 0, yorder = 1, ksize = 3)来计算在x或y方向上的一阶导数。一阶导数的核算子如下二阶导数的核算子如下使用Sobel函数计算图像边缘的代码如下: 代码中用到的图像下载链接:https://pan.baidu.com/s/1gfAggZh 密码:dnol

    //opencv版本:OpenCV3.0 //VS版本:VS2013 #include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/imgproc/types_c.h> #include <opencv2/highgui/highgui.hpp> #include <opencv2/highgui/highgui_c.h> #include <iostream> using namespace cv; using namespace std; //-----------------------------------【头文件包含部分】--------------------------------------- // 描述:包含程序所依赖的头文件 //---------------------------------------------------------------------------------------------- #include <opencv2/opencv.hpp> #include<opencv2/highgui/highgui.hpp> #include<opencv2/imgproc/imgproc.hpp> //-----------------------------------【命名空间声明部分】--------------------------------------- // 描述:包含程序所使用的命名空间 //----------------------------------------------------------------------------------------------- using namespace cv; //-----------------------------------【main( )函数】-------------------------------------------- // 描述:控制台应用程序的入口函数,我们的程序从这里开始 //----------------------------------------------------------------------------------------------- int main( ) { //【0】创建 grad_x 和 grad_y 矩阵 Mat grad_x, grad_y; Mat abs_grad_x, abs_grad_y,dst; //【1】载入原始图 Mat src = imread("21.jpg"); //【2】显示原始图 imshow("【原始图】sobel边缘检测", src); //【3】求 X方向梯度 Sobel( src, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT ); convertScaleAbs( grad_x, abs_grad_x ); imshow("【效果图】 X方向Sobel", abs_grad_x); //【4】求Y方向梯度 Sobel( src, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT ); convertScaleAbs( grad_y, abs_grad_y ); imshow("【效果图】Y方向Sobel", abs_grad_y); //【5】合并梯度(近似) addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst ); imshow("【效果图】整体方向Sobel", dst); waitKey(0); return 0; }

    运行结果如下图所示:

     

    三、Laplace算子 OpecnCV提供了Laplacian函数来计算图像的拉普拉斯运算。函数原型如下: C++: void Laplacian(InputArray src, OutputArray dst, int ddepth, int ksize=1, double scale=1, double delta=0, int borderType=BORDER_DEFAULT )参数意义如下:src:源图像dst:目标图像,和源图像的大小和通道数一样。ddepth:目标图像深度。ksize:核算子的大小,用计算二阶导数时使用。delta:可选的delta值,结果进行存储前的附加值、borderType:边界处理方法,具体的详见帖子thread-177-1-1.html 这个函数实际上就是把使用Sobel在x方向和y方向算子计算出的二阶层数进行合成,从而得到自己的计算结果。使用Laplacian函数计算图像边缘的代码如下: 代码中用到的图像下载链接:https://pan.baidu.com/s/1slJptsL 密码:tiki

    //opencv版本:OpenCV3.0 //VS版本:VS2013 #include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/imgproc/types_c.h> #include <opencv2/highgui/highgui.hpp> #include <opencv2/highgui/highgui_c.h> #include <iostream> using namespace cv; using namespace std; //-----------------------------------【头文件包含部分】--------------------------------------- // 描述:包含程序所依赖的头文件 //---------------------------------------------------------------------------------------------- #include <opencv2/opencv.hpp> #include<opencv2/highgui/highgui.hpp> #include<opencv2/imgproc/imgproc.hpp> //-----------------------------------【命名空间声明部分】--------------------------------------- // 描述:包含程序所使用的命名空间 //----------------------------------------------------------------------------------------------- using namespace cv; //-----------------------------------【main( )函数】-------------------------------------------- // 描述:控制台应用程序的入口函数,我们的程序从这里开始 //----------------------------------------------------------------------------------------------- int main() { //【0】变量的定义 Mat src, src_gray, dst, abs_dst; //【1】载入原始图 src = imread("22.jpg"); //【2】显示原始图 imshow("【原始图】图像Laplace变换", src); //【3】使用高斯滤波消除噪声 GaussianBlur(src, src, Size(3, 3), 0, 0, BORDER_DEFAULT); //【4】转换为灰度图 cvtColor(src, src_gray, CV_RGB2GRAY); //【5】使用Laplace函数 Laplacian(src_gray, dst, CV_16S, 3, 1, 0, BORDER_DEFAULT); //【6】计算绝对值,并将结果转换成8位 convertScaleAbs(dst, abs_dst); //【7】显示效果图 imshow("【效果图】图像Laplace变换", abs_dst); waitKey(0); return 0; }

    运行结果如下图所示:

    最新回复(0)