[图像处理]-Canny边缘检测算法

1.问题描述

在处理图像时,有时我们需要图像的边界或通过边界得到一定的信息,如何有效而准确的找到这些边界并显示出来就了一个问题,而Canny算法则可以很好的解决它。

2.简述Canny算法

Canny 是一种 multi-stage 算法,分别如下:

  1. 高斯滤波:平滑图像,消除噪声
  2. 梯度和方向计算:利用Sobel算子计算每个像素点的梯度和方向
  3. 非极大值抑制:消除边缘检测带来的杂散相应(本来不是边缘检测出来是)
  4. 双阈值:检测真正和潜在的边缘
  5. 滞后技术:通过抑制弱边缘来完成边缘检测跟踪边界
2.1高斯滤波

本质就是模糊图像,玩过PS的应该很好了解,本来图像上有很多噪点,用涂抹工具抹一下,噪点没了,图片变模糊了,噪点消失了.
这一阶段比较类似于卷积,拿一个33或55的带权重的滤波器给图像乘一下.
这里以size=3的高斯内核为例:这里做了归一化处理(元素和为 1)
在这里插入图片描述
滤波的主要目的是降噪,一般的图像处理算法都需要先进行降噪。而高斯滤波主要使图像变得平滑(模糊),同时也有可能增大了边缘的宽度。

2.2计算图像梯度及方向

对于平滑后的图像,首先在水平和垂直方向采用 Sobel kernel 计算得到水平方向Gx和垂直方向Gy(具体计算过程参考链接).

然后计算每个像素的边缘梯度和梯度方向:
在这里插入图片描述
这样就得到的图像中每一个点的梯度值及梯度方向

2.3非最大值抑制 NMS

计算得到梯度值和梯度方向后,对图片进行全面的扫描,以去除不构成边缘的无关像素点.

对于每个像素,检查其是否是在梯度方向中其临近像素点中的局部最大值. 如图:
在这里插入图片描述
点 A 位于图像边缘(垂直方向). 梯度方向(Gradient Direction) 垂直于边缘. 点 B 和点 C 位于梯度方向.
因此,检查点 A 和点 B,点 C,确定点A 是否是局部最大值. 如果点 A 是局部最大值,则继续下一个阶段;如果点 A 不是局部最大值,则其被抑制(设为 0).

简单来说,NMS 得到的结果是一个 薄边缘(thin edges) 的二值图片.可以理解为边缘点全部被标为1,非边缘点被标为0 .

2.4双阈值筛选

这一阶段主要判断上面NMS后的哪些是真正的边缘,哪些是假边缘
该阶段需要设定两个阈值,minVal 和 maxVal,任何边缘强度大于maxVal的确定为边缘,而小于minVal的确定为非边缘,进行丢弃.
位于maxVal与minVal之间的为待确定边缘,进行连续性判断,如果其连着确定边缘则认为是真正边缘的一部分,否则,进行丢弃.如下图所示.
在这里插入图片描述
边缘 A 大于 maxVal,因此为“确定边缘(sure-edge)”.
虽然边缘 C 小于 maxVal,但其连接着边缘 A,因此也认为是有效边缘,以得到完整的边缘曲线.
但,边缘 B 虽然大于 minVal,并与边缘 C 位于相同的区域,但其没有与任何“确定边缘”相连接,因此,丢弃该边缘 B.
由上可见,minVal 和 maxVal 值的选择对于边缘检测的结果非常重要.

此外,该阶段的处理还移除小的像素噪声,因为假设边缘是长曲线.
最终,即可得到图片的有效边缘.

注意
具体这两个值怎么设置,我们就要分析两个值变化对图像的影响。

  • maxVal: 带来最明显的差异,增大maxVal无疑会导致原来的边界点可能会直接消失。但这种消失时是成片消失。

  • minVal: 增大minVal,会导致有些待定像素点被弃用,也就是靠近边界像素点的介于双阈值之间的被弃用。导致的现象就是边界出现破损,这种非成片消失。只是边界信息不完整。

下面以 video = cv2.Canny(img, 80, 250) 为例:分别增大minVal和maxVal。

  • 增大minVal: (边界出现缺损)
    在这里插入图片描述
  • 增大maxVal: (边界出现成片消失,边界信息完整)
    在这里插入图片描述
    在实际应用中,观察梯度图像,如果边界信息缺损,那么适当的减小minVal;如果有不想要的区域出现,那么适当的增加MaxVal。

3.opencv实现

OpenCV 提供了 cv2.canny() 函数.

edge = cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient ]]])
###
参数 Image - 输入图片,必须为单通道的灰度图
参数 threshold1 和 threshold2 - 分别对应于阈值 minVal 和 maxVal
参数 apertureSize - 用于计算图片提取的 Sobel kernel 尺寸. 默认为 3.
参数 L2gradient - 指定计算梯度的等式. 当参数为 True 时,采用 2.2 中的梯度计算公式,其精度更高;否则采用的梯度计算公式为:
梯度|G|=|Gx|+|Gy|
###

具体代码如下

    import cv2
    import numpy as np
    from matplotlib import pyplot as plt

    img = cv2.imread('test.jpg',0)
    edges = cv2.Canny(img, 100, 200)

    plt.subplot(121),plt.imshow(img,cmap = 'gray')
    plt.title('Original Image'), plt.xticks([]), plt.yticks([])
    plt.subplot(122),plt.imshow(edges,cmap = 'gray')
    plt.title('Edge Image'), plt.xticks([]), plt.yticks([])

    plt.show()

效果
在这里插入图片描述
带滚动条代码

import numpy as np
import cv2

def nothing(x):
    pass

img=cv2.imread('/home/cheng/Desktop/1.jpg',0)

cv2.namedWindow('res')
cv2.createTrackbar('min','res',0,25,nothing)
cv2.createTrackbar('max','res',0,25,nothing)
while(1):
    if cv2.waitKey(1)&0xFF==27:
        break
    maxVal=cv2.getTrackbarPos('max','res')
    minVal=cv2.getTrackbarPos('min','res')
    canny=cv2.Canny(img,10*minVal,10*maxVal)
    cv2.imshow('res',canny)
cv2.destroyAllWindows()

效果
在这里插入图片描述

4.参考

opencv-python(13):Canny边缘检测
Python - Opencv 之 Canny 边缘检测
Canny边缘检测算法

03-15
<think>好的,我现在需要回答用户关于Canny边缘检测算法及其在OpenCV中的应用的问题。首先,我要确保自己正确理解Canny算法的各个步骤,并能够清晰地解释每个步骤的作用。根据用户提供的引用内容,特别是引用[2]和引用[4],Canny算法包括噪声抑制、计算梯度、非极大抑制、双阈检测和边缘跟踪这几个关键步骤。 首先,噪声抑制部分,通常使用高斯滤波来平滑图像,减少噪声的影响。这部分需要解释为什么需要这一步,可能用户会好奇为什么首先要模糊图像,反而可能觉得这会降低边缘的清晰度。所以我要说明噪声对边缘检测的干扰,高斯滤波的作用是去除噪声,同时保留边缘信息。 接下来是计算梯度,这里需要提到使用Sobel算子来检测水平和垂直方向的边缘,并计算梯度的幅和方向。这部分可能需要详细说明Sobel算子的工作原理,以及梯度方向如何用于后续的非极大抑制。 然后是非极大抑制,这一步的目的是细化边缘,只保留局部最大梯度的像素点,抑制其他非极大的点。用户可能对如何比较相邻像素的梯度感兴趣,需要解释清楚这个过程,比如根据梯度方向比较相邻像素的梯度幅,保留最大。 双阈检测部分,需要解释高阈和低阈的作用,如何通过这两个阈来区分强边缘、弱边缘和非边缘像素。同时,要说明如何通过滞后阈处理来连接边缘,确保边缘的连续性。这里可能需要举例说明不同阈设置对结果的影响,比如引用[3]中的代码示例,调整minVal和maxVal参数会如何改变检测效果。 最后是边缘跟踪,连接强边缘并去除孤立的弱边缘点。这部分要说明如何通过弱边缘与强边缘的连接来确定最终的边缘,避免断断续续的边缘。 在应用部分,用户提到了OpenCV中的Cv2.Canny方法,如引用[1]和[3]中的代码示例。需要解释该函数的使用方法,参数的意义,比如低阈和高阈的设置,以及如何调整这些参数来优化边缘检测的结果。可能还需要提到不同参数对检测效果的影响,比如较高的阈会减少噪声但可能丢失部分边缘,较低的阈则保留更多边缘但可能引入噪声。 此外,用户提供的引用[4]提到了非极大抑制和双阈算法的示意图,这可能有助于用户直观理解这些步骤,但回答中无法展示图片,所以需要用文字描述清楚。 最后,生成相关问题时,需要考虑用户可能进一步想了解的内容,比如参数调整技巧、算法优缺点、与其他边缘检测算法的比较、实际应用案例等。确保问题能够引导用户深入学习和应用Canny算法。 在整理回答时,要注意使用正确的LaTeX格式,行内公式用$...$,独立公式用$$...$$。例如,在解释高斯滤波时,可能需要写出高斯核的数学表达式,如$G(x,y) = \frac{1}{2\pi\sigma^2}e^{-\frac{x^2+y^2}{2\sigma^2}}$,但根据用户的引用内容,可能不需要深入数学细节,所以需要判断是否必要。 另外,确保引用标识正确添加,每个引用来源的末尾自然标注[^n],比如在提到Canny算法由John F. Canny提出时,引用[2],在提到双阈检测时引用[4]等。 最后,代码示例部分需要检查是否正确,如引用[1]和[3]中的代码,确保解释清楚每个参数的作用,比如在cv2.Canny(img, 50, 150)中,50和150分别代表低阈和高阈,以及如何影响结果。 总结步骤:先概述Canny算法的流程,分步骤详细解释,结合OpenCV的实现,提供代码示例,说明参数调整,最后生成相关问题。</think>### Canny边缘检测算法及其OpenCV实现 Canny边缘检测是一种多阶段算法,用于在图像中准确识别边缘。它由John F. Canny于1986年提出,至今仍被广泛使用[^2]。其核心步骤包括: 1. **高斯滤波降噪** 通过高斯滤波器平滑图像以减少噪声干扰。高斯核的数学表示为: $$G(x,y) = \frac{1}{2\pi\sigma^2}e^{-\frac{x^2+y^2}{2\sigma^2}}$$ 其中$\sigma$控制平滑程度,$\sigma$越大,去噪效果越强,但可能模糊边缘2. **计算梯度幅与方向** 使用Sobel算子分别计算水平和垂直方向的梯度($G_x$和$G_y$),得到梯度幅$M = \sqrt{G_x^2 + G_y^2}$和方向$\theta = \arctan\left(\frac{G_y}{G_x}\right)$[^4]。 3. **非极大抑制** 仅保留梯度方向上幅最大的像素,抑制非极大像素,使边缘更细。例如,若梯度方向为水平,则比较左右像素的幅[^4]。 4. **双阈检测与边缘连接** - **高阈(`maxVal`)**:高于此的像素视为强边缘- **低阈(`minVal`)**:低于此的像素被抑制。 - **中间区域**:若与强边缘相连则保留,否则剔除。 5. **边缘跟踪** 通过连接相邻的强边缘点,形成完整边缘--- ### OpenCV中的实现 OpenCV提供`cv2.Canny()`函数,参数包括输入图像、低阈和高阈: ```python import cv2 img = cv2.imread("image.jpg", cv2.IMREAD_GRAYSCALE) edges = cv2.Canny(img, 50, 150) # 低阈50,高阈150 cv2.imshow("Edges", edges) cv2.waitKey(0) ``` - **阈调整**:低阈过高可能导致边缘断裂,过低则引入噪声。例如,`cv2.Canny(img, 80, 150)`比`cv2.Canny(img, 50, 100)`保留更少边缘但更干净[^3]。 --- ### 应用场景 - **医学影像分析**:如血管边缘提取。 - **自动驾驶**:车道线检测。 - **工业检测**:零件轮廓识别。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值