Canny边缘检测

1.算法概述

  图象的边缘是指图象局部区域亮度变化显著的部分,该区域的灰度剖面可以看作是一个阶跃,即从一个灰度值在很小的缓冲区域内急剧变化到另一个灰度相差较大的灰度值。图象的边缘部分集中了图象的大部分信息,图象边缘的确定与提取对于整个图象场景的识别与理解是非常重要的,同时也是图象分割所依赖的重要特征,边缘检测主要是图象的灰度变化的度量、检测和定位

  Canny 边缘检测是一种使用多级边缘检测算法检测边缘的方法。1986 年,John F. Canny 发表了著名的论文 A Computational Approach to Edge Detection,在这篇论文中详述了如何进行边缘检测。

 通常情况下边缘检测的目的是在保留原有图像属性的情况下,显著减少图像的数据规模。有多种算法可以进行边缘检测,虽然Canny算法年代久远,但可以说它是边缘检测的一种标准算法,而且仍在研究中广泛使用。

2.最优边缘准则

 Canny 的目标是找到一个最优的边缘检测算法,最优边缘检测的含义是:

(1)最优检测:算法能够尽可能多地标识出图像中的实际边缘,漏检真实边缘的概率和误检非边缘的概率都尽可能小;
(2)最优定位准则:检测到的边缘点的位置距离实际边缘点的位置最近,或者是由于噪声影响引起检测出的边缘偏离物体的真实边缘的程度最小;
(3)检测点与边缘点一一对应:算子检测的边缘点与实际边缘点应该是一一对应。 为了满足这些要求,Canny 使用了变分法(calculus of variations),这是一种寻找优化特定功能的函数的方法。最优检测使用四个指数函数项表示,但是它非常近似于高斯函数的一阶导数。

3.Canny 边缘检测基础

Canny 边缘检测分为如下几个步骤:

(1)应用高斯滤波平滑图像,目的是去除噪声。
(2)计算图像梯度,得到可能边缘;
(3)应用非最大抑制技术来消除边误检;
(4)应用双阈值的方法筛选边缘信息;
(5)利用滞后技术来跟踪边界。

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

 由于图像边缘非常容易受到噪声的干扰,为了避免检测到错误的边缘信息,通常需要对图像进行滤波以除去噪声。滤波的目的平滑一些纹理较弱的非边缘区域,以便得到更准确的边缘。在实际处理过程中,通常采用高斯滤波去除图像中的噪声。
在这里插入图片描述
图3-1  高斯滤波示例

 如图3-1演示使用高斯滤波器T对原始图像O中像素值为226的像素点进行滤波,得到该点在滤波结果图像 D 内的值的过程。

 在滤波过程中,通过滤波器对像素点周围的像素计算加权平均值,获取最终滤波结果。对于高斯滤波器T,越临近中心的点,权值越大

 对图像O中像素值为226的像素点,使用滤波器T进行滤波的计算过程及其结果为:结果=1/56×
(197×1+25×1+106×2+156×1+159×1
+149×1+40×1+107×4+5×3+71×1
+163×2+198×4+226×8+223×4+156×2
+222×1+37×3+68×4+193×3+157×1
+42×1+72×1+250×2+41×1+75×1)
= 138

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

3.2 计算梯度

 在这里,我们只需要关注梯度的方向,梯度的方向与边缘的方向是垂直的。边缘检测算子返回水平方向的Gx和垂直方向的Gy。梯度的幅度𝐺和方向𝛩(用角度值表示)为:
在这里插入图片描述
 其中,atan2(•)表示具有两个参数的arctan函数。梯度的方向总是与边缘垂直的,通常就近取值为水平(左、右)、垂直(上、下)、对角线(右上、左上、左下、右下)等 8 个不同的方向。

 因此,在计算梯度时,会得到梯度的幅度和角度(代表梯度的方向)两个值。图3-2展示了梯度的表示法。其中,每一个梯度包含幅度和角度两个不同的值。为了方便观察,这里使用了可视化表示方法。例如,左上角顶点的值“2↑”实际上表示的是一个二元数对“(2, 90)”,表示梯度的幅度为 2,角度为 90°。
在这里插入图片描述
图3-2  梯度示例

3.3 非极大值抑制

 在获得了梯度的幅度和方向后,遍历图像中的像素点,去除所有非边缘的点。在具体实现时,逐一遍历像素点,判断当前像素点是否是周围像素点中具有相同梯度方向的最大值,并根据判断结果决定是否抑制该点
 通过以上描述可知,该步骤是边缘细化的过程。针对每一个像素点:
 (1)如果该点是正/负梯度方向上的局部最大值,则保留该点。
 (2)如果不是,则抑制该点(归零)。如图3-3中,A、B、C三点具有相同的方向(梯度方向垂直于边缘)。判断这三个点是否为各自的局部最大值:如果是,则保留该点;否则,抑制该点(归零)。
在这里插入图片描述
图3-3  非极大值抑制示例之一

 通过比较判断可知,A点具有最大的局部值,所以保留A点(称为边缘),其余两点(B和C)被抑制(归零)。
 在图3-4中,黑色背景的点都是向上方向梯度(水平边缘)的局部最大值。因此,这些点会被保留;其余点被抑制(处理为 0)。这意味着,这些黑色背景的点最终会被处理为边缘点,而其他点都被处理为非边缘点
在这里插入图片描述
图3-4  非极大值抑制示例之二

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

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

3.4 应用双阈值确定边缘

 在完成非极大值抑制之后,图像的强边缘已经在当前获取的边缘图像内。但是,一些虚边缘可能也在边缘图像内。这些虚边缘可能是真实图像产生的,也可能是由于噪声产生的。对于由于噪声产生的虚边缘必须将其剔除

 因此设置两个阀值,分别为高阀值(maxVal)和低阀值(minVal)。根据当前边缘像素的梯度幅度与这两个阀值之间的关系,判断边缘的属性,具体步骤如下:
   ①如果当前边缘像素的梯度幅度大于或等于高阀值,则将当前边缘像素标记为强边缘(需要保留)。
  ②如果当前边缘像素的梯度幅度介于高阀值与低阀值之间,则将当前边缘像素标记为虚边缘(需要保留)。
  ③如果当前边缘像素的梯度幅度小于或等于低阀值,则抑制当前边缘像素(需要抛弃)。

 在上述过程中我们得到了虚边缘,需要对其做进一步处理。一般通过判断虚边缘和强边缘是否连接来确定虚边缘到底属于哪种情况。通常情况下,对于一个虚边缘:
  ①与强边缘连接,则将该边缘处理为边缘。
  ②与强边缘无连接,则该边缘为弱边缘,将其抑制。

 如图3-5,左侧显示的是三个边缘信息,右侧是对边缘信息进行分类的示意图,具体划分如下:
  ①A点的梯度值值大于maxVal,因此A是强边缘
  ②B和C点的梯度值介于maxVal和minVal之间,因此B、C是虚边缘
  ③D 点的梯度值小于minVal,因此D被抑制(抛弃)。
在这里插入图片描述
图3-5  边缘分类的示意图

 图3-6显示了对图3-5中的虚边缘B和C的处理结果,其中
  ①B点的梯度值介于maxVal和minVal之间,是虚边缘,但该点与强边缘不相连,故将其抛弃
  ②C点的梯度值介于maxVal和minVal之间,是虚边缘,但该点与强边缘A相连,故将其保留
在这里插入图片描述
图3-6   边缘分类的处理结果示意图

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

4.Canny 函数及使用

 OpenCV提供了函数 cv2.Canny()来实现 Canny 边缘检测,其语法形式如下: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观察获取到的边缘有何不同。

import cv2
original = cv2.imread("lena_gray.jpg")
result_1 = cv2.Canny(original, 64, 256)
result_2 = cv2.Canny(original, 16, 128)
result_3 = cv2.Canny(original, 8, 64)
cv2.imshow("lena_gray", original)
cv2.imshow("threshold1=64,threshold2=256时的边缘检测结果", result_1)
cv2.imshow("threshold1=16,threshold2=128时的边缘检测结果", result_2)
cv2.imshow("threshold1=8,threshold2=64时的边缘检测结果", result_3)
cv2.waitKey()
cv2.destroyAllWindows()

 程序运行结果如图4-1、4-2、4-3和4-4所示,对比可以知道,当函数cv2.Canny()的参数threshold1和threshold2的值较小时,能够捕获更多的边缘信息
在这里插入图片描述

图4-1  原始图像

在这里插入图片描述
图4-2  threshold1=64,threshold2=256时的边缘检测结果
在这里插入图片描述
图4-3  threshold1=16,threshold2=128时的边缘检测结果
在这里插入图片描述
图4-4  threshold1=8,threshold2=64时的边缘检测结果

  • 44
    点赞
  • 232
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值