7. 边缘检测
7.1 Roberts算子
Roberts边缘矩阵是图像矩阵与以下两个卷积核分别做卷积:
R
o
b
e
r
t
s
135
=
[
1
0
0
−
1
]
,
R
o
b
e
r
t
s
45
=
[
0
1
−
1
0
]
\mathbf{Robert}{{\mathbf{s}}_{135}}=\left[ \begin{matrix}1 & 0 \\0 & -1 \\\end{matrix} \right],\mathbf{Robert}{{\mathbf{s}}_{45}}=\left[ \begin{matrix}0 & 1 \\-1 & 0 \\\end{matrix} \right]
Roberts135=[100−1],Roberts45=[0−110]
- R o b e r t s 135 \mathbf{Robert}{{\mathbf{s}}_{135}} Roberts135锚点的位置在卷积核逆时针翻转180°后的第0行第0列;
- R o b e r t s 45 \mathbf{Robert}{{\mathbf{s}}_{45}} Roberts45锚点的位置在卷积核逆时针翻转180°后的第0行第1列。
与Roberts核做卷积,本质上是两个对角方向上的差分。
- 与 R o b e r t s 45 \mathbf{Robert}{{\mathbf{s}}_{45}} Roberts45卷积后的结果取绝对值,反映的是45°方向上的灰度变化率;
- 与 R o b e r t s 135 \mathbf{Robert}{{\mathbf{s}}_{135}} Roberts135卷积后的结果取绝对值,反映的是135°方向上的灰度变化率;
可以对Roberts算子进行改进:
R
o
b
e
r
t
s
x
=
[
1
−
1
]
,
R
o
b
e
r
t
s
y
=
[
1
−
1
]
\mathbf{Robert}{{\mathbf{s}}_{x}}=\left[ \begin{matrix} 1 & -1 \\ \end{matrix} \right],\mathbf{Robert}{{\mathbf{s}}_{y}}=\left[ \begin{matrix} 1 \\ -1 \\ \end{matrix} \right]
Robertsx=[1−1],Robertsy=[1−1]
- R o b e r t s x \mathbf{Robert}{{\mathbf{s}}_{x}} Robertsx锚点的位置在卷积核逆时针翻转180°后的第0行第0列;
- R o b e r t s y \mathbf{Robert}{{\mathbf{s}}_{y}} Robertsy锚点的位置在卷积核逆时针翻转180°后的第0行第0列。
与Roberts核做卷积,本质上是两个对角方向上的差分。
- 与 R o b e r t s x \mathbf{Robert}{{\mathbf{s}}_{x}} Robertsx卷积后的结果取绝对值,反映的是水平方向上的灰度变化率;
- 与 R o b e r t s y \mathbf{Robert}{{\mathbf{s}}_{y}} Robertsy卷积后的结果取绝对值,反映的是垂直方向上的灰度变化率;
在使用由两个或者多个卷积核组成的边缘检测算子时,假设有 𝑛 个卷积核,记 c o v 1 , c o v 2 , ⋯ , c o v n \mathbf{co}{{\mathbf{v}}_{1}},\mathbf{co}{{\mathbf{v}}_{2}},\cdots ,\mathbf{co}{{\mathbf{v}}_{n}} cov1,cov2,⋯,covn为图像分别与各卷积核做卷积后的结果,通常有四种方式来衡量最后输出的边缘强度:
- 取对应位置绝对值的和;
- 取对应位置平方和的开方;
- 取对应位置绝对值的最大值;
- 插值法: ∑ i = 1 n a i ∣ c o v i ∣ \sum\limits_{i=1}^{n}{{{a}_{i}}\left| \mathbf{co}{{\mathbf{v}}_{i}} \right|} i=1∑nai∣covi∣,其中 a i ≥ 0 , ∑ i = 1 n a i = 1 {{a}_{i}}\ge 0,\sum\limits_{i=1}^{n}{{{a}_{i}}=1} ai≥0,i=1∑nai=1。
其中取绝对值的最大值的方式,对边缘的走向有些敏感,而其他几种方式可以获得性能更一致的全方位响应。
取平方和的开方的方式效果一般是最好的,但是同时会更加耗时。
Roberts 边缘检测因为使用了很少的邻域像素来近似边缘强度,因此对图像中的噪声具有高度敏感性。
可以先对图像进行平滑处理,然后进行Roberts边缘检测。
7.2 Prewitt边缘检测
标准的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
]
\mathbf{prewit}{{\mathbf{t}}_{x}}=\left[ \begin{matrix} 1 & 0 & -1 \\ 1 & 0 & -1 \\ 1 & 0 & -1 \\ \end{matrix} \right],\mathbf{prewit}{{\mathbf{t}}_{y}}=\left[ \begin{matrix} 1 & 1 & 1 \\ 0 & 0 & 0 \\ -1 & -1 & -1 \\ \end{matrix} \right]
prewittx=⎣⎡111000−1−1−1⎦⎤,prewitty=⎣⎡10−110−110−1⎦⎤
- 图像与 p r e w i t t x \mathbf{prewit}{{\mathbf{t}}_{x}} prewittx卷积后可以反映图像垂直方向上的边缘;
- 图像与 p r e w i t t y \mathbf{prewit}{{\mathbf{t}}_{y}} prewitty卷积后可以反映图像水平方向上的边缘。
这两个卷积核是可分离的。分离的结果如下:
p
r
e
w
i
t
t
x
=
[
1
1
1
]
★
[
1
0
−
1
]
,
p
r
e
w
i
t
t
y
=
[
1
1
1
]
★
[
1
0
−
1
]
\mathbf{prewit}{{\mathbf{t}}_{x}}=\left[ \begin{matrix} 1 \\ 1 \\ 1 \\ \end{matrix} \right]\bigstar \left[ \begin{matrix} 1 & 0 & -1 \\ \end{matrix} \right],\mathbf{prewit}{{\mathbf{t}}_{y}}=\left[ \begin{matrix} 1 & 1 & 1 \\ \end{matrix} \right]\bigstar \left[ \begin{matrix} 1 \\ 0 \\ -1 \\ \end{matrix} \right]
prewittx=⎣⎡111⎦⎤★[10−1],prewitty=[111]★⎣⎡10−1⎦⎤
从分离的结果来看:
- p r e w i t t x \mathbf{prewit}{{\mathbf{t}}_{x}} prewittx算子实际上先对图像进行垂直方向上的非归一化的均值平滑,然后进行水平方向上的差分;
- p r e w i t t y \mathbf{prewit}{{\mathbf{t}}_{y}} prewitty算子实际上先对图像进行水平方向上的非归一化的均值平滑,然后进行垂直方向上的差分。
由于对图像进行了平滑处理(同一方向相邻三个梯度的加权平均),所以对噪声较多的图像进行Prewitt边缘检测得到的边缘比Roberts要好。
可以对标准的Prewitt算子进行改进:
p
r
e
w
i
t
t
135
=
[
1
1
0
1
0
−
1
0
−
1
−
1
]
,
p
r
e
w
i
t
t
45
=
[
0
1
1
−
1
0
1
−
1
−
1
0
]
\mathbf{prewit}{{\mathbf{t}}_{135}}=\left[ \begin{matrix} 1 & 1 & 0 \\ 1 & 0 & -1 \\ 0 & -1 & -1 \\ \end{matrix} \right],\mathbf{prewit}{{\mathbf{t}}_{45}}=\left[ \begin{matrix} 0 & 1 & 1 \\ -1 & 0 & 1 \\ -1 & -1 & 0 \\ \end{matrix} \right]
prewitt135=⎣⎡11010−10−1−1⎦⎤,prewitt45=⎣⎡0−1−110−1110⎦⎤
以上算子可以反映45°和135°方向上的边缘。但是,这两个卷积核是不可分离的。
7.3 Sobel边缘检测
7.3.1 三阶的Sobel算子
在图像的平滑处理中,高斯平滑的效果往往比均值平滑要好,因此把 Prewitt 算子的非归一化的均值卷积核替换成非归一化的高斯卷积核,就可以构建 3 阶的 Sobel 边缘检测算子。
KaTeX parse error: No such environment: align at position 8: \begin{̲a̲l̲i̲g̲n̲}̲ & \mathbf{so…
7.3.2 高阶的Sobel算子
窗口大小 | 平滑算子(二项式展开式的系数) | 差分算子 |
---|---|---|
2 | 1 1 | 1 -1 |
3 | 1 2 1 | 1 0 -1 |
4 | 1 3 3 1 | 1 1 -1 -1 |
5 | 1 4 6 4 1 | 1 2 0 -2 -1 |
OpenCV函数如下:
void cv::Sobel(cv::InputArray src, cv::OutputArray dst, int ddepth, int dx, int dy, int ksize = 3, double scale = (1.0), double delta = (0.0), int borderType = 4)
src:输入矩阵
dst:输出矩阵,即 src 与 Sobel 核的卷积
ddepth:输出矩阵的数据类型
dx:当 dx ≠ 0 时,src 与差分方向为水平方向上的 Sobel 核卷积
dy:当 dx = 0, dy ≠ 0 时,src 与差分方向为垂直方向上的 Sobel 核卷积
ksize:sobel 核的尺寸,值为 1,3,5,7
scale:比例系数
delta:平移系数
borderType:边界扩充类型
7.4 Scharr算子
s c h a r r x = [ 3 0 − 3 10 0 − 10 3 0 − 3 ] , s c h a r r y = [ 3 10 3 0 0 0 − 3 − 10 − 3 ] \mathbf{scharr}_{x}=\left[ \begin{matrix} 3 & 0 & -3 \\ 10 & 0 & -10 \\ 3 & 0 & -3 \\ \end{matrix} \right],\mathbf{scharr}_{y}=\left[ \begin{matrix} 3 & 10 & 3 \\ 0 & 0 & 0 \\ -3 & -10 & -3 \\ \end{matrix} \right] scharrx=⎣⎡3103000−3−10−3⎦⎤,scharry=⎣⎡30−3100−1030−3⎦⎤
这两个卷积核是不可分离的。同样地,Scharr边缘检测算子也可以扩展到其他方向,比如:
s
c
h
a
r
r
135
=
[
10
3
0
3
0
−
3
0
−
3
−
10
]
,
s
c
h
a
r
r
45
=
[
0
3
10
−
3
0
3
−
10
−
3
0
]
\mathbf{scharr}_{135}=\left[ \begin{matrix} 10 & 3 & 0 \\ 3 & 0 & -3 \\ 0 & -3 & -10 \\ \end{matrix} \right],\mathbf{scharr}_{45}=\left[ \begin{matrix} 0 & 3 & 10 \\ -3 & 0 & 3 \\ -10 & -3 & 0 \\ \end{matrix} \right]
scharr135=⎣⎡103030−30−3−10⎦⎤,scharr45=⎣⎡0−3−1030−31030⎦⎤
OpenCV函数如下:
void cv::Scharr(InputArray src, OutputArray dst, int ddepth, int dx, int dy, double scale = 1, double delta = 0, int borderType = BORDER_DEFAULT)
src:输入矩阵
dst:输出矩阵,即 src 与 Scharr 核的卷积
ddepth:输出矩阵的数据类型
dx:当 dx ≠ 0 时,src 与差分方向为水平方向上的 Scharr 核卷积
dy:当 dx = 0, dy ≠ 0 时,src 与差分方向为垂直方向上的 Scharr 核卷积
ksize:Scharr 核的尺寸,值为 1,3,5,7
scale:比例系数(默认即可)
delta:平移系数(默认即可)
borderType:边界扩充类型
7.5 Kirsch算子
上面所介绍的边缘检测算子均是由两个方向上的卷积核组成的,接下来介绍两种由各个方向上的卷积核组成的边缘检测算子(Kirsch算子和Robinson算子)。
Kirsch算子由以下8个卷积核组成:
k
1
=
[
5
5
5
−
3
0
−
3
−
3
−
3
−
3
]
,
k
2
=
[
−
3
−
3
−
3
−
3
0
−
3
5
5
5
]
,
k
3
=
[
−
3
5
5
−
3
0
5
−
3
−
3
−
3
]
,
k
4
=
[
−
3
−
3
−
3
5
0
−
3
5
5
−
3
]
k
5
=
[
−
3
−
3
5
−
3
0
5
−
3
−
3
5
]
,
k
6
=
[
5
−
3
−
3
5
0
−
3
5
−
3
−
3
]
,
k
7
=
[
−
3
−
3
−
3
−
3
0
5
−
3
5
5
]
,
k
8
=
[
5
5
−
3
5
0
−
3
−
3
−
3
−
3
]
\begin{matrix} {{k}_{1}}=\left[ \begin{matrix} 5 & 5 & 5 \\ -3 & 0 & -3 \\ -3 & -3 & -3 \\ \end{matrix} \right],{{k}_{2}}=\left[ \begin{matrix} -3 & -3 & -3 \\ -3 & 0 & -3 \\ 5 & 5 & 5 \\ \end{matrix} \right],{{k}_{3}}=\left[ \begin{matrix} -3 & 5 & 5 \\ -3 & 0 & 5 \\ -3 & -3 & -3 \\ \end{matrix} \right],{{k}_{4}}=\left[ \begin{matrix} -3 & -3 & -3 \\ 5 & 0 & -3 \\ 5 & 5 & -3 \\ \end{matrix} \right] \\ {{k}_{5}}=\left[ \begin{matrix} -3 & -3 & 5 \\ -3 & 0 & 5 \\ -3 & -3 & 5 \\ \end{matrix} \right],{{k}_{6}}=\left[ \begin{matrix} 5 & -3 & -3 \\ 5 & 0 & -3 \\ 5 & -3 & -3 \\ \end{matrix} \right],{{k}_{7}}=\left[ \begin{matrix} -3 & -3 & -3 \\ -3 & 0 & 5 \\ -3 & 5 & 5 \\ \end{matrix} \right],{{k}_{8}}=\left[ \begin{matrix} 5 & 5 & -3 \\ 5 & 0 & -3 \\ -3 & -3 & -3 \\ \end{matrix} \right] \\ \end{matrix}
k1=⎣⎡5−3−350−35−3−3⎦⎤,k2=⎣⎡−3−35−305−3−35⎦⎤,k3=⎣⎡−3−3−350−355−3⎦⎤,k4=⎣⎡−355−305−3−3−3⎦⎤k5=⎣⎡−3−3−3−30−3555⎦⎤,k6=⎣⎡555−30−3−3−3−3⎦⎤,k7=⎣⎡−3−3−3−305−355⎦⎤,k8=⎣⎡55−350−3−3−3−3⎦⎤
图像与每一个核进行卷积,然后取绝对值作为对应方向上的边缘强度的量化。对 8 个卷积结果取绝对值,然后在对应值位置取最大值作为最后输出的边缘强度。在进行边缘强度的灰度级显示时,将大于 255 的值截断为 255 即可
7.6 Robinson算子
与Kirsch算子类似,Robinson算子也是由以下8个卷积核组成:
r
1
=
[
1
1
1
1
−
2
1
−
1
−
1
−
1
]
,
r
2
=
[
1
1
1
−
1
−
2
1
−
1
−
1
1
]
,
r
3
=
[
−
1
1
1
−
1
−
2
1
−
1
1
1
]
,
r
4
=
[
−
1
−
1
1
−
1
−
2
1
1
1
1
]
r
5
=
[
−
1
−
1
−
1
1
−
2
1
1
1
1
]
,
r
6
=
[
1
−
1
−
1
1
−
2
−
1
1
1
1
]
,
r
7
=
[
1
1
−
1
1
−
2
−
1
1
1
−
1
]
,
r
8
=
[
1
1
1
1
−
2
−
1
1
−
1
−
1
]
\begin{matrix} {{r}_{1}}=\left[ \begin{matrix} 1 & 1 & 1 \\ 1 & -2 & 1 \\ -1 & -1 & -1 \\ \end{matrix} \right],{{r}_{2}}=\left[ \begin{matrix} 1 & 1 & 1 \\ -1 & -2 & 1 \\ -1 & -1 & 1 \\ \end{matrix} \right],{{r}_{3}}=\left[ \begin{matrix} -1 & 1 & 1 \\ -1 & -2 & 1 \\ -1 & 1 & 1 \\ \end{matrix} \right],{{r}_{4}}=\left[ \begin{matrix} -1 & -1 & 1 \\ -1 & -2 & 1 \\ 1 & 1 & 1 \\ \end{matrix} \right] \\ {{r}_{5}}=\left[ \begin{matrix} -1 & -1 & -1 \\ 1 & -2 & 1 \\ 1 & 1 & 1 \\ \end{matrix} \right],{{r}_{6}}=\left[ \begin{matrix} 1 & -1 & -1 \\ 1 & -2 & -1 \\ 1 & 1 & 1 \\ \end{matrix} \right],{{r}_{7}}=\left[ \begin{matrix} 1 & 1 & -1 \\ 1 & -2 & -1 \\ 1 & 1 & -1 \\ \end{matrix} \right],{{r}_{8}}=\left[ \begin{matrix} 1 & 1 & 1 \\ 1 & -2 & -1 \\ 1 & -1 & -1 \\ \end{matrix} \right] \\ \end{matrix}
r1=⎣⎡11−11−2−111−1⎦⎤,r2=⎣⎡1−1−11−2−1111⎦⎤,r3=⎣⎡−1−1−11−21111⎦⎤,r4=⎣⎡−1−11−1−21111⎦⎤r5=⎣⎡−111−1−21−111⎦⎤,r6=⎣⎡111−1−21−1−11⎦⎤,r7=⎣⎡1111−21−1−1−1⎦⎤,r8=⎣⎡1111−2−11−1−1⎦⎤
其边缘检测的过程与Kirsch一致。
7.7 Canny边缘检测
基于卷积运算的边缘检测算法,比如 Sobel、Prewitt 等,有如下两个缺点:
- 没有充分利用边缘的梯度方向。
- 最后输出的边缘二值图,只是简单地利用阈值进行处理,显然如果阈值过大,则会损失很多边缘信息;如果阈值过小,则会有很多噪声。
而 Canny 边缘检测基于这两点做了改进,提出了:
- 基于边缘梯度方向的非极大值抑制。
- 双阈值的滞后阈值处理。
7.7.1 算法原理
略,具体见书P248。
7.7.2 OpenCV函数
void cv::Canny( InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize = 3, bool L2gradient = false );
image:输入图像
edges:输出图像
threshold1:低阈值
threshold2:高阈值
apertureSize:使用的 Sobel 核的窗口大小,默认是 3 × 3,也可以尝试 5 × 5 或 7 × 7 等
L2gradient:计算边缘强度时使用的方式,true 代表使用的是平方和开方的方式,false 代表使用的是绝对值和的方式。
7.8 Laplacian算子
对二维连续函数
f
(
x
,
y
)
f(x,y)
f(x,y)求梯度如下:
KaTeX parse error: No such environment: align at position 8: \begin{̲a̲l̲i̲g̲n̲}̲ & {{\nabla }…
将其推广到离散的二维数组(矩阵),即矩阵的拉普拉斯变换是矩阵与拉普拉斯核(以下两种表示都可以,只差一个负号)的卷积:
l
0
=
[
0
−
1
0
−
1
4
−
1
0
−
1
0
]
,
l
0
−
=
[
0
1
0
1
−
4
1
0
1
0
]
{{l}_{0}}=\left[ \begin{matrix} 0 & -1 & 0 \\ -1 & 4 & -1 \\ 0 & -1 & 0 \\ \end{matrix} \right],{{l}_{{{0}^{-}}}}=\left[ \begin{matrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0 \\ \end{matrix} \right]
l0=⎣⎡0−10−14−10−10⎦⎤,l0−=⎣⎡0101−41010⎦⎤
图像矩阵与拉普拉斯核的卷积本质上是计算任意位置的值与其在水平方向和垂直方向上四个相邻点平均值之间的差值。
此外,Laplacian算子还有一些常用的形式:
l
1
=
[
−
1
−
1
−
1
−
1
8
−
1
−
1
−
1
−
1
]
,
l
2
=
[
2
−
1
2
−
1
−
4
−
1
2
−
1
2
]
,
l
3
=
[
0
2
0
2
−
8
2
0
2
0
]
,
l
4
=
[
2
0
2
0
−
8
0
2
0
2
]
{{l}_{1}}=\left[ \begin{matrix} -1 & -1 & -1 \\ -1 & 8 & -1 \\ -1 & -1 & -1 \\ \end{matrix} \right],{{l}_{2}}=\left[ \begin{matrix} 2 & -1 & 2 \\ -1 & -4 & -1 \\ 2 & -1 & 2 \\ \end{matrix} \right],{{l}_{3}}=\left[ \begin{matrix} 0 & 2 & 0 \\ 2 & -8 & 2 \\ 0 & 2 & 0 \\ \end{matrix} \right],{{l}_{4}}=\left[ \begin{matrix} 2 & 0 & 2 \\ 0 & -8 & 0 \\ 2 & 0 & 2 \\ \end{matrix} \right]
l1=⎣⎡−1−1−1−18−1−1−1−1⎦⎤,l2=⎣⎡2−12−1−4−12−12⎦⎤,l3=⎣⎡0202−82020⎦⎤,l4=⎣⎡2020−80202⎦⎤
拉普拉斯核内所有值的和必须等于 0,这样就使得在恒等灰度值区域不会产生错误的边缘,而且上述几种形式的拉普拉斯算子均是不可分离的。
-
Laplacian算子的缺点:
- 没有对图像进行了平滑处理,所以它会对噪声产生较大的响应,误将噪声作为边缘;
- 无法像Sobel 和 Prewitt 算子那样单独得到水平方向、垂直方向或者其他固定方向上的边缘。
-
Laplacian算子的优点:
- 拉普拉斯算子的优点是它只有一个卷积核,所以其计算成本比其他算子要低。
OpenCV函数如下:
void cv::Laplacian(InputArray src, OutputArray dst, int ddepth, int ksize = 1, double scale = 1, double delta = 0, int borderType = BORDER_DEFAULT)
src:输入矩阵
dst:输出矩阵
ddepth:输出矩阵的数据类型(位深)
ksize:拉普拉斯核的类型(必须是正奇数)
ksize = 1:采用 l 0 − {l}_{{{0}^{-}}} l0−形式的拉普拉斯核
ksize = 3:采用 l 4 {l}_{4} l4形式的拉普拉斯核
scale:比例系数(默认即可)
delta:平移系数(默认即可)
borderType:边界扩充类型
7.9 高斯拉普拉斯(LoG)边缘检测
背景:Laplacian边缘检测算子没有对图像做平滑处理,会对噪声产生明显的响应。所以在用拉普拉斯核进行边缘检测时,首先要对图像进行高斯平滑处理,然后再与拉普拉斯核进行卷积运算。
这里进行了两次卷积运算。而高斯拉普拉斯边缘检测算法只用进行一次卷积运算。
基本原理就是对二维高斯函数 g a u s s ( x , y , σ ) gauss(x,y,\sigma) gauss(x,y,σ)求梯度(具体略)。
7.10 高斯差分(DoG)边缘检测
略
7.11 Marr-Hildreth边缘检测
高斯差分和高斯拉普拉斯是 Marr-Hildreth 边缘检测的基底。
对于高斯差分和高斯拉普拉斯边缘检测,最后一步只是简单地进行阈值化处理,显然所得到的边缘很粗略,不够精准。
Marr-Hildreth 边缘检测可以简单地理解为对高斯差分和高斯拉普拉斯检测到的边缘的细化(细节略),就像 Canny 对 Sobel、Prewitt 检测到的边缘的细化一样。