第10章 Canny边缘检测 -- Canny边缘检测基础

《OpenCV 轻松入门 面向Python》 学习笔记

Canny边缘检测基础

函数原型:

edges = cv2.Canny(image, threshold1, threshold2, apertureSize, L2gradient)

参数:

  • edges:计算得到的边缘图像
  • image:原始图像
  • threshold1:处理过程中的第一个阈值(minVal)
  • threshold2:处理过程中的第 二个阈值(maxVal)
  • apertureSize:Sobel 算子的孔径大小
  • L2gradient:计算图像梯度幅度的标识。 默认值是False,使用L1范数进行计算(直接将两个方向导数的绝对值相加);如果为True,使用更精确的L2范数进行计算(两个方向的导数的平方和再开方)。

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

  1. 去噪。噪声会影响边缘检测的准确性,因此首先要将噪声过滤掉。
  2. 计算梯度的幅度与方向。
  3. 非极大值抑制。适当的让边缘“变瘦”
  4. 确定边缘。 使用双阈值算法确定最终的边缘信息
1. 去噪 (应用高斯滤波去除噪声)

在图像中,一般会存在一些纹理较弱的非边缘区域。这些纹理较弱的非边缘就是噪声,为了避免噪声的干扰,避免检测到错误的边缘信息,我们采用高斯滤波去除图像中的噪声。

2. 计算梯度 (根据梯度的方向)

在计算梯度时,边缘检测算子会返回水平方向的梯度 G x G_x Gx 和 垂直方向的梯度 G y G_y Gy。在这里,我们不仅关注梯度的大小,还关注梯度的方向。

  • 梯度幅度:

    • 若参数 L2gradient=False,采用L1范数计算梯度幅度: G = ∣ G x ∣ + ∣ G y ∣ G = |G_x| + |G_y| G=Gx+Gy
    • 若参数 L2gradient= True,采用L2范数计算梯度幅度: G = G x 2 + G y 2 G = \sqrt{G_x^2 + G_y^2} G=Gx2+Gy2
  • 梯度方向: θ = a t a n 2 ( G x , G y ) \theta =atan2(G_x, G_y) θ=atan2(Gx,Gy),得到的梯度角度就近取值为:上,下,左,右,左上,左下,右上,右下 8个方向。

梯度的方向与边缘的方向是垂直的。
在这里插入图片描述

3. 非极大值抑制

在获取了梯度的幅度与方向后,采用非极大值抑制的方法,遍历图中的像素点,去除所有非边缘的点。
在具体实现过程中,逐一遍历像素点,判断该像素点 是否是周围(在3x3的邻域范围内,与沿着其对应的梯度方向的两个像素相比) 的最大值

  • 如果该点是正/负梯度方向上的局部最大值,则保留该点。 “正/负梯度方向上”理解为:上和下是同一个梯度方向上的正/负方向,左和右是同一个梯度方向上的正/负方向,左上和右下是同一个梯度方向上的正/负方向,右上和左下是同一个梯度方向上的正/负方向。
  • 如果不是,则抑制该点,归零处理

以图示例说明 1:
中心点的梯度幅度为8, 方向为向下,所以沿着其梯度方向(向上和向下)的两个像素为其上方(梯度幅度值为2,梯度方向为向下)和 其下方(梯度幅度值为2,梯度方向为向上)的两个像素。比较结果,中心像素为最大值,保留该点。
在这里插入图片描述
以图示例说明 1:
”正/负梯度方向上“指的是与自己方向相同,以及与自己相反方向的梯度方向,黑色背景的像素点都是垂直方向梯度(向上,向下)方向上(水平边缘)的局部最大值。
在这里插入图片描述
经过上述处理后,同一个方向上的若干个边缘点,基本上只保留了一个,因此实现了边缘细化的目的

4. 应用双阈值确定边缘

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

设定两个阈值(函数参数),其中一个为高阈值maxVal,另一个为低阈值minVal,根据当前边缘像素的梯度值与这两个阈值的关系,判断边缘的属性:
(1)如果当前边缘像素的梯度值大于或等于maxVal,则将当前边缘像素标记为强边缘
(2)如果当前边缘像素的梯度值介于maxVal和minVal之间,则将当前边缘像素标记为虚边缘
(3)如果当前边缘像素的梯度值小于或等于minVal,则抑制当前边缘像素

上述过程中,我们得到的虚边缘需要做进一步处理:
(4)如果该虚边缘与强边缘有连接,则将该边缘处理为边缘
(5)如果该虚边缘与强边缘无连接,则抑制该边缘


举例:

import cv2
import numpy as np

image = cv2.imread("/Users/manmi/Desktop/lena.bmp", 0)
result_1 = cv2.Canny(image, 128, 200)
result_2 = cv2.Canny(image, 32, 128)

cv2.imshow('image', image)
cv2.imshow('result_1', result_1)
cv2.imshow('result_2', result_2)
cv2.waitKey()
cv2.destroyAllWindows()

输出为:
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Enzo 想砸电脑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值