三种最基本的边缘检测法
1:直接对图像平滑滤波,之后利用sobel算子计算图像梯度,进行阈值处理,得到图像边缘图。这是最基本的边缘检测方法。效果当然一般般而且容易产生边缘断线。
2:Marr-Hildreth检测法,Marr和Hildreth两位前辈证明,
1)灰度变化和图像尺度无关(不管图像是大是小,比如将同一张图片进行缩放,他的边缘应该是不会改变的),所以检测的时候要用不同尺寸的算子(比如大图片如果使用很小的算子,一条线容易变成一个区域被0像素隔开)。
2)灰度变化会在一阶导数引起波峰波谷,在二阶导数引起零交叉。
于是证明出满足这些条件最好的算子是LOG,也就是先高斯滤波,再拉普拉斯,求得零交叉,在opencv上对应代码
GaussianBlur(src, src, Size(3, 3), 1.5, 1.5);
Laplacian(src, dst, src.depth(), 3, 1, 0, BORDER_DEFAULT);
但令人奇怪的是,这两个函数都没有输入阈值的参数,可能opencv在两个函数内自动计算的吧。
3:Canny算子也是用的最多的算子,先高斯滤波,在求梯度幅值图像,然后非最大值抑制,最后双阈值处理+连接分析进行连接边缘
非最大值抑制能够产生更细的边缘图像,因为求梯度是一阶偏导运算,而一阶导数求出的边缘是比较粗的,最后如果还是觉得边缘很粗的话
可以用形态学细化算法,注意的是在Canny中选取双阈值时Canny前辈提示我们用1:3,或者1:2的效果更好。
Mat grayimg;
Mat flower = imread("D:/picture/orange.jpg");
cvtColor(flower, grayimg, COLOR_BGR2GRAY);
GaussianBlur(grayimg, grayimg, Size(5, 5), 2);
imshow("[高斯滤波]效果图", grayimg);
Canny(grayimg, grayimg, 30, 60);
imshow("[canny检测]算子的边缘检测", grayimg);
注意:再求图像的边缘的时候必须先将图像转换为灰度图像。原因引用百度知道里的朋友的回答:“
由于边缘检测基本是用梯度算子完成的,梯度是在坐标(x,y)处指向f最大变化率的方向的向量,而彩色图像实际是由若干种原色(如RGB)构成的,如果直接检测彩色图像边缘也就是对每种色彩单独检测,但是各原色在一点处的梯度方向可能不同,从而得到的边缘也不同,会发生错误。要采用计算平均向量可以解决该问题但复杂性提高。
疑惑:在刚萨雷斯的书中,作者提示我们在选取高斯滤波模板(n*n)和标准差(σ)时应该使n为大于等于6σ的最小奇整数,但在实际用opencv函数Gaussianblur()进行效果检验的时候发现使n大于标准差的6倍效果并不是最好的,不知道作者这句话是什么意思。 ----------------------分割线---------------------------------------------------------------------------- 疑惑解答:最近看到了一篇博客,里面就提到了高斯滤波模板之所以选择6σ的原因,原文如下
高斯模版是圆对称的,且卷积的结果使原始像素值有最大的权重,距离中心越远的相邻像素值权重也越小。 在实际应用中,在计算高斯函数的离散近似时,在大概3σ距离之外的像素都可以看作不起作用,这些像素的计算也就可以忽略。所以,通常程序只计算(6σ+1)*(6σ+1)就可以保证相关像素影响。 而且标准差的大小决定图像的平滑程度,大尺度对应图像的概貌特征,小尺度对应图像的细节特征。大的标准差对应低分辨的粗糙尺度,反之对应精细尺度。
引用链接:http://blog.csdn.net/xiaowei_cqu/article/details/8067881
http://blog.csdn.net/abcjennifer/article/details/7639681/