空间域图像增强:OpenCV实现更多一阶导数图像边缘检测算子
0.综述
图像的一阶导数算子除了Sobel
边缘检测算子以外,常见的还有Roberts
边缘检测算子与Prewitt
边缘检测算子。尽管OpenCV
中没有这两个算子直接调用的API,我们可以通过自定义滤波器来自行创建Robert
算子和Prewitt
算子来实现图像的梯度边缘检测。
关于Sobel
算子和图像梯度的内容可以参见下面这篇博客:
OpenCV
自定义滤波器则可以参见下面这篇博客:
1.Roberts边缘检测算子原理分析
任意一对相互垂直方向上的差分可以看成是梯度的近似求解,Roberts
边缘检测算子就是基于该原理,用对角线上相邻像素之差来代替梯度,从而寻找图像中边缘。所以Roberts
边缘检测算子是一个交叉算子,其在点
(
i
,
j
)
(i,j)
(i,j)处的梯度幅值表达式为:
G
(
i
,
j
)
=
∣
f
(
i
,
j
)
−
f
(
i
+
1
,
j
+
1
)
∣
+
∣
f
(
i
+
1
,
j
)
−
f
(
i
,
j
+
1
)
∣
(1)
G(i,j)=|f(i,j)-f(i+1,j+1)|+|f(i+1,j)-f(i,j+1)|\tag{1}
G(i,j)=∣f(i,j)−f(i+1,j+1)∣+∣f(i+1,j)−f(i,j+1)∣(1)
其中:
G
x
=
f
(
i
,
j
)
−
f
(
i
+
1
,
j
+
1
)
G_x=f(i,j)-f(i+1,j+1)
Gx=f(i,j)−f(i+1,j+1)
G
y
=
f
(
i
+
1
,
j
)
−
f
(
i
,
j
+
1
)
G_y=f(i+1,j)-f(i,j+1)
Gy=f(i+1,j)−f(i,j+1)
所以等式
(
1
)
(1)
(1)可以简化为:
G
(
i
,
j
)
=
∣
G
x
∣
+
∣
G
y
∣
G(i,j)=|G_x|+|G_y|
G(i,j)=∣Gx∣+∣Gy∣
G
x
,
G
y
G_x,G_y
Gx,Gy的对于2x2大小卷积核分别为:
H
x
=
[
1
0
0
−
1
]
H_x= \left[ \begin{matrix} 1 &0 \\ 0& -1 \end{matrix} \right]
Hx=[100−1]
H
y
=
[
0
−
1
1
0
]
H_y= \left[ \begin{matrix} 0 &-1 \\ 1& 0 \end{matrix} \right]
Hy=[01−10]
由于Roberts
边缘检测算子是利用图像的两个对角线方向的相邻像素之差进行梯度幅值的检测,所以求得的是在差分点
(
i
+
1
/
2
,
j
+
1
/
2
)
(i+1/2,j+ 1/2)
(i+1/2,j+1/2)处梯度幅值的近似值,而不是所预期的点
(
i
,
j
)
(i,j)
(i,j)处的近似值,为了避免引起混淆,通常采用3X3邻域计算梯度值。
利用Roberts
边缘检测算子进行边缘检测的方法是:分别利用上述两个模板对图像进行逐像素卷积,将2个卷积结果值相加,然后判别该相加结果是否大于或等于某个阈值,如果满足条件,则将其作为结果图像中对应于模板
(
i
,
j
)
(i,j)
(i,j)位置的像素值;如果不满足条件,则给结果图像中对应于模板
(
i
,
j
)
(i,j)
(i,j)位置的像素赋0值。
由于Roberts
算子模板窗口较小,平滑噪声的作用小,且对噪声较为敏感。该算法仅采用了对角线上相邻像素之差进行梯度幅度检测,并未考虑水平相邻像素和垂直相邻像素的情况,无法消除局部噪声干扰,也会丢失灰度值变化缓慢的局部边缘,从而导致目标的边缘轮廓不连续。
2.Prewitt边缘检测算子原理分析
Prewitt
边缘检测算子在x方向和y方向的梯度幅值形式与Sobel
算子的形式完全相同,只是它的系数均为1。该算子对应的两个方向的3x3卷积核分别为:
H
x
=
[
−
1
0
1
−
1
0
1
−
1
0
1
]
H_x= \left[ \begin{matrix} -1 &0&1 \\ -1 &0&1 \\ -1 &0&1 \\ \end{matrix} \right]
Hx=⎣⎡−1−1−1000111⎦⎤
H
y
=
[
1
1
1
0
0
0
−
1
−
1
−
1
]
H_y= \left[ \begin{matrix} 1&1&1\\ 0&0&0\\ -1&-1&-1\\ \end{matrix} \right]
Hy=⎣⎡10−110−110−1⎦⎤
Prewitt
边缘检测算子的计算比Sobel
算子更为简单,但是在噪声方面Sobel
算子更胜一筹。从总体上来说,梯度算子对噪声都有一定的敏感性,所以比较适用于图像边缘灰度值比较尖锐,并且图像噪声比较小的情况下应用。
3.OpenCV自定义滤波器实现Roberts算子与Prewitt算子
首先定义两个算子的卷积核:
Mat roberts_x = (Mat_<int>(2, 2) << 1, 0, 0, -1);
Mat roberts_y = (Mat_<int>(2, 2) << 0, -1, 1, 0);
Mat pre_kx = (Mat_<char>(3, 3) << -1, 0, 1, -1, 0, 1, -1, 0, 1);
Mat pre_ky = (Mat_<char>(3, 3) << 1, 1, 1, 0, 0, 0, -1, -1, -1);
然后使用filter2D
函数进行卷积计算:
Mat rob_x, rob_y, pre_x, pre_y;
filter2D(input, rob_x, CV_16S, roberts_x);
filter2D(input, rob_y, CV_16S, roberts_y);
convertScaleAbs(rob_x, rob_x);
convertScaleAbs(rob_y, rob_y);
filter2D(input, pre_x, CV_32F, pre_kx);
filter2D(input, pre_y, CV_32F, pre_ky);
convertScaleAbs(pre_x, pre_x);
convertScaleAbs(pre_y, pre_y);
最后显示出结果:
imshow("rob_x", rob_x);
imshow("rob_y", rob_y);
imshow("pre_x", pre_x);
imshow("pre_y", pre_y);
最终结果如下:
通过上面的结果可以看出,垂直算子对垂直方向的边缘梯度具有较强的响应,而水平算子对水平方向上的边缘梯度具有较强的响应。在这三种边缘检测算法中,Roberts
算子的检测结果最精细,Prewitt
算子比Sobel
算子稍精细一些。