之前刚接触 Canny 算子的时候,已经理解过一次。最近需要再次用到它,又花了很长的时间去理解。为方便下次理解,做了这次笔记。文中代码是我从 matlab edge函数中 canny_old 部分中粘贴出来的部分代码,只是用来配合理解非极大值抑制的原理,不能直接使用。
Canny 非极大值抑制分成 3 部分:
- 确定像素的梯度方向
- 对像素线性插值,找出极大值点。
- 将像素值大于低阈值的极大值点作为弱边缘
本文中符号表示:
- X :讨论像素
- ix:x 方向梯度值
- iy:y方向梯度值
- direction:梯度方向 1-4
- mag 梯度幅度
1 确定像素梯度方向
如上图所示,X 是需要讨论的像素点,梯度向量的每个四分之一圆被45°线分成两种情况,一种情况是倾向于水平,另一种倾向于竖直。一共 8 个方向,因为我们使用关于中心像素的对称点,所以对于非极大值抑制我们只考虑其中 4 个(1 和 (1) 属于一个方向)
以图中属于方向 1 的区间为例: iy < 0, ix > 0, ix > -iy。
其他也是类似的分法。
这部分 Matlab edge 函数代码是这样的,非常简单明确:
switch direction
case 1
idx = find((iy<=0 & ix>-iy) | (iy>=0 & ix<-iy));
case 2
idx = find((ix>0 & -iy>=ix) | (ix<0 & -iy<=ix));
case 3
idx = find((ix<=0 & ix>iy) | (ix>=0 & ix<iy));
case 4
idx = find((iy<0 & ix<=iy) | (iy>0 & ix>=iy));
end
然后下面的部分我不理解,有知道的大佬望告知一下。
注释部分是:Exclude the exterior pixels(排除外部像素)外部像素是什么意思?
if ~isempty(idx)
v = mod(idx, m);
extIdx = (v == 1 | v == 0 | idx<=m | (idx > (n-1)* m));
idx(extIdx) = [];
end
ixv = ix(idx);
iyv = iy(idx);
gradmag = mag(idx);
2 线性插值
如果梯度极大值不在像素点上,而在他们之间的某一点(亚像素点)。那么为了算出这个点,就需要进行线性插值。
还是以属于方向 1 的区间为例,红色点的梯度值由绿色点和黄色点的梯度值算出。
那么红色点是靠近黄色点还是绿色点?这就需要一个数来表示它于黄色点和绿色点的距离,我们将它命名为权重 d
。
在方向 1 的区间中 d = i y i x d = \frac{iy}{ix} d=