步骤:
去噪声
任何边缘检测算法都不可能在未经处理的原始数据上很好地处理,所以第一步是对原始数据与高斯平滑模板作卷积,得到的图像与原始图像相比有些轻微的模糊(blurred)。这样,单独的一个像素噪声在经过高斯平滑的图像上变得几乎没有影响。
图像中的边缘可能会指向不同的方向,所以 Canny 算法使用 4 个 mask 检测水平、垂直以及对角线方向的边缘。原始图像与每个 mask 所作的卷积都存储起来。对于每个点我们都标识在这个点上的最大值以及生成的边缘的方向。这样我们就从原始图像生成了图像中每个点亮度梯度图以及亮度梯度的方向。
参数:
Canny 算法包含许多可以调整的参数,它们将影响到算法的计算的时间与实效。
高斯滤波器的大小:第一步所用的平滑滤波器将会直接影响 Canny 算法的结果。较小的滤波器产生的模糊效果也较少,这样就可以检测较小、变化明显的细线。较大的滤波器产生的模糊效果也较多,将较大的一块图像区域涂成一个特定点的颜色值。这样带来的结果就是对于检测较大、平滑的边缘更加有用,例如彩虹的边缘。
阈值:使用两个阈值比使用一个阈值更加灵活,但是它还是有阈值存在的共性问题。设置的阈值过高,可能会漏掉重要信息;阈值过低,将会把枝节信息看得很重要。很难给出一个适用于所有图像的通用阈值。目前还没有一个经过验证的实现方法。
Canny 算法适用于不同的场合。它的参数允许根据不同实现的特定要求进行调整以识别不同的边缘特性。对于PC上的实时图像处理来说可能慢得无法使用,尤其是在使用大的高斯滤波器的情况下。
高斯滤波器是一类根据高斯函数的形状来选择权值的线性平滑滤波器。高斯平滑滤波器对于抑制服从正态分布的噪声非常有效。
小节:(来自此处)
canny边缘检测算子,主要流程就是平滑图像、计算梯度的幅值和方向、对梯度幅值进行非极大值抑制、用双阈值确定边缘。
(1)平滑图像,用的离散化的二维高斯函数:
(2)然后就是计算梯度的幅值和方向,用的这两个矩阵:
这个是计算公式:
但有的地方说计算梯度的幅值和方向用的是sobel算子,opencv里应该就是用的sobel,这里有说明。
(3)对梯度幅值进行非极大值抑制:
这条蓝线是梯度方向,局部最大值就在这条线上。除了C点外,梯度方向的交点dTmp1和dTmp2这两个点的值也可能会是局部最大值。判断C点灰度与这两个点灰度大小即可判断C点是否为其邻域内的局部最大灰度点。如果经过判断,C点灰度值小于这两个点中的任一个,那就说明C点不是局部极大值,那么则可以排除C点为边缘。这就是非极大值抑制的工作原理。梯度方向垂直于边缘方向。
实际上,我们只能得到C点邻域的8个点的值,而dTmp1和dTmp2并不在其中,要得到这两个值就需要对该两个点两端的已知灰度进行线性插值。
这里的非极大值抑制讲得还是蛮清楚的。
(4)双阈值确定边缘:
根据高阈值得到一个边缘图像,这样一个图像含有很少的假边缘,但是由于阈值较高,产生的图像边缘可能不闭合,未解决这样一个问题采用了另外一个低阈值。
在高阈值图像中把边缘链接成轮廓,当到达轮廓的端点时,该算法会在端点的8邻域点中寻找满足低阈值的点,再根据此点收集新的边缘,直到整个图像边缘闭合。
关于滤波看看这个就ok啦~
最后总结:根据这里的介绍,
1. 我们在第一步的平滑处就可以用满足自己应用场景的滤波算法,不一定非要用高斯滤波。因为滤波的主要目的是为了去除噪声
,所以应该选择适合应用场景的滤波算法。而且比如这里,高斯平滑使用5×5的矩阵(模板),做卷积运算,常规用的都是3×3的。
开始还不清楚怎么拿高斯平滑函数计算模板,其实就是把σ往里一带,坐标也往里一带,中心点坐标(0,0),其他的位置就以这个(0,0)位置为参照表示坐标,x, y表示的就是当前点到中心点的距离。都带到公式里,就能计算矩阵了(模板)。
2. 第二步计算梯度幅值和方向,这里其实也应该用适合的算子,比如,有的地方就是很简单的2×2矩阵,而有的地方就用3×3矩阵。
3. 比如平滑那里用高斯平滑,有时候为了降低计算量,直接用两个一维高斯函数分别计算来替换直接用二维高斯函数计算。
Canny算子是John Canny在1986年提出的,那年老大爷才28岁,该文章发表在PAMI顶级期刊上的(1986. A computational approach to edge detection. IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. 8, 1986, pp. 679-698)。老大爷目前在加州伯克利做machine learning,80-90年代视觉都是图像处理,现在做视觉都是机器学习的天下,大爷的主页(http://www.cs.berkeley.edu/~jfc/)。