【CV面试】Canny边缘检测算法与原理

本文介绍了Canny边缘检测算法的原理和步骤,包括高斯滤波、梯度计算、非极大值抑制以及双阈值检测。通过这些步骤,算法能够有效识别图像中的边缘,并减少噪声干扰。此外,文章提到了代码实现的概要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


首先,我们知道:

  1. 边缘是图像的重要特征之一;
  2. 图像边缘是数字图像的高频成分,也就是像素值变化较为剧烈的点,亮度变化比较大的点,对应图像梯度的极值;
  3. 边缘检测包括一阶微分算子,例如:Prewitt算子、Sobel算子(x,y方向);二阶微分算子,例如:Laplace算子、LoG高斯-拉普拉斯算子(Laplace of Gaussian);还有Canny边缘检测。

后面,我们详细的学习下,canny边缘检测算法的原理,和为什么要这样做,一套究竟。文末放视频参考链接,可结合视频共同学习。

一、canny边缘检测点步骤

1
检测步骤如下:

  1. 应用高斯滤波器,平滑图像,滤除噪声点(降噪,噪声点也是像素变化急剧的点,属于高频部分,提前去除,降低后续在边缘部分,引入不必要的边缘)
  2. 计算图像中每个像素点的梯度大小和方向(梯度)
  3. 使用非极大值抑制(Non-Maximum Suppression, NMS),以消除边缘检测、目标检测带来的杂散响应,即对待测边缘或目标,应尽可能有唯一的准确响应(非极大值抑制)
  4. 应用双阈值检测,确定真实和潜在的边缘(双阈值检测)
  5. 通过抑制孤立的弱边缘,完成边缘检测。

一个个的,听着挺高大上,那一步步的,都是为啥这么干呢?下面我们一一娓娓道来

1.1、如何和为什么计算每个像素点的梯度大小和方向?

梯度计算

上图,是计算一个像素点的梯度大小和方向,需要用到的滤波器和计算公式,其中:

  1. Gx-x方向的滤波算子(竖直方向)
  2. Gy-y方向的滤波算子(水平方向)
  3. G-梯度幅值大小
  4. θ-梯度方向

下面,就是lena图,和经过计算得到的梯度图,左边原图,每一个点表示的是像素值,右侧的梯度图,每一个点表示的是梯度幅值。尽管表示的都是图,但是代表的意义,是不同的:

梯度图
自问下,为什么我们要计算梯度的幅值和方向呢

  1. 我们前面提到,边是图像中像素值变化比较大的点,而梯度的幅值就是衡量像素变化率的大小
  2. 梯度的方向,是用来干什么呢?前面滤波器时候我们知道,过一个像素点,有很多的方向,我们要找到一个方向,是梯度变化最大的方向。因为只有在梯度方向上,是这个像素点变化最为剧烈的

1.2、怎么还引入非极大值抑制(Non-Maximum Suppression,NMS)?

非极大值抑制
仔细观察梯度图,我们会发现:

  1. 相比于原始图像,梯度图像显得简单了很多,但是大致的轮廓还是看的清楚;
  2. 边缘的区域,有一种朦朦胧胧的素描感,不是棱角分明的感觉,边缘白色区域是有渐变色的。

这不是我们需要的边缘。我们希望在与白色边缘垂直的梯度方向上只留下一个最大的像素点,将其他的像素点消除掉,置为 0。这也就是我们要引入非极大值抑制的最根本原因。

那么,问题又来了,该如何将目标像素点留下来,其他的给去除掉呢?那就用非极大值抑制。

非极大值抑制应用在边缘细化技术。渐变图像中每个像素的算法步骤是:

  1. 将当前像素的边缘强度(幅值),与正梯度方向和负梯度方向上的像素的边缘强度进行比较。
  2. 如果当前像素的边缘强度(幅值),与具有相同方向的掩模中的其他像素相比是最大的(即,指向y方向的像素,则将其与其上方和下方的像素进行比较,垂直轴),该值将被保留。否则,该值将被抑制。

在上图右侧的示意图里面:

  1. 蓝色斜线表示的就是梯度方向,其中C点恰好在像素点上,θ为梯度角;
  2. 梯度方向在其他两个水平方向上面,没有落在像素点上,例如其中g1、g2上点,该点的幅值是线性插值的方式计算得到的,参与到非极大值抑制中去。

1.3、双阈值检测-边缘的连接

双阈值检验

尽管经过非极大值抑制,使得部分非必要的点给去除了,但是还会存在部分点区域,或者点是孤立,这部分的点还需要进一步的去处掉,于是,就引入了双阈值检测。

听到双阈值,就首先肯定是有两个大小不一样的,一个小阈值minVal和一个大阈值maxVal。一般open CV建议,minVal=50maxVal=minVal*3。那么:

  1. 大与maxVal的肯定是边
  2. 小于minVal的肯定不是边
  3. 介于minValmaxVal的,就是需要我们需要连接的部分。也是最复杂的部分,单独聊下过程。

介于minValmaxVal连接过程:

  1. 首先将肯定是边的点,押入栈内;
  2. 然后比较站内元素,其8邻域点各个点,是否存在;如果存在,那么这个点压入栈内;
  3. 继续步骤 2的过程,直到栈空位置,这样就将潜在是边的点,全部连接到一起了。

这样,就得到了最终检测结果,如下所示:

canny

二、代码实现

从第一章节的讲解,若要实现canny边缘检测算法,那么猜测下大概需要以下这些功能:

  1. 滤波,降噪,去除噪声;
  2. 梯度检测,得到每个像素点的梯度大小和方向;
  3. 非极大值抑制,去除部分不利梯度
  4. 双阈值检测

代码详情解析部分,待进一步学习讲解。敬请期待。相信文本中肯定还是有什么不准确的地方的,欢迎小伙伴评论区指出

参考视频:

  1. 视频地址1: canny edge detection(canny边缘检测)
  2. 视频地址2:Canny边缘检测原理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

钱多多先森

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

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

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

打赏作者

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

抵扣说明:

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

余额充值