Canny算子解析
在冈萨雷斯老师的数字图像处理中,有这么一段话:
虽然算法复杂,但本节讨论的(Canny[1968])是迄今为止讨论的边缘检测器中最为优秀的。Canny方法基于三个基本目标:
1。低错误率,所有的边缘都应该被找到,并且没有伪响应。也就是检测的边缘必须尽可能是真实的边缘。
2.边缘点应该被很好的定位。已定位的边缘必须尽可能接近真实边缘。也就是由检测器标记为边缘的点和真实边缘的中心之间的距离应该最小。
3.单一的边缘点响应。对于真实的边缘点,检测器返回一个点,也就是真实边缘周围的局部大数应该是最小的。这意味着仅存在一个单一边缘点的位置,检测器不应该指出多个边缘像素。
但是需要注意的是,由于受到实际情况的影响,以及Canny边缘一些实际的情况的影响,实际上,我们真正能够提取Canny边缘也不一定是准确的。
步骤
1.令
f
(
x
,
y
)
f(x,y)
f(x,y)为输入图像,
G
(
x
,
y
)
G(x,y)
G(x,y)为高斯函数
G
(
x
,
y
)
=
e
−
x
2
+
y
2
2
σ
2
G(x,y)=e^{-\frac{x^2+y^2}{2\sigma^2}}
G(x,y)=e−2σ2x2+y2
用G和f的卷积形成一幅平滑后的图像
f
x
(
x
,
y
)
f_x(x,y)
fx(x,y):
f
x
(
x
,
y
)
=
G
(
x
,
y
)
★
f
(
x
,
y
)
f_x(x,y) = G(x,y) \bigstar f(x,y)
fx(x,y)=G(x,y)★f(x,y)
实际在MATLAB中使用imgaussfilt(f,sigma)即可,但是由于做的ui最好让用户有点交互性,所以我会设计让用户自己输入sigma的值。
2.计算梯度幅值和方向:
M
(
x
,
y
)
=
g
x
2
+
g
y
2
M(x,y) = \sqrt{g_x^2+g_y^2}
M(x,y)=gx2+gy2
和
α
(
x
,
y
)
=
a
r
c
t
a
n
(
g
y
g
x
)
\alpha(x,y) = arctan(\frac{g_y}{g_x})
α(x,y)=arctan(gxgy)
实际上为了效率的提升我们计算的时候我们会采用sobel或者其他模板,我在程序设计时就是用的sobel模板进行卷积,即fspecial函数,以及它的转置。其中
g
x
=
∂
f
x
/
∂
x
g_x = \partial f_x / \partial x
gx=∂fx/∂x,
g
y
=
∂
f
x
/
∂
x
g_y = \partial f_x/ \partial x
gy=∂fx/∂x。然后根据算出的相角进行赋值,可以分为水平边缘、垂直边缘、45
∘
^\circ
∘,-45
∘
^\circ
∘的边缘。角度计算根据第三步中的图进行计算,下图会很明确,根据范围进行赋值。
3.NMS极大值抑制
实际上在本篇文章中,我采用的就是最原始的Canny。在上一步中,你完成了梯度赋值和角度图像的计算,根据角度去寻访,
比如如这幅图像里所说的,如果你是垂直的我就去寻访它上方和下方的位置,如果你在循环中所在像元
x
(
i
,
j
)
x(i,j)
x(i,j)<
x
(
i
+
1
,
j
)
x(i+1,j)
x(i+1,j)或者
x
(
i
−
1
,
j
)
x(i-1,j)
x(i−1,j)中的任何一个,那么我就认定它是一个伪边缘。同理,水平边缘寻访左右两个像元,斜
4
5
∘
45^\circ
45∘和
−
4
5
∘
-45^\circ
−45∘同样去寻访。
4.阈值处理和连接
实际上,我采用的阈值处理方法是一个不是很严谨的方法我采用的是最大值的0.08倍和0.24倍作为低阈值和高阈值,应该算一种经验模型吧。检测完之后再进行形态学连接。
https://www.bilibili.com/video/BV18C4y1a7RY/一个Canny边缘提取的ui
最后放上我做完的ui的演示视频。我感觉我还是可能讲不清楚,毕竟理解的还不是特别完全。
我的UI主要是考虑交互性以及错误的提示。