Bootstrap

深入解析 Canny 边缘检测:原理、步骤与实践应用全攻略

在这里插入图片描述

摘要:本文全面且深入地探讨了 Canny 边缘检测。详细阐述了其包括去噪(重点分析高斯核选取及不同大小核的影响)、计算梯度、非极大值抑制、双阈值确定边缘等核心步骤,并结合实际案例与代码(如使用 cv2.Canny 对 pig.JPG 图片处理)展示其在不同阈值设置下的效果差异及原因,助力读者深入理解并掌握 Canny 边缘检测技术在图像处理领域的应用要点与原理精髓。
如果你觉得本文对你有帮助,请点赞收藏关注,我会持续创作更多跟OpenCV相关的文章

Canny边缘检测步骤

第一步:去噪

一般是使用高斯滤波,高斯滤波的特点是靠近中心的权值比较大,远离的权值较小。平滑一些纹理较弱的非轮廓区域,我用画图板给大家画一个例子,使用高斯滤波核对下面这张图的红色像素点进行计算:
在这里插入图片描述
高斯卷积核的如下:
在这里插入图片描述
两个矩阵乘法/56 = 138.
核越大对于噪声的敏感度就越低,通常来说5x5的核足以满足大多数情况
因为边缘的方向是由切向量来定义的,所以梯度的方向与边缘的方向垂直。

高斯核的选取

小核的局限性:小高斯核(如 3x3)在抑制噪声方面的能力相对较弱。虽然它能够较好地保留图像的细节和边缘的精确位置,但在实际应用中,很多图像都含有一定程度的噪声。如果噪声没有得到有效抑制,就会在边缘检测过程中产生大量的伪边缘。这些伪边缘会干扰真正边缘信息的提取,导致边缘检测结果不准确。

用 5x5 的高斯核可以在一定程度上有效地平滑图像,减少噪声的影响。例如,在一幅含有椒盐噪声(图像上随机出现的黑白像素点)的图像中,5x5 的高斯核能够将这些噪声点周围的像素值进行加权平均,使得噪声引起的像素值突变得到缓解。这样,在后续的边缘检测步骤(如计算梯度幅值和方向)中,就不容易因为噪声的干扰而错误地检测出边缘。

高斯核越大,边缘信息对于噪声的敏感度就越低,核越大定位错误也会增加。
虽然较大的高斯核(如 5x5)可能会导致边缘定位出现一些误差,但在很多实际应用场景中,这种误差是可以接受的。因为边缘检测的主要目的通常是获取物体的大致轮廓,而不是精确到像素级别的边缘位置。例如,在一个工业零件检测的场景中,只需要知道零件的大致边缘位置来判断其形状是否符合标准,少量的边缘定位误差不会对整体的检测结果产生重大影响。
相比于小核可能产生的大量伪边缘,大核导致的边缘定位错误相对来说是次要的。如果使用小核,大量的伪边缘会使得后续的边缘连接、轮廓提取等操作变得非常复杂,甚至无法准确地获取物体的完整轮廓。而使用 5x5 的核可以在减少伪边缘的同时,虽然会有一定的定位错误,但仍然能够提供相对清晰和准确的边缘轮廓。

第二步:计算梯度

G = (Gx^2 +Gy ^2)**(1/2)
方向 = arctan2(Gy,Gx)
梯度的方向与边缘垂直,就近取值为(左右上下、左上 左下 右上右下)八种,因此在计算梯度的时候,我们会得到角度和梯度两个值,请看下图:
在这里插入图片描述

第三步:非极大值抑制

获得梯度的幅度和方向以后,遍历所有像素点,去掉所有非边缘的点,判断当前仙姑私单是否式周围中具有相同梯度方向的最大值,如果不是最大值就抑制该点。通过非极大值抑制实现边缘细化的目的

第四步:双阈值确定边缘

第四步又分为两小步;
第一步:设置两个阈值 max min 如果梯度>= max那么标记为强边缘,如果在 max>梯度>min,那么标记为弱边缘,如果梯度<min,那么直接删去
第二步:遍历弱边缘,若与强边缘有连接,那么确定为边缘,没连接删去

语法与案例

语法

edges = cv2.Canny(待处理8位输入图像image ,阈值1 threshold1,阈值2 threshold2,图像梯度幅度L2gradient 默认为False计算速度快,他的图像梯度是二者绝对值之和,而设置为True就是G = (Gx^2 +Gy ^2)**(1/2),这样计算的更为准确)
我使用的是jupyter notebook,我项目的文件结构是这样的,我将对pig.JPG图片进行处理,如果你使用的是pycharm,将图片和代码放在同一个文件夹下就好了:在这里插入图片描述
我把我的pig.JPG图片放在文章中,大家可以下载然后重命名:
在这里插入图片描述
案例是为了论证一个知识点,请先看代码和运行结果,我再讲这个知识点:

import numpy as np
import cv2
pig = cv2.imread("pig.JPG")
img1 = cv2.Canny(pig,128,200)
img2 = cv2.Canny(pig,32,128)
cv2.imshow("original",pig)
cv2.imshow("128-200",img1)
cv2.imshow("32-128",img2)
cv2.waitKey()
cv2.destroyAllWindows()

在这里插入图片描述
在上面这个运行结果可以看出,阈值低的部分可以选择出更多边缘细节。
原因如下:当低阈值较小时,更多的像素梯度幅值能够大于低阈值,这就使得更多的像素有机会被标记为弱边缘像素或者强边缘像素。
例如,在一个包含一些微弱边缘的图像中,较低的低阈值可以让这些微弱边缘对应的像素梯度幅值超过低阈值,从而被考虑进入边缘检测的后续流程。
对于后续的边缘连接等操作,这些被标记为弱边缘的像素有机会与强边缘像素连接起来,最终形成完整的边缘。因为在边缘连接阶段,一些弱边缘像素如果与强边缘像素相邻或者在一定的连接规则下,它们会被判定为边缘的一部分,从而增加了边缘的完整性,捕获到更多的边缘信息。

致谢

本文参考了一些博主的文章,博取了他们的长处,也结合了我的一些经验,对他们表达诚挚的感谢,使我对 Canny边缘检测 有更深入的了解,也推荐大家去阅读一下他们的文章。纸上学来终觉浅,明知此事要躬行:
opencv基础44- Canny边缘检测详解-cv.Canny()
图像处理算法 | 高斯滤波

;