Canny算子
📘 Canny 边缘检测学习笔记
一、Canny 算子
Canny 不是一个算子,而是一套“边缘提取流程”
目标:边缘准、细、连续、抗噪
二、Canny 的完整处理流程(最小必要)
高斯滤波 → 梯度计算 → 非极大值抑制(NMS) → 双阈值 → 滞后连接
重点:
NMS:决定“是不是一条线”
双阈值 + 滞后:决定“这条线要不要”
三、步骤 1:高斯滤波(Gaussian Blur)
作用
- 抑制噪声
- 防止噪声在梯度阶段被放大成“假边缘”
特点
- σ 越大 → 越平滑 → 边缘越少
- σ 越小 → 细节多 → 噪声多
四、步骤 2:梯度计算(Gradient)
常用方式
- 使用Sobel 算子(X / Y)计算XY上的导数,得到梯度大小并通过arctan2(GY/GX)得到梯度方向。
注意此处使用的是arctan2这个函数,这个函数能根据x和y的正负实现-Π到Π的映射,不是我们通常理解的arctan。
得到两样东西
- 梯度幅值:边缘“强不强”
- 梯度方向:边缘“法线方向”
📌 后续 NMS 完全依赖梯度方向
五、步骤 3:非极大值抑制(NMS)【核心】
1️⃣ NMS 是在做什么?
沿梯度方向,只保留梯度最大的像素,其余抑制
目的一句话:
把“多像素宽的边缘带”压成“单像素边界线”
2️⃣ 梯度方向的离散化(工程关键)
真实梯度是连续的,但 Canny 只使用 4 个方向:
| 连续角度 | 离散方向 |
|---|---|
| ≈ 0° | 0° |
| ≈ 45° | 45° |
| ≈ 90° | 90° |
| ≈ 135° | 135° |
📌 注意:
方向是“选比较方向”,不是“比较数量”
3️⃣ NMS 实际比较的是几个点?
永远只比较 2 个点,即在当前点的梯度方向上选择前后两个点(方向一致才比较,否则不进行比较)。
- 当前像素 P
- 沿梯度方向的前后两个邻居
4️⃣ 各方向比较示意

- 0°:左 / 右
- 90°:上 / 下
- 45°:左上 / 右下
- 135°:左下 / 右上
保留条件:
G(P) ≥ G(neighbor1) 且 G(P) ≥ G(neighbor2)
否则:
G(P) = 0
5️⃣ NMS 的本质理解(非常重要)
NMS = 沿梯度方向的一维峰值检测
-
梯度方向 = 边缘法线方向
-
我们只关心:
当前点是不是“法线方向上的极大值”
六、步骤 4:双阈值检测(Double Threshold)【核心】
1️⃣ 为什么不能用单阈值?
- 阈值高 → 边缘断裂
- 阈值低 → 噪声大量出现
👉 单阈值无法兼顾“完整性”和“纯净度”
2️⃣ 双阈值的基本思想

设定两个阈值:
- High Threshold
- Low Threshold
对 NMS 后的像素分类:
| 梯度值 | 分类 |
|---|---|
| ≥ High | 强边缘 |
| Low ~ High | 弱边缘 |
| < Low | 非边缘 |
3️⃣ 强边缘 vs 弱边缘的真实含义
- 强边缘
→ 几乎可以确定是真边缘 - 弱边缘
→ 自身不确定,但可能是真边缘的延续,仅当弱边缘与强边缘相连时才保留。
📌 弱边缘 ≠ 噪声
七、步骤 5:滞后阈值(边缘连接)
规则
弱边缘只有在“连接到强边缘”时才被保留
- 与强边缘 8 邻域连通 → 保留
- 否则 → 删除
直觉理解
强 —— 弱 —— 弱 —— 弱 ✔
弱 —— 弱 —— 弱 ✘
👉 这一步让 Canny:
- 抗噪
- 不断边
- 边缘连续
八、参数的工程经验总结
| 参数 | 经验值 |
|---|---|
| σ | 与噪声 / 分辨率相关 |
| High | 控制主结构 |
| Low | 控制连通性 |
| Low : High | 1 : 2 或 1 : 3 |
⚠️ 顺序必须是:
梯度 → NMS → 双阈值 → 滞后连接
九、Canny 的整体逻辑闭环
找变化 → 变成线 → 判断真假 → 保留有意义的连续边缘
十、一句话终极总结
NMS 决定“边缘是不是一条线”
双阈值 + 滞后 决定“这条线值不值得留下来”

浙公网安备 33010602011771号