【图像处理】Canny边缘检测
前言
Canny边缘检测的步骤如下:
- 使用高斯滤波器,以平滑图像,滤除噪声。
- 计算图像中每个像素点的梯度强度和方向。
- 应用非极大值抑制,以消除边缘检测带来的杂散相应。(让边缘变瘦)
- 应用双阈值检测来确定真实的和潜在的边缘。
- 通过抑制孤立的弱边缘最终完成边缘检测。
高斯滤波器去除图像噪声
图像边缘容易收到噪声的干扰,因此为了避免检测到错误的边缘信息,需要建筑滤波器将图像做一个去噪的处理。滤波可以平滑一些纹理较弱的非边缘区域,以此得到更准确的边缘。
在滤波过程中,我们通过滤波器对像素点周围的像素计算加权平均值,获取最终滤波结果。对于高斯滤波器T,越临近中心的点,权值越大。
滤波器的大小也是可变的,滤波器的核越大,边缘信息对于噪声的敏感度就越低。不过,核越大,边缘检测的定位错误也会随之增加。
通常来说,一个5×5的核能够满足大多数的情况。
梯度大小与方向计算
使用Sobel算子计算图像梯度的幅度。
梯度的方向总是与边缘垂直的,通常就近取值为水平(左、右)、垂直(上、下)、对角线(右上、左上、左下、右下)等8个不同的方向。
下图的梯度的表示法中,每一个梯度包含幅度和角度两个不同的值。为了方便观察,这里使用了可视化表示方法。例如,左上角顶点的值“2↑”实际上表示的是一个二元数对“(2, 90)”,表示梯度的幅度为2,角度为90°。
注意梯度方向和实际的边缘方向是垂直的。
非极大值抑制
在获得了梯度的幅度和方向后,遍历图像中的像素点,去除所有非边缘的点。在具体实现时,逐一遍历像素点,判断当前像素点是否是周围像素点中具有相同梯度方向的最大值,并根据判断结果决定是否抑制该点,这一过程也称作 边缘细化(即一个方向上提取出来的像素点变少了)。
针对每个像素点:
- 如果该点是其方向正/负梯度上的局部最大值,则保留该点。
- 如果不是,则抑制该点(归零)。
比如下图中A点具有最大的局部值,所以保留A点(称为边缘),其余两点(B和C)被抑制(归零)。由于ABC三点的梯度方向都是水平的,均垂直于边缘。
“正/负梯度方向上”是指相反方向的梯度方向。例如,在图10-5中,黑色背景的像素点都是垂直方向梯度(向上、向下)方向上(即水平边缘)的局部最大值。这些点最终会被处理为边缘点。
因此,这些黑色背景的点最终会被处理为边缘点,而其他点都被处理为非边缘点。
经过上述处理后,对于同一个方向的若干个边缘点,基本上仅保留了一个,因此实现了边缘细化的目的。
双阈值确定边缘
完成上述步骤后,图像内的强边缘已经在当前获取的边缘图像内。但是,一些虚边缘可能也在边缘图像内。这些虚边缘可能是真实图像产生的,也可能是由于噪声所产生的。对于后者,必须将其剔除。
设置两个阈值,其中一个为高阈值maxVal,另一个为低阈值minVal。根据当前边缘像素的梯度值(指的是梯度幅度,下同)与这两个阈值之间的关系,判断边缘的属性。具体步骤为:
- 如果当前边缘像素的梯度值大于或等于maxVal,则将当前边缘像素标记为强边缘。
- 如果当前边缘像素的梯度值介于maxVal与minVal之间,则将当前边缘像素标记为虚边缘(需要保留)。
- 如果当前边缘像素的梯度值小于或等于minVal,则抑制当前边缘像素。
在上述过程中,我们得到了虚边缘,需要对其做进一步处理。一般通过判断虚边缘与强边缘是否连接,来确定虚边缘到底属于哪种情况。通常情况下,如果一个虚边缘:- 与强边缘连接,则将该边缘处理为边缘。
- 与强边缘无连接,则该边缘为弱边缘,将其抑制。
在下图中,左图显示的是三个边缘信息,右图是对边缘信息进行分类的示意图,具体划分如下:
- A点的梯度值值大于maxVal,因此A是强边缘。
- B和C点的梯度值介于maxVal和minVal之间,因此B、C是虚边缘。
- D点的梯度值小于minVal,因此D被抑制(抛弃)。
对于虚边缘:
● B点的梯度值介于maxVal和minVal之间,是虚边缘,但该点与强边缘不相连,故将其抛弃。
C点的梯度值介于maxVal和minVal之间,是虚边缘,但该点与强边缘A相连,故将其保留。
注意,高阈值maxVal和低阈值minVal不是固定的,需要针对不同的图像进行定义。
函数介绍
使用openCV提供的Canny函数来实现边缘检测:
1 | edges = cv.Canny( image, threshold1, threshold2[, apertureSize[, L2gradient]]) |
edges为计算得到的边缘图像。
● image为8位输入图像。
● threshold1表示处理过程中的第一个阈值。
● threshold2表示处理过程中的第二个阈值。
● apertureSize表示Sobel算子的孔径大小。
● L2gradient为计算图像梯度幅度(gradient magnitude)的标识。其默认值为False。如果为True,则使用更精确的L2范数进行计算(即两个方向的导数的平方和再开方),否则使用L1范数(直接将两个方向导数的绝对值相加)。
示例介绍
假设现在对于某张火箭的背景图,计划使用canny检测来获取图像的边缘。测试使用不同大小的阈值,观察或渠道的边缘有何不同。
1 | import cv2 as cv |
观察结果如下:
其中:
- 左上图为原图。
- 右上角为参数128,200的边缘检测结果。
- 中下图为参数32,128的边缘检测结果。
由图可以发现,两个相关的阈值较小时,可以捕获更多的边缘信息。
参考资料
- 《openCV入门》