Canny 边缘检测
选题背景
Canny 边缘检测算法[1][2]在计算机视觉领域享有"不可动摇"的历史地位,被广泛誉为边缘检测的"黄金标准"。
它的核心意义可以总结为以下四个方面:
-
从"经验启发"走向"严格数学最优化" 在 Canny 之前,大多数边缘检测算子(如 Sobel、Prewitt、Roberts)都是基于研究者的直觉和经验设计的(例如用简单的差分模板去寻找像素突变)。 Canny 第一次将边缘检测定义为一个数学最优化问题。他提出了三大严格的量化指标(信噪比、定位精度、单一响应),并运用变分法求出了理论上的最优解。 这种"定义目标 -> 数学建模 -> 求解最优"的科学范式,深刻影响了后续数十年的计算机视觉研究。
-
发现了边缘检测的"不确定性原理" Canny 在推导中证明了一个极其深刻的物理规律:检测率(抗噪性)和定位精度是一对不可调和的矛盾。 算子越宽(平滑越多),越能抵抗噪声,但边缘的位置就越模糊; 算子越窄,定位越精准,但极易把噪声当成边缘。 这一发现彻底打破了寻找"完美单一算子"的幻想,为后来的多尺度图像分析奠定了理论基础。
-
滞后双阈值完美解决"边缘断裂"行业痛点 早期的算法通常只使用一个固定阈值,只要图像中有一点点噪声波动,提取出来的边缘就像虚线一样断断续续。 Canny 创造性地引入了"滞后双阈值(Hysteresis Thresholding)“配合连通性分析,极大地提升了提取出完整、干净、连续边缘的概率。
-
强大的工程适应性与长久的生命力 虽然 Canny 推导出了复杂的理论最优算子,但他非常务实地证明了高斯一阶导数是对该算子的极佳近似。这使得算法不仅效果好, 而且计算效率极高。时至今日,距论文发表将近 40 年,Canny 算法依然是 OpenCV 等各大计算机视觉库中最常用、最底层的核心函数, 也是任何新提出的边缘检测算法必须对比的"基准线”。
算法描述(重点)
数学模型
问题定义
Canny 认为,一个优秀的边缘检测器必须满足以下三个量化的数学准则:
-
良好的检测(Good Detection):最大化输出信噪比(SNR)。
算子对边缘中心的响应为 $H_G$,对噪声的均方根响应为 $H_n$ 。其比值为:
$$ SNR = \frac{H_G}{H_n} = \frac{|\int_{-W}^{+W} G(-x)f(x)dx|}{n_0 \sqrt{\int_{-W}^{+W} f^2(x)dx}} $$其中,假设边缘模型为$G(x)$, 算子为$f(x)$,加性高斯白噪声的均方幅度为$n_0$,滤波器宽度为$W$。
-
良好的定位(Good Localization):检测到的边缘点应尽可能靠近真实边缘的中心。
定位性能被定义为边缘位置偏差均方根的倒数,通过Taylor级数和随机过程分析可得,定位算式为:
$$ Localization = \frac{|\int_{-W}^{+W} G'(-x)f'(x)dx|}{n_0 \sqrt{\int_{-W}^{+W} f'^2(x)dx}} $$ -
单一响应(Low Multiple Responses):对于单条边缘,算子应该只产生一个响应峰值,避免因噪声干扰而在边缘附近产生多个假边缘。
Canny 利用 Rice 噪声公式 来预测噪声引起的平均峰值间距 $x_{max}$
$$ x_{max}(f) = 2 \pi \left( \frac{\int f'^2(x) dx}{\int f''^2(x) dx} \right)^{1/2} $$为了保证单一边缘只被标记一次,他引入了一个约束条件:将噪声响应的平均间距设定为算子宽度的某个比例 $k$(即 $x_{max} = kW$)
假设输入为 $G(x) = Au(x)$,其中$u(x)$为阶跃函数,$A$为幅值。 要满足这三个准则,定义泛函
$$ \Sigma(f) = \Sigma(f) = \frac{|\int_{-W}^{0} f(x)dx|}{\sqrt{\int_{-W}^{W} f^2(x)dx}} \quad \Lambda(f') = \frac{|f'(0)|}{\sqrt{\int_{-W}^{W} f'^2(x)dx}} $$现在,问题变成了一个经典的变分学问题:寻找一个函数 $f(x)$,使得目标泛函 $\Sigma(f) \cdot \Lambda(f’)$ 取得极大值, 同时满足单一响应约束和边界条件。
变分法求解泛函极值
由于 $\Sigma$ 和 $\Lambda$ 中的积分形式复杂,Canny 使用了等周问题(Isoperimetric Problem)的技巧。 因为尺度变换不改变目标函数的极值结构,他将分母中的积分设定为常数,从而将问题转化为最小化分母之一,同时受其他积分常数约束的形式。
他构造了带有拉格朗日乘子($\lambda_1, \lambda_2, \lambda_3$)的复合泛函
$$ \Psi(f, f', f'') = f^2 + \lambda_1 f'^2 + \lambda_2 f''^2 + \lambda_3 f $$根据变分法求极值的必要条件,函数 $f(x)$ 必须满足欧拉-拉格朗日方程。 对于包含高阶导数的泛函,其欧拉方程为:
$$ \frac{\partial \Psi}{\partial f} - \frac{d}{dx}\left(\frac{\partial \Psi}{\partial f'}\right) + \frac{d^2}{dx^2}\left(\frac{\partial \Psi}{\partial f''}\right) = 0 $$将 $\Psi$ 代入,得到一个常系数四阶常微分方程:
$$ 2f(x) - 2\lambda_1 f''(x) + 2\lambda_2 f''''(x) + \lambda_3 = 0 $$求解特征方程:通过求二次变分 $\delta^2 J$,Canny 证明了为了使系统存在最小值,方程的特征根必定是四个复数根, 形式为 $\gamma = \pm \alpha \pm i\omega$。因此,该微分方程在区间 $[-W, 0]$ 内的通解是一个有阻尼的振荡系统, 即指数函数与三角函数的乘积叠加:
$$ f(x) = a_1 e^{\alpha x} \sin(\omega x) + a_2 e^{\alpha x} \cos(\omega x) + a_3 e^{-\alpha x} \sin(\omega x)+ a_4 e^{-\alpha x} \cos(\omega x) + c $$利用边界条件$f(0)=0, f(-W)=0$,可以解出待定系数。经过数值优化后,Canny 发现这个四阶微分方程的解在波形上极其逼近高斯函数的一阶导数 $G’(x) = -\frac{x}{\sigma^2} \exp(-\frac{x^2}{2\sigma^2})$。
扩展至二维
上述推导是在一维切面上完成的。在真实的二维图像 $I(x,y)$ 中,边缘的方向是未知的。Canny 利用了多变量微积分将算法扩展到二维空间。 设二维平滑函数为对称高斯 $G(x,y)$。图像被平滑后,任意一点的法向向量(即梯度方向 $\vec{n}$)可以由下式确定:
$$ \vec{n} = \frac{\nabla (G * I)}{|\nabla (G * I)|} $$在二维平面上寻找边缘点,等价于在梯度方向 $\vec{n}$ 上,寻找方向导数 $G_{\vec{n}}$ 的局部最大值。 在微积分中,方向导数的极值点对应于二阶方向导数的零交叉点。因此,非极大值抑制的数学本质就是求解以下偏微分方程:
$$ \frac{\partial^2}{\partial \vec{n}^2} (G * I) = 0 $$算法流程
高斯平滑滤波
由于图像在获取和传输过程中往往会受到噪声干扰,而边缘检测本质上是求导操作,导数对噪声极为敏感(噪声会导致局部强烈的假边缘)。 因此,第一步必须使用高斯滤波器对图像进行平滑降噪。实际上,根据卷积的性质(由于偶函数卷积和互相关等价,所以这里直接用卷积代替) 高斯滤波与梯度计算的结合就相当于用高斯核的一阶导数对图像进行滤波。
$$ \frac{d}{dx} \left(f * g\right) = f * \frac{d}{dx}g $$用一个二维高斯核与原始图像进行卷积。高斯核的大小(例如 $3\times3$、$5\times5$)和标准差 $\sigma$ 决定了平滑的程度。$\sigma$ 越大,平滑越强,抗噪越好, 但边缘细节也会丢失更多。这一点 Canny 也在论文中提到了,就是所谓的"不确定性原理",将泛函在空间上缩放,即令
$$ \Sigma(f_\omega)=\sqrt{\omega}\Sigma(f),\quad\Lambda(f_\omega')=\frac{1}{\sqrt{\omega}}\Lambda(f') $$$\omega$对两个指标的作用是相反的。
计算梯度幅值和方向
找到图像中像素亮度变化最剧烈的地方,即潜在的边缘。边缘通常发生在亮度突变的地方,数学上表现为一阶导数的极值。 使用差分算子(最常用的是 Sobel 算子,也有用 Prewitt 或 Roberts 算子的)分别计算图像在水平方向(X 轴)和垂直方向(Y 轴)的梯度幅值 $G_x$ 和 $G_y$。 然后计算每个像素点的综合梯度幅值和梯度方向:
- 梯度幅值: $G = \sqrt{G_x^2 + G_y^2}$(代表边缘的强度)
- 梯度方向: $\theta = \arctan\left(\frac{G_y}{G_x}\right)$ (代表边缘的走向,垂直于边缘)
非极大值抑制
将模糊、较宽的边缘"瘦身"为单像素宽的细线条,精确定位边缘中心。经过平滑和梯度计算后,得到的边缘往往比较粗。我们要找出真正的边缘点, 也就是在局部梯度方向上变化最剧烈的那个点。
遍历图像中的每一个像素,查看该像素的梯度方向。为了简化计算,通常将梯度方向近似为四个主要方向之一:0°(水平)、45°(对角)、90°(垂直)或 135°(反对角)。 沿着这个梯度方向,比较该像素与其前后相邻两个像素的梯度幅值。
- 如果该像素的梯度幅值不是这三个点中最大的,则将其梯度值设为 0。
- 如果它是最大的,则保留其梯度值,作为候选边缘点。
双阈值检测
区分真实的强边缘和可能由噪声引起的弱边缘。经过非极大值抑制后,剩下的像素点都是局部的梯度极大值, 但其中有些极大值可能是由微小的噪声波动引起的。Canny 引入了高、低两个阈值。设定一个高阈值和一个低阈值
- 强边缘:梯度幅值 > 高阈值。这些被认为是极其可靠的真实边缘。
- 弱边缘:低阈值 < 梯度幅值 $\le$ 高阈值。这些点待定,可能是真实边缘的延伸,也可能是噪声。
- 被抑制:梯度幅值 $\le$ 低阈值。直接当作背景或噪声剔除,值设为 0。
滞后边界跟踪
解决边缘断裂问题,将有效的弱边缘连接成完整的线条。真实的边缘通常是连续的。如果一个弱边缘点与一个强边缘点相连, 那么这个弱边缘很大概率也是真实边缘的一部分;如果一个弱边缘孤立存在,则很可能是噪声。
遍历所有的"弱边缘"像素:检查其周围的连通邻域。如果在这个邻域内存在至少一个强边缘像素,那么这个弱边缘就被保留, 并升级为强边缘,正式成为最终输出的边缘点。如果周围没有任何强边缘相连,则将该弱边缘抑制,设为 0。
尺度讨论
根据上述公式,$\omega$对两个指标的作用是相反的,而高斯核$\sigma$正比于$\omega$,因此我们可以得出以下定性的分析
- $\sigma$ 越小,平滑越弱,抗噪越差,但边缘细节也会保留更多。
- $\sigma$ 越大,平滑越强,抗噪越好,但边缘细节也会丢失更多。
软件实现
编程语言为python 3.11.0,开发环境为PyCharm 2025.3.3。
高斯平滑滤波
采用上次作业中的高斯平滑滤波函数。
计算梯度幅值和方向
使用 Sobel 算子计算图像在水平方向(X 轴)和垂直方向(Y 轴)的梯度幅值 $G_x$ 和 $G_y$, 再通过式计算每个像素点的综合梯度幅值和梯度方向。
注意:这里进行滤波的时候不能使类型为uint8,Sobel 算子的计算结果可以为负数, 若使用uint8类型会导致计算值溢出。所以我采用了float32类型。

Sobel 算子代码
非极大值抑制
由于圆周上下对称,搜索也是前后都进行的,所以只需要半圆的四个方向即可。 将半圆周四等分,分别对应0°、45°、90°、135°。判断前后两个像素的梯度幅值是否大于当前像素的梯度幅值。
注意:遍历范围需要往内部缩减一格,否则会溢出。

非极大值抑制代码
双阈值检测
按照理论的实现即可,我这里采用的是取相对比例抑制,opencv中的Canny函数是直接设定高阈值和低阈值。 由于不同图像中的阈值范围不同,设置比例可能更加通用一点。

双阈值检测代码
滞后边界跟踪
此处搜索范围为$3\times3$

滞后边界跟踪代码
数据分析和可视化
图片采用经典的cameraman图像,包含多个不同的边缘和噪声。
每步拆分
高斯核采用$\sigma = 1.4$,$ksize = (5, 5)$,高阈值比例为$0.12$,低阈值比例为$0.05$。处理结果如下所示。 可以看到,非极大值抑制很好地将边缘精确定位下来,滞后阈值检测则能够将边缘连接起来,但由于探测范围比较小,连接的边有限。 后方的建筑物就因为缺少足够的强边缘而被略去了。

原始图像

高斯滤波

Sobel 算子滤波

非极大值抑制

双阈值检测

滞后边界跟踪
尺度讨论
分别对 $\sigma=0.5, 1.0, 1.5, 2.0$ 进行测试。下图展示了不同高斯平滑尺度对边缘检测结果的影响。
可以看到,当 $\sigma=0.5$ 时,平滑程度较低,边缘检测结果保留了极高的细节, 但同时对噪声极其敏感。前方草地极细碎的纹理以及图像固有的高频噪点都被当作边缘提取了出来,使得画面显得较为杂乱。
当 $\sigma=1.0$ 时,高斯滤波的平滑作用开始显现,草地区域的细碎噪点被大量抑制, 同时人物主体和背景建筑的轮廓依然保持清晰,取得了较好的信噪比与定位精度折中。
当 $\sigma=1.5$ 时,图像中的高频噪点已基本被完全滤除,画面十分干净。但由于平滑尺度的增大, 部分真实弱边缘的梯度幅值下降,导致后方远景建筑群的微弱轮廓开始被阈值抑制并逐渐消失。
当 $\sigma=2.0$ 时,高频信息被进一步过度平滑。不仅更多细节边缘(如摄影师大衣的褶皱、远处的塔楼结构)因梯度跌破阈值而彻底丢失, 且定位精度(Localization)的显著下降导致部分相邻边缘发生移位或粘连,造成局部线条结构失真。 总体而言,有效边缘的数量随着 $\sigma$ 的增大呈现减少趋势。

σ=0.5

σ=1.0

σ=1.5

σ=2.0
结论
本次作业从底层数学原理出发,深入剖析并完整复现了 Canny 边缘检测算法。主要成果包括:
- 理论验证:系统梳理了算法背后的变分法最优化模型与三大评价准则,深刻理解了边缘检测中抗噪性与定位精度之间不可调和的"不确定性原理"。
- 底层算法实现:脱离高度封装的计算机视觉库,利用 Python 与 NumPy 库从零构建了高斯平滑、Sobel 梯度计算、非极大值抑制(NMS)以及滞后双阈值连通等核心模块,成功实现了将模糊的图像梯度细化为单像素宽连续轮廓的完整处理链路。
- 尺度效应分析:通过对经典 Cameraman 测试图像的参数对比实验,直观且定量地验证了高斯核标准差 $\sigma$ 对特征提取结果的影响。实验结果与理论推导高度吻合,证实了 $\sigma$ 增大时高频细节丢失及边缘定位精度下降的物理现象。
参考文献
[1] Canny, J. (1986). A Computational Approach to Edge Detection. IEEE Transactions on Pattern Analysis and Machine Intelligence, PAMI-8(6), 679-698.
[2] Gonzalez, R. C., & Woods, R. E. (2011). Digital Image Processing (3rd ed.). Prentice Hall.