对边缘的直观理解

边缘有助于我们对图像进行语义理解。直观上,边缘发生在图像强度值变化剧烈的地方

如何描述变化?自然是用导数/梯度

如上图,我们对图中的信号在水平方向上求导,可以得到右侧的导数图像,可以看到,它在边缘处由于信号发生剧烈变化,导数产生了极值。因此,导数的极值点能帮助我们定位边缘所在。

用卷积描述导数

对于一个二元的连续函数f(x,y)其偏导数可由如下极限得到:

\[\frac{\partial f(x, y)}{\partial x} = \lim_{\varepsilon \to 0} \frac{f(x + \varepsilon, y) - f(x, y)}{\varepsilon}
\]

而对于离散的图像数据,我们通常使用如下表达式近似偏导数,也就是有限差分的方式:

\[\frac{\partial f(x, y)}{\partial x} \approx \frac{f(x + 1, y) - f(x, y)}{1}
\]

而这种计算方式,可以用卷积核的形式进行处理:

x方向上的导数可理解为右边的像素减去我自己,转化成卷积核长这样:

y方向上的导数可理解为上面的像素减去我自己,转化成卷积核长这样:

用这种卷积核对图像做卷积,得到每个像素点在x和y方向上的导数:

其他几种表示导数的卷积核

除了上面这种”极简“导数卷积核外,我们常用的还有以下几种卷积核:

Prewitt

该算子考虑了上下两层的信息,增强了对弱边缘的捕获能力,更具有鲁棒性。

Sobel

该算子在其中心列/行上权重为2,也就是说更关注自身所在列/行,能够抵御一定的噪声干扰。

这个卷积核可以分解为

\[\begin{bmatrix}
1 \\
2 \\
1
\end{bmatrix}
\cdot
\begin{bmatrix}
-1 & 0 & 1
\end{bmatrix}
\]

可以把卷积分解成两次小的卷积操作,降低计算复杂度。

Roberts

可以检测45°/135°边缘。

从工程实践来说,Sobel算子具有良好的抗噪性和运算效率,其综合性能最优,是最常用的求导卷积核。OpenCV等库的默认实现。为了解决其在方向上的局限性(x,y两个方向),也常组合使用多方向核(如8方向Sobel扩展)。

图像2D上的导数---梯度

1D上叫导数,2D上叫梯度。把函数对x和y的偏导数放到一个向量中,该向量就表示了梯度信息。

\[\nabla f = \left[ \frac{\partial f}{\partial x}, \frac{\partial f}{\partial y} \right]
\]

这个梯度向量的方向,就表达了当前像素点主要是在这个方向上变化

\[\theta = \tan^{-1} \left( \frac{\partial f}{\partial y} / \frac{\partial f}{\partial x} \right)
\]

向量的长度,就是在这个方向上变化的快慢

\[||\nabla f|| = \sqrt{\left( \frac{\partial f}{\partial x} \right)^2 + \left( \frac{\partial f}{\partial y} \right)^2}
\]

该点的梯度长度,决定了该点是不是边缘,边缘点的梯度变化大,非边缘的梯度小。

梯度的方向,垂直于边。

把梯度的模算出来,画在图像上,就得到了梯度强度图,取一个阈值,就能取到边缘上的点。

(也可以理解为取极值点,但极值点可能比较离散,连不成一条线)

真实场景的应用---高斯偏导核

对于实际图像来说,由于噪声存在,如果直接使用上面的导数卷积核,就会造成如下情况:

导数的极值到处都是。如何处理噪声?我们可以做高斯平滑。

如下图所示,我们先做平滑,再进行求导

这两步又可以合成一步(卷积的交换律,结合律),也就是

\[\frac{d}{dx}(f*g) = f * \frac{d}{dx}g
\]

高斯平滑加导数,等效于直接对高斯核做导数,然后与之卷积

也就是高斯偏导核

二维的高斯偏导核图像如图:

注意:这里的x方向的高斯偏导核是不可以再分解成两个高斯核的,可以从高斯函数公式的导数公式看出。

原高斯核可以分成两个方向的高斯核相乘。也就可以先对x方向求卷积,再对y方向求卷积。

高斯偏导核的σ影响:下图σ为1,3,7

可以看到σ越小,检测到的边缘越精细,越大,检测到的边缘的尺度越大。

高斯核 vs 高斯偏导核

高斯核:

  • 高频率波,低通滤波
  • 权值为正
  • 加权和为正

高斯偏导核

  • 高斯核的导数
  • 可为负
  • 加权和为0
  • 高对比度(边缘)处有高绝对值的加权值

Canny算法

通过上文中的方法,我们首先计算高斯偏导核的卷积结果,得到梯度模的图像

设置阈值对边缘点进行筛选:

这里存在一个问题:由于做了高斯模糊,阈值以上部分边缘看起来很粗

如上图,我们设置阈值之后,阈值以上的部分是一段相对较粗的区域,边缘的具体位置不精确。而实际上我们更期望得到的边缘是更精准的一条线。这里我们需要引入非最大化抑制的方法。

非最大化抑制 non-maximun suppression

我们在每个像素的梯度方向上判断前后两个点和自身模的大小,如果自己是最大的则保留,否则不保留。

如上图所示,q点的梯度方向上,前后两个点分别是r和p,梯度大小可以通过像素点上的梯度插值得到。判断p、q、r的梯度大小,如果q是最大的,则q点保留下来;如果q不是最大的,则q点舍弃。

由于梯度方向和边缘是垂直关系,这样从整体来看,我们最终留下了那个边缘垂线方向上的极值点

然而这里又产生了新问题:求得结果不连通

如图中人脸下巴位置处,理应有一条边缘连接起来,而由于光照等因素影响,使得该处梯度变化不明显,检测出的边缘无法连通;而如果我们降低阈值,有可能引入更多的噪声因素。

此时,我们可以引入双阈值检测方法。

双阈值检测 Hysteresis Thresholding

该方法的核心思路在于设置高低两种阈值,筛选出可信的边缘,再利用边缘的连通性补全弱边缘信息。

  1. 用高阈值检测出图中粗的部分,这部分梯度变化剧烈且稳定,受噪声干扰小,比较鲁棒。
  2. 用低阈值检测弱边缘,这部分可能包含较多的候选点,也包含更多的噪声。
  3. 这里引入一个先验条件,有效的弱边缘一定与高阈值检测出的强边缘连通。因此,我们可以检查弱边缘像素候选点的8邻域像素:
    • 若邻域内存在强边缘像素,则该弱边缘点标记为有效
    • 若邻域内不存在强边缘像素,则该弱边缘点视为噪声,舍弃掉。

      下图为通过双阈值检测得到的结果:

总结Canny算法步骤

  1. 使用高斯导数过滤图像

    首先,对图像进行高斯滤波,以减少噪声并平滑图像,为后续的边缘检测做好准备。

  2. 找到梯度的大小和方向

    计算图像的梯度,确定每个像素点的梯度幅度和方向。梯度幅度表示边缘的强度,梯度方向表示边缘的方向。

  3. 非最大抑制(Non-maximum suppression)​

    将宽的“脊”缩小到单个像素宽度。通过比较每个像素点的梯度幅度与其相邻像素点,保留局部最大值,从而细化边缘。

  4. 双阈值检测​

    定义高低两个阈值:

    • 使用高阈值初步检测边缘曲线,确保鲁棒性强的边缘被保留。
    • 使用低阈值来链接边缘曲线,把和强边缘相接的弱边缘连接起来。

边缘检测及Canny算法的更多相关文章

  1. OpenCV探索之路(六):边缘检测(canny、sobel、laplacian)

    边缘检测的一般步骤: 滤波--消除噪声 增强--使边界轮廓更加明显 检测--选出边缘点 Canny算法 Canny边缘检测算法被很多人推崇为当今最优秀的边缘检测算法,所以我们第一个就介绍他. open ...

  2. 边缘检测之Canny

    1. 写在前面 最近在做边缘检测方面的一些工作,在网络上也找了很多有用的资料,感谢那些积极分享知识的先辈们,自己在理解Canny边缘检测算法的过程中也走了一些弯路,在编程实现的过程中,也遇到了一个让我 ...

  3. [OpenCV入门教程之十二】OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑

    http://blog.csdn.net/poem_qianmo/article/details/25560901 本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog ...

  4. 学习 opencv---(11)OpenC 边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器

    本篇文章中,我们将一起学习OpenCV中边缘检测的各种算子和滤波器——Canny算子,Sobel算子,Laplace算子以及Scharr滤波器.文章中包含了五个浅墨为大家准备的详细注释的博文配套源代码 ...

  5. Canny算法检测边缘

    Canny算法是边缘检测的一个经典算法,比单纯用一些微分算子来检测的效果要好很多,其优势有以下几点: 边缘误检与漏检率低. 边缘定位准确,且边界较细. 自带一定的滤噪功能,或者说,对噪声的敏感度要比单 ...

  6. 边缘检测:Canny算子,Sobel算子,Laplace算子

    1.canny算子 Canny边缘检测算子是John F.Canny于 1986 年开发出来的一个多级边缘检测算法.更为重要的是 Canny 创立了边缘检测计算理论(Computational the ...

  7. opencv目标检测之canny算法

    canny canny的目标有3个 低错误率 检测出的边缘都是真正的边缘 定位良好 边缘上的像素点与真正的边缘上的像素点距离应该最小 最小响应 边缘只能标识一次,噪声不应该标注为边缘 canny分几步 ...

  8. Canny算法源码,欢迎交流

    http://blog.csdn.net/jianxiong8814/article/details/1563109 http://blog.csdn.net/assuper/article/deta ...

  9. (22)Canny算法

    基础知识,主要是看这个博客:https://blog.csdn.net/qq_41167777/article/details/84863351

  10. opencv笔记4:模板运算和常见滤波操作

    time:2015年10月04日 星期日 00时00分27秒 # opencv笔记4:模板运算和常见滤波操作 这一篇主要是学习模板运算,了解各种模板运算的运算过程和分类,理论方面主要参考<图像工 ...

随机推荐

  1. JpaRepository动态代理执行原理

    本文基于spring-boot-starter-data-jpa:2.7.17分析 SpringBoot 里集成Jpa自动配置是如何处理的 通过分析SpringBoot 自动配置核心源码可以找到Jpa ...

  2. 基于 Admission Webhook 实现 Pod DNSConfig 自动注入

    本文主要分享如何使用 基于 Admission Webhook 实现自动修改 Pod DNSConfig,使其优先使用 NodeLocalDNS . 1.背景 上一篇部署好 NodeLocal DNS ...

  3. Diary -「NOI 2022」尘降

      又一次,以这样一种身份来到国赛赛场.起跑线延长出赛场外,我将于此开始又一场已知"无用"的竞技. 虚无中 我的尘埃盲目漂泊摇晃   时间回到数个月前的省选,\(600\) 分的总 ...

  4. MAC安装redis的简单方法

    part 1:安装redis1.官网下载压缩包https://redis.io/download or brew install redis(太慢了-)我此处选的法一,先去官网上下载包,在解压使用. ...

  5. C++:Eigen库

    了解C++的Eigen库,主要内容来自:https://blog.csdn.net/hongge_smile/article/details/107296658 ,并加入自己的笔记. 介绍 Eigen ...

  6. 3. 使用sql查询csv/json文件内容,还能关联查询?

    1. 简介 我们在前面的文章提到了calcite可以支持文件系统的数据源适配, 其实官方已经提供了相应的能力, 其支持csv和json的查询适配, 废话不多说, 直接展示. 2. Maven < ...

  7. Q:ssh远程连接慢的原因排查

    连接linux服务器一般都是使用SSH远程连接的方式.有时,SSH连接速度很慢,大约30s左右,但是ping时一切正常. 问题原因 1.server的sshd会去DNS查找访问的client ip的h ...

  8. 这或许是全网最全的 DeepSeek 使用指南,95% 的人都不知道的使用技巧(建议收藏)

    2025年春节过的好快,转眼间,大家又回到了各自工作岗位了,要说这个春节,什么最火,肯定绕不开DeepSeek. 几乎一夜之间,所有人都在关注DeepSeek,甚至我在老家,完全没用过AI的七大姑八大 ...

  9. 小程序开发实战案例五 | 小程序如何嵌入H5页面

    在接入小程序过程中会遇到需要将 H5 页面集成到小程序中情况,今天我们就来聊一聊怎么把 H5 页面塞到小程序中. 本篇文章将会从下面这几个方面来介绍: 小程序承载页面的前期准备 小程序如何承载 H5 ...

  10. day:2 软件测试流程——H模型

    软件测试流程_H 模型 一.详细流程 1.产品召开需求澄清会议,产品.开发.测试都参加 2.测试和开发拿到需求 3.测试经理拿到需求,根据需求编写测试计划 测试计划(内容:测试目的,背景,范围,测试准 ...