图像的信息是十分丰富的,而边缘信息往往能表征物体的特征,因此边缘提取在图像处理中是十分重要的。
基于直觉,边缘位置的颜色值(或灰度值)是骤变的,因此为了提取边缘,可以联想到提取变化率大的位置,即对图像求导。
但在计算机中,图像是由离散的像素点组成的,在这里使用的是查分的方式,相邻像素点之间差值就是变化率。
提取图像的边缘信息,可以通过 一阶导数(First-order derivative) 或者 二阶导数(Second-order derivative) 实现。
如下图所示,边缘位于一阶导数的极值处,以及二阶导数的过0点处。
图自https://www.jianshu.com/p/2334bee37de5。
假如:
# 图像灰度值
[5, 5, 4, 3, 2, 1, 0, 0, 0, 6, 0, 0]
# 一阶导
[0, 0, -1, -1, -1, -1, -1, 0, 0, 6, -6, 0, 0]
# 二阶导
[0, 0, -1, 0, 0, 0, 0, 1, 0, 6, -12, 6, 0, 0]
一阶导能产生较粗的边缘(那一块-1
),二阶导对精细部位比较敏感(如灰度值6
对应的-12
),并且能产生双边效应(如-1,0,...,0,-1
)。
一阶导(First-order derivative):
∂ f ∂ x = f ( x + 1 ) − f ( x ) \frac {\partial f}{\partial x} = f(x+1) - f(x) ∂x∂f=f(x+1)−f(x)
若按照一阶导的查分公式,一阶算子的模板为
[
−
1
,
1
]
[-1, 1]
[−1,1],但是偶数大小的模板不利于对离散图像的中心点求值,因此衍生出了Prewitt算子:
P
r
e
w
i
t
t
_
x
=
∣
−
1
0
1
−
1
0
1
−
1
0
1
∣
,
P
r
e
w
i
t
t
_
y
=
∣
−
1
−
1
−
1
0
0
0
1
1
1
∣
Prewitt\_x= \begin{vmatrix} -1 & 0 & 1 \\ -1 & 0 & 1 \\ -1 & 0 & 1 \end{vmatrix}, \ Prewitt\_y= \begin{vmatrix} -1 & -1 & -1 \\ 0 & 0 & 0 \\ 1 & 1 & 1 \end{vmatrix}
Prewitt_x=∣∣∣∣∣∣−1−1−1000111∣∣∣∣∣∣, Prewitt_y=∣∣∣∣∣∣−101−101−101∣∣∣∣∣∣
考虑到同一水平线相邻的像素值与中心点的距离更近,对中心点的影响力也应该更大,故延伸出了Sobel算子:
S
o
b
e
l
_
x
=
∣
−
1
0
1
−
2
0
2
−
1
0
1
∣
,
S
o
b
e
l
_
y
=
∣
−
1
−
2
−
1
0
0
0
1
2
1
∣
Sobel\_x= \begin{vmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{vmatrix}, \ Sobel\_y= \begin{vmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \end{vmatrix}
Sobel_x=∣∣∣∣∣∣−1−2−1000121∣∣∣∣∣∣, Sobel_y=∣∣∣∣∣∣−101−202−101∣∣∣∣∣∣
分别计算x、y方向的偏导Gx、Gy,求绝对值,
G
(
x
,
y
)
=
G
x
+
G
y
G(x, y) = Gx+Gy
G(x,y)=Gx+Gy,最后压缩至
[
0
,
255
]
[0, 255]
[0,255]。
Lena图像初始化与show函数定义:
Prewitt算子
Sobel算子
二阶导(Second-order derivative):
∂ 2 f ∂ x 2 = f ′ ( x + 1 ) − f ′ ( x ) = f ( x + 2 ) − f ( x + 1 ) − f ( x + 1 ) + f ( x ) = f ( x + 1 ) + f ( x − 1 ) − 2 f ( x ) \begin{aligned} \frac {\partial^2 f}{\partial x^2} &= f'(x+1) - f'(x) \\ &=f(x+2)-f(x+1)-f(x+1)+f(x) \\ &=f(x+1)+f(x-1)-2f(x) \end{aligned} ∂x2∂2f=f′(x+1)−f′(x)=f(x+2)−f(x+1)−f(x+1)+f(x)=f(x+1)+f(x−1)−2f(x)
参考图像二阶导的查分公式,可以用Laplacian算子在二维图像进行Sliding Window,算子参考公式:
L
a
p
l
a
c
i
a
n
(
f
)
=
∂
2
f
∂
x
2
+
∂
2
f
∂
y
2
Laplacian(f) = \frac {\partial^2 f}{\partial x^2} + \frac {\partial^2 f}{\partial y^2}
Laplacian(f)=∂x2∂2f+∂y2∂2f
故卷积模板为:
K
e
r
n
e
l
L
a
p
l
a
c
i
a
n
=
∣
0
1
0
1
−
4
1
0
1
0
∣
Kernel _{Laplacian}= \begin{vmatrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0 \end{vmatrix}
KernelLaplacian=∣∣∣∣∣∣0101−41010∣∣∣∣∣∣
若考虑主副对角线的情况:
K
e
r
n
e
l
L
a
p
l
a
c
i
a
n
=
∣
1
1
1
1
−
8
1
1
1
1
∣
Kernel _{Laplacian} = \begin{vmatrix} 1 & 1 & 1 \\ 1 & -8 & 1 \\ 1 & 1 & 1 \end{vmatrix}
KernelLaplacian=∣∣∣∣∣∣1111−81111∣∣∣∣∣∣
Laplacian算子
Canny算法
Canny算法的步骤如下:
- 运用高斯滤波进行图像平滑,目的是去除噪声(这点在使用其他算子时也可以参考);
- 运用Sobel算子计算梯度强度,记录图像的梯度强度和梯度方向;
- 运用非极大值抑制(Non-maximum suppression),抑制同梯度方向非最大的像素值(置0),保留最大值;
- 运用双阈值(Double Thresholding),对图像像素值进行划分。大于上阈值的认为强边界,介于上下阈值的认为弱边界,小于下阈值的肯定不是边界;
- 利用滞后的边界跟踪,和强边界相连的弱边界认为是边界,其他的边界则抑制。
参考文献
简书:数字图像 - 边缘检测原理 - Sobel, Laplace, Canny算子
CSDN:OpenCV—python 边缘检测(Canny)
百度百科:canny算法
OpenCV Document:Canny()
GitHub:canny.app