opencv之Canny边缘检测

文章目录


前言

Canny边缘检测是一种流行的边缘检测算法,用于检测图像中的边缘。它通过一系列步骤将图像中的像素边缘突出显示出来,主要分为以下几个步骤:

  1. 灰度化:将图像转换为灰度图,减少计算复杂度。
  2. 高斯滤波:使用高斯滤波器对图像进行平滑处理,以减少噪声对边缘检测的影响。
  3. 计算梯度:通过计算图像的梯度(通常使用Sobel算子)来检测边缘的方向和强度。
  4. 非极大值抑制:对梯度幅值进行非极大值抑制,以保留边缘并减少非边缘的杂点。
  5. 双阈值处理:通过设置高阈值和低阈值,将强边缘和弱边缘分离出来。
  6. 边缘连接:根据强边缘将弱边缘连接起来,形成最终的边缘检测结果。

1.应用高斯滤波去除图像噪声

由于图像边缘非常容易受到噪声的干扰,因此为了避免检测到错误的边缘信息,通常需要对图像进行滤波以去除噪声。滤波的目的是平滑一些纹理较弱的非边缘区域,以便得到更准确的边缘。在实际处理过程中,通常采用高斯滤波去除图像中的噪声。图1演示了使用高斯滤波器T对原始图像O中像素值为226的像素点进行滤波,得到该点在滤波结果图像D内的值的过程。


图1

在滤波过程中,我们通过滤波器对像素点周围的像素计算加权平均值,获取最终滤波结果。对于高斯滤波器T,越临近中心的点,权值越大。在图1中,对图像O中像素值为226的像素点,使用滤波器T进行滤波的计算过程及结果为:

当然,高斯滤波器(高斯核)并不是固定的,例如它还可以是:

滤波器的大小也是可变的,高斯核的大小对于边缘检测的效果具有很重要的作用。滤波器的核越大,边缘信息对于噪声的敏感度就越低。不过,核越大,边缘检测的定位错误也会随之增加。通常来说,一个5×5的核能够满足大多数的情况。

2.计算梯度

在上一章中,我们介绍了如何计算图像梯度的幅度。在这里,我们关注梯度的方向,梯度的方向与边缘的方向是垂直的。

边缘检测算子返回水平方向的 G x G_x Gx和垂直方向的 G y G_y Gy。梯度的幅度 G G G和方向 θ \theta θ(用角度值表示)为:

式中, a t a n 2 ( ⋅ ) atan2(·) atan2(⋅)表示具有两个参数的arctan函数。梯度的方向总是与边缘垂直的,通常就近取值为水平(左、右)、垂直(上、下)、对角线(右上、左上、左下、右下)等8个不同的方向。因此,在计算梯度时,我们会得到梯度的幅度和角度(代表梯度的方向)两个值。图2展示了梯度的表示法。其中,每一个梯度包含幅度和角度两个不同的值。为了方便观察,这里使用了可视化表示方法。例如,左上角顶点的值2↑实际上表示的是一个二元数对(2, 90),表示梯度的幅度为2,角度为90°。


图2

3.非极大值抑制

在获得了梯度的幅度和方向后,遍历图像中的像素点,去除所有非边缘的点。在具体实现时,逐一遍历像素点,判断当前像素点是否是周围像素点中具有相同梯度方向的最大值,并根据判断结果决定是否抑制该点。通过以上描述可知,该步骤是边缘细化的过程。针对每一个像素点:

  • 如果该点是正/负梯度方向上的局部最大值,则保留该点。
  • 如果不是,则抑制该点(归零)。

在图3中,A、B、C三点具有相同的方向(梯度方向垂直于边缘)。判断这三个点是否为各自的局部最大值:如果是,则保留该点;否则,抑制该点(归零)。

图3

经过比较判断可知,A点具有最大的局部值,所以保留A点(称为边缘),其余两点(B和C)被抑制(归零)。

在图4中,黑色背景的点都是向上方向梯度(水平边缘)的局部最大值。因此,这些点会被保留;其余点被抑制(处理为0)。这意味着,这些黑色背景的点最终会被处理为边缘点,而其他点都被处理为非边缘点。

图4

正/负梯度方向上是指相反方向的梯度方向。例如,在图5中,黑色背景的像素点都是垂直方向梯度(向上、向下)方向上(即水平边缘)的局部最大值。这些点最终会被处理为边缘点。

图5

经过上述处理后,对于同一个方向的若干个边缘点,基本上仅保留了一个,因此实现了边缘细化的目的。

4.应用双阈值确定边缘

完成上述步骤后,图像内的强边缘已经在当前获取的边缘图像内。但是,一些虚边缘可能也在边缘图像内。这些虚边缘可能是真实图像产生的,也可能是由于噪声所产生的。对于后者,必须将其剔除。

设置两个阈值,其中一个为高阈值maxVal,另一个为低阈值minVal。根据当前边缘像素的梯度值(指的是梯度幅度,下同)与这两个阈值之间的关系,判断边缘的属性。具体步骤为:

  1. 如果当前边缘像素的梯度值大于或等于maxVal,则将当前边缘像素标记为强边缘。
  2. 如果当前边缘像素的梯度值介于maxVal与minVal之间,则将当前边缘像素标记为虚边缘(需要保留)。
  3. 如果当前边缘像素的梯度值小于或等于minVal,则抑制当前边缘像素。在上述过程中,我们得到了虚边缘,需要对其做进一步处理。一般通过判断虚边缘与强边缘是否连接,来确定虚边缘到底属于哪种情况。通常情况下,如果一个虚边缘:
    • 与强边缘连接,则将该边缘处理为边缘。
    • 与强边缘无连接,则该边缘为弱边缘,将其抑制。

在图6中,左图显示的是三个边缘信息,右图是对边缘信息进行分类的示意图,具体划分如下:

图6

  • A点的梯度值值大于maxVal,因此A是强边缘。
  • B和C点的梯度值介于maxVal和minVal之间,因此B、C是虚边缘。
  • D点的梯度值小于minVal,因此D被抑制(抛弃)。

图7显示了对图6中的虚边缘B和C的处理结果。其中:

图7

  • B点的梯度值介于maxVal和minVal之间,是虚边缘,但该点与强边缘不相连,故将其抛弃。
  • C点的梯度值介于maxVal和minVal之间,是虚边缘,但该点与强边缘A相连,故将其保留。

注意,高阈值maxVal和低阈值minVal不是固定的,需要针对不同的图像进行定义。

5.Canny函数及使用

OpenCV提供了函数cv2.Canny()来实现Canny边缘检测,其语法形式如下:

python 复制代码
edges = cv.Canny( image, threshold1, threshold2[, apertureSize[, L2gradient]])

式中:

  • edges为计算得到的边缘图像。
  • image为8位输入图像。
  • threshold1表示处理过程中的第一个阈值。
  • threshold2表示处理过程中的第二个阈值。
  • apertureSize表示Sobel算子的孔径大小。
  • L2gradient为计算图像梯度幅度(gradient magnitude)的标识。其默认值为False。如果为True,则使用更精确的L2范数进行计算(即两个方向的导数的平方和再开方),否则使用L1范数(直接将两个方向导数的绝对值相加)。

代码

使用函数cv2.Canny()获取图像的边缘,并尝试使用不同大小的threshold1和threshold2,观察获取到的边缘有何不同。

python 复制代码
import cv2
o=cv2.imread("lena.bmp", cv2.IMREAD_GRAYSCALE)
r1=cv2.Canny(o,128,200)
r2=cv2.Canny(o,32,128)
cv2.imshow("original", o)
cv2.imshow("result1", r1)
cv2.imshow("result2", r2)
cv2.waitKey()
cv2.destroyAllWindows()

运行程序,结果如图9所示。其中:

  • original图是原始图像。
  • result1图是参数threshold1为128、threshold2为200时的边缘检测结果。
  • result2图是参数threshold1为32、threshold2为128时的边缘检测结果。
相关推荐
黑色叉腰丶大魔王4 小时前
基于 MATLAB 的图像增强技术分享
图像处理·人工智能·计算机视觉
菜狗woc13 小时前
opencv-python的简单练习
人工智能·python·opencv
paixiaoxin15 小时前
CV-OCR经典论文解读|An Empirical Study of Scaling Law for OCR/OCR 缩放定律的实证研究
人工智能·深度学习·机器学习·生成对抗网络·计算机视觉·ocr·.net
西猫雷婶15 小时前
python学opencv|读取图像(十四)BGR图像和HSV图像通道拆分
开发语言·python·opencv
AI视觉网奇16 小时前
人脸生成3d模型 Era3D
人工智能·计算机视觉
云空16 小时前
《QT 5.14.1 搭建 opencv 环境全攻略》
开发语言·qt·opencv
编码小哥16 小时前
opencv中的色彩空间
opencv·计算机视觉
吃个糖糖16 小时前
34 Opencv 自定义角点检测
人工智能·opencv·计算机视觉
禁默16 小时前
2024年图像处理、多媒体技术与机器学习
图像处理·人工智能·microsoft
花花少年16 小时前
【Windows版】opencv 和opencv_contrib配置
opencv·opencv_contrib