【图像处理】-020 形态学操作
图像的形态学(morphology)表示数学形态学的内容,将数学形态学作为工具从图像中提取表达和描绘区域形状的有用图像分量,如边界、骨架和凸壳等。
1 基础知识
数学形态学的语言是集合论。数学形态学中的集合表示图像中的对象。例如,在二值图像中,所有白色像素的集合是该图像的一个完整的形态学描述。在二值图像中,问题中的集合是二维整数空间的元素,在该空间中,集合的每一个元素都是一个多元组(二维向量),这些多元组的坐标是图像中的一个白色或黑色的像素坐标(x,y)。
一个集合
B
B
B反射表示为
B
^
\hat{B}
B^,定义如下:
(1)
B
^
=
{
w
∣
w
=
−
b
,
b
∈
B
}
\hat{B}=\{ w|w=-b,b\in B \} \tag{1}
B^={w∣w=−b,b∈B}(1)
如果
B
B
B描述图像中的像素的集合(二维点),则
B
^
\hat{B}
B^是
B
B
B中
(
x
,
y
)
(x,y)
(x,y)坐标被
(
−
x
,
−
y
)
(-x,-y)
(−x,−y)替代的点的集合。
集合
B
B
B按照点
z
=
(
z
1
,
z
2
)
z=(z_1,z_2)
z=(z1,z2)表示为
(
B
)
z
(B)_z
(B)z的平移定义如下:
(2)
(
B
)
z
=
{
c
∣
c
=
b
+
z
,
b
∈
B
}
(B)_z= \{ c|c=b+z,b \in B \} \tag{2}
(B)z={c∣c=b+z,b∈B}(2)
如果
B
B
B描述图像中物体的像素集合,则
(
B
)
z
(B)_z
(B)z是
B
B
B中
(
x
,
y
)
(x,y)
(x,y)坐标被
(
x
+
z
1
,
y
+
z
2
)
(x+z_1,y+z_2)
(x+z1,y+z2)替代的点的集合。
2 腐蚀和膨胀
2.1 腐蚀
作为
Z
2
Z^2
Z2中的集合
A
A
A和
B
B
B,表示为
A
⊝
B
A\circleddash B
A⊝B的
B
B
B对
A
A
A的腐蚀定义为:
(3)
A
⊝
B
=
{
z
∣
(
B
)
z
⊆
A
}
A\circleddash B=\{ z|(B)_z \subseteq A\} \tag{3}
A⊝B={z∣(B)z⊆A}(3)
该式指出
B
B
B对
A
A
A腐蚀是用
z
z
z平移的
B
B
B包含在
A
A
A中的所有点
z
z
z的集合。集合
B
B
B是一个结构元。因为
B
B
B必须包含在
A
A
A中这一陈述等价于
B
B
B不与背景共享任何公共元素,故可以将腐蚀表达为如下的等价形式:
(4)
A
⊝
B
=
{
z
∣
(
B
)
z
∩
A
c
=
∅
}
A \circleddash B = \{z|(B)_z \cap A^c=\varnothing\} \tag{4}
A⊝B={z∣(B)z∩Ac=∅}(4)
其中,
A
c
A^c
Ac表示
A
A
A的补集,
∅
\varnothing
∅表示空集。
腐蚀缩小或细化了二值图像中的物体。事实上,可以将腐蚀看成是形态学滤波操作,这种操作将小于结构元的图像细节从图像中滤除了。
2.2 膨胀
A
A
A和
B
B
B是
Z
2
Z^2
Z2中的集合,表示为
A
⨁
B
A \bigoplus B
A⨁B的
B
B
B对
A
A
A的膨胀定义为:
(5)
A
⨁
B
=
{
z
∣
(
B
^
)
z
∩
A
≠
∅
}
A\bigoplus B=\{ z|(\hat{B})_z \cap A \neq \varnothing \} \tag{5}
A⨁B={z∣(B^)z∩A̸=∅}(5)
式5以
B
B
B关于它的原点的映像,并且以
z
z
z对映像进行平移为基础的。
B
B
B对
A
A
A的膨胀是所有位移
z
z
z的集合,这样,
B
^
\hat{B}
B^和
A
A
A至少有一个元素是重叠的。等价于:
(6)
A
⨁
B
=
{
z
∣
[
(
B
^
)
z
∩
A
]
⊆
A
}
A\bigoplus B=\{ z|[(\hat{B})_z \cap A] \subseteq A\} \tag{6}
A⨁B={z∣[(B^)z∩A]⊆A}(6)
其中,
B
B
B是结构元,
A
A
A是被膨胀的集合。
膨胀是一种非线性操作,而卷积是一种线性操作。
腐蚀是一种收缩或细化操作,膨胀则会“增长”或“粗化”二值图像中的物体。 这种特殊的方式和粗化的宽度由所用的机构元来控制。
膨胀的最简单的应用之一是桥接裂缝。
3 实现
在OpenCV中,有cv::dilate
、cv::erode
等函数用来分别进行膨胀和腐蚀操作。还有cv::morphologyEx
可以进行所有形态学操作,包括腐蚀、膨胀、开运算、闭运算、顶帽操作、底帽操作等等。这里,我选择使用后者来进行实验。
#include "../Include/baseOps.h"
int main()
{
//OutputDebugString(L"AB");
SetCurrentDirectoryToExePath();
cv::Mat src = cv::imread("../images/72.png");
cv::imshow("原图", src);
cv::Mat bw;
cv::threshold(src, bw, 125, 255, cv::THRESH_BINARY);
cv::imshow("125阈值二值化", bw);
cv::Mat m = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));
cv::Mat dst;
cv::morphologyEx(bw, dst, cv::MORPH_ERODE, m);
cv::imshow("腐蚀", dst);
cv::morphologyEx(bw, dst, cv::MORPH_DILATE, m);
cv::imshow("膨胀", dst);
cv::waitKey(0);
return 0;
}