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°
≈ 45° 45°
≈ 90° 90°
≈ 135° 135°

📌 注意:
方向是“选比较方向”,不是“比较数量”


3️⃣ NMS 实际比较的是几个点?

永远只比较 2 个点,即在当前点的梯度方向上选择前后两个点(方向一致才比较,否则不进行比较)。

  • 当前像素 P
  • 沿梯度方向的前后两个邻居

4️⃣ 各方向比较示意

Image

  • 0°:左 / 右
  • 90°:上 / 下
  • 45°:左上 / 右下
  • 135°:左下 / 右上

保留条件:

G(P) ≥ G(neighbor1) 且 G(P) ≥ G(neighbor2)

否则:

G(P) = 0

5️⃣ NMS 的本质理解(非常重要)

NMS = 沿梯度方向的一维峰值检测

  • 梯度方向 = 边缘法线方向

  • 我们只关心:

    当前点是不是“法线方向上的极大值”


六、步骤 4:双阈值检测(Double Threshold)【核心】

1️⃣ 为什么不能用单阈值?

  • 阈值高 → 边缘断裂
  • 阈值低 → 噪声大量出现

👉 单阈值无法兼顾“完整性”和“纯净度”


2️⃣ 双阈值的基本思想

Image

Image

设定两个阈值:

  • 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 决定“边缘是不是一条线”
双阈值 + 滞后 决定“这条线值不值得留下来”

posted @ 2025-12-13 14:10  Ytytyty  阅读(165)  评论(0)    收藏  举报