OpenCv学习18——Canny边缘检测

本节内容参考于:https://www.cnblogs.com/techyan1990/p/7291771.html https://baike.baidu.com/item/canny算法/8439208?fr=aladdin
https://zh.wikipedia.org/wiki/Canny算子

  1. Canny算法简介:
    Canny边缘检测算子是John F. Canny于 1986 年开发出来的一个多级边缘检测算法。更为重要的是 Canny 创立了边缘检测计算理论(Computational theory of edge detection)解释这项技术如何工作。
    通常情况下边缘检测的目的是在保留原有图像属性的情况下,显著减少图像的数据规模。目前有多种算法可以进行边缘检测,虽然Canny算法年代久远,但可以说它是边缘检测的一种标准算法,而且仍在研究中广泛使用。
    Canny算法是一个很好的边缘检测器,是一种很常用也很实用的图像处理方法

  2. Canny算法实现步骤:
    Canny边缘检测算法可以分为以下5个步骤:
    ①应用高斯滤波,进行高斯模糊GaussianBlur来平滑图像,目的是去除噪声
    ②进行灰度转换——cvtColor
    ③找寻图像的强度梯度(intensity gradients),利用Sobel/Scharr算子来实现
    ④应用非最大信号抑制(non-maximum suppression)技术来消除边误检(本来不是但检测出来是)
    ⑤应用双阈值的方法来决定可能的(潜在的)边界,输出二值图像

    我们这里首先详细介绍两个新的概念——即非最大信号抑制及利用高低阈值输出二值图像
    非最大抑制:
    图像中的边缘可能会指向不同的方向,所以Canny算法使用4个mask检测水平、垂直以及对角线方向的边缘。原始图像与每个mask所作的卷积都存储起来。对于每个点我们都标识在这个点上的最大值以及生成的边缘的方向。这样我们就从原始图像生成了图像中每个点亮度梯度图以及亮度梯度的方向。
    这一步的目的是将模糊(blurred)的边界变得清晰(sharp)。通俗的讲,就是保留了每个像素点上梯度强度的极大值,而删掉其他的值。对于每个像素点,进行如下操作:
    a) 将其梯度方向近似为以下值中的一个(0,45,90,135,180,225,270,315)(即上下左右和45度方向)
    b) 比较该像素点,和其梯度方向正负方向的像素点的梯度强度
    c) 如果该像素点梯度强度最大则保留,否则抑制(删除,即置为0)
    为了更好的解释这个概念,看下图。
    在这里插入图片描述
    图中的数字代表了像素点的梯度强度,箭头方向代表了梯度方向。以第二排第三个像素点为例,由于梯度方向向上,则将这一点的强度(7)与其上下两个像素点的强度(5和4)比较,由于这一点强度最大,则保留为边缘点否则则不保存为边缘点。处理后效果如下图所示。在上面这段话中我们需要注意的是我们进行比较的像素点是将这一点与其方向上的周围的像素点进行比较
    在这里插入图片描述
    上图中,可以想象,边界处的梯度方向总是指向垂直于边界的方向,即最后会保留一条边界处最亮的一条细线。

    关于高低阈值处理输出二值图像的内容摘自于维基百科:

    After application of non-maximum suppression, remaining edge pixels provide a more accurate representation of real edges in an image. However, some edge pixels remain that are caused by noise and color variation. In order to account for these spurious responses, it is essential to filter out edge pixels with a weak gradient value and preserve edge pixels with a high gradient value. This is accomplished by selecting high and low threshold values. If an edge pixel’s gradient value is higher than the high threshold value, it is marked as a strong edge pixel. If an edge pixel’s gradient value is smaller than the high threshold value and larger than the low threshold value, it is marked as a weak edge pixel. If an edge pixel’s value is smaller than the low threshold value, it will be suppressed. The two threshold values are empirically determined and their definition will depend on the content of a given input image.是引用

    即我们可以简单理解为:在施加非极大值抑制之后,剩余的像素可以更准确地表示图像中的实际边缘。然而,仍然存在由于噪声和颜色变化引起的一些边缘像素。为了解决这些杂散响应,必须用弱梯度值过滤边缘像素,并保留具有高梯度值的边缘像素,可以通过选择高低阈值来实现。如果边缘像素的梯度值高于高阈值,则将其标记为强边缘像素;如果边缘像素的梯度值小于高阈值并且大于低阈值,则将其标记为弱边缘像素;如果边缘像素的梯度值小于低阈值,则会被抑制。阈值的选择取决于给定输入图像的内容。
    推荐的高低阈值比为T2:T1=3/1 OR 2/1,其中T2为高阈值,T1为低阈值

  3. 用到的重要的API

    CV_EXPORTS_W void Canny( InputArray image, 
    						 OutputArray edges,
                             double threshold1,
                             double threshold2,
                             int apertureSize = 3, 
                             bool L2gradient = false );
    

    函数参数说明:第一第二个参数易明,不再赘述;第三个参数为低阈值常取高阈值的1/2或1/3;第四个参数为高阈值;第五个参数为Sobel算子的size,通常我们取默认值3,及一3✖3的矩阵;最后一个参数则是如果选择True则采用L2来进行归一化,false采用L1来进行归一化,我们一般采用默认值false即可
    在这里插入图片描述

  4. 实验代码及效果展示

    #include "iostream"
    #include "opencv2\opencv.hpp"
    
    using namespace std;
    using namespace cv;
    
    void Canny_Demo(int, void*);
    
    Mat gray_src;
    int t1_threshold;
    Mat src, dst;
    Mat edge_dst;
    
    int main()
    {
    	int max_value = 255;
    	src = imread("C:/Users/he104/Desktop/opencv_images/timg.jpg");
    	if (src.empty())
    	{
    		cout << "could not load the images" << endl;
    		return -1;
    	}
    	namedWindow("input_images", CV_WINDOW_AUTOSIZE);
    	namedWindow("ouput_images", CV_WINDOW_AUTOSIZE);
    	cvtColor(src, gray_src, CV_BGR2GRAY);
    	createTrackbar("Threshold_Value", "ouput_images", &t1_threshold, max_value, Canny_Demo);
    	Canny_Demo(0, 0);
    	namedWindow("input_images", CV_WINDOW_AUTOSIZE);
    	imshow("input_images", src);
    	waitKey(0);
    	destroyAllWindows();
    	return 0;
    }
    
    
    void Canny_Demo(int, void*)
    {
    	blur(gray_src, gray_src, Size(3, 3), Point(-1), BORDER_DEFAULT);
    	Canny(gray_src, edge_dst, t1_threshold, t1_threshold * 2, 3, false);
    	dst.create(src.size(), src.type());
    	src.copyTo(dst,edge_dst);
    	imshow("ouput_images", dst);//image.copyTo(imageROI,mask),作用是把mask和image重叠以后把mask中像素值为0(black)的点对应的image中的点变为透明,而保留其他点。
    }
    
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值