
目录
[四、最关键:为什么这样能 "细化"?](#四、最关键:为什么这样能 “细化”?)
一、原理
边缘细化 = 非极大值抑制(NMS) 只保留 "梯度方向上" 最亮的那个点,其余全部删掉 → 边缘自动变细到 1 像素宽。
二、原因
原始边缘是粗的、模糊的 ,因为梯度在一片区域都很大。我们只想要一条细线,所以:
沿着梯度方向,只留最大的那个点,其他全部抑制为 0。
这就是边缘瘦身(Thinning)。
三、完整步骤逻辑
步骤 1:根据梯度方向 → 选出 2 个邻居 a、b
梯度方向决定你比哪两个点:
1. 水平梯度(左右变化)→ 边缘垂直
→ 比较 左、右
比较 左、右
a
x
b
2. 垂直梯度(上下变化)→ 边缘水平
→ 比较 上、下
a x b
3. 45° 梯度(↗)
→ 比较 左上 ↔ 右下
a
x
b
4. 135° 梯度(↖)
→ 比较 右上 ↔ 左下
b
x
a
步骤 2:三数取最大
IF max( a, x, b ) == x
输出 x
ELSE
输出 0
只有中心是局部最大 → 保留 否则 → 删掉(置 0)
四、最关键:为什么这样能 "细化"?
因为:
- 真实边缘只有一条线
- 这条线上的点,一定是梯度方向上最大的点
- 旁边的点,幅值一定更小 → 被抑制
结果:粗边缘 → 自动变成 1 像素宽细线。
五、硬件为什么超级友好?
硬件不需要除法、不需要三角函数、不需要浮点
只需要三样东西:
- 梯度方向(4 个方向之一)
- 多路选择器(MUX)
- 比较器(MAX 选择)
硬件流程
- 根据梯度方向(0/45/90/135)→ MUX 直接选出 a 和 b
- 输入 3 个数:a、x、b
- 比较器输出最大值
- 如果最大值 = x → 保留,否则 → 0
完全组合逻辑,0 时钟周期,超高速!
六、伪代码
cpp
// 输入
gradient_dir // 0=水平,1=垂直,2=45°,3=135°
mag // 当前像素幅值
neighbor[8] // 8 邻域幅值
// 步骤1:按方向选 a b
if gradient_dir == 水平:
a = neighbor[上]
b = neighbor[下]
elif gradient_dir == 垂直:
a = neighbor[左]
b = neighbor[右]
elif gradient_dir == 45°:
a = neighbor[左上]
b = neighbor[右下]
else:
a = neighbor[右上]
b = neighbor[左下]
// 步骤2:非极大值抑制
max_val = max(a, mag, b)
if max_val == mag:
out = mag
else:
out = 0