质量声明:原创文章,内容质量问题请评论吐槽。如对您产生干扰,可私信删除。
主要参考:(美)拉斐尔·C.冈萨雷斯. 数字图像处理 第3版[M]. 阮秋琦,译. 北京:电子工业出版社, 2017: 633.
形态学重建
形态学重建涉及两幅图像和一个结构元:
- Marker 图像 :包含变换的起点,将被连续膨胀,直至收敛
- Mask 图像 :用来约束膨胀结果,即 Mask >= Marker
- 结构单元 (Structuring Element,SE):定义连通性
数学迭代式:
M a r k e r = ( M a r k e r ⊕ S E ) ∩ M a s k Marker = (Marker \oplus SE) \cap Mask
M
a
r
k
e
r
=
(
M
a
r
k
e
r
⊕
S
E
)
∩
M
a
s
k
代码示例:
def
imreconstruct
(
marker
,
mask
,
SE
=
np
.
ones
(
[
3
,
3
]
)
)
:
"""
描述:以mask为约束,连续膨胀marker,实现形态学重建,其中mask >= marker
参数:
- marker 标记图像,单通道/三通道图像
- mask 模板图像,与marker同型
- conn 联通性重建结构元,参照matlab::imreconstruct::conn参数,默认为8联通
"""
while
True
:
marker_pre
=
marker
dilation
=
cv
.
dilate
(
marker
,
kernel
=
SE
)
marker
=
np
.
min
(
(
dilation
,
mask
)
,
axis
=
0
)
if
(
marker_pre
==
marker
)
.
all
(
)
:
break
return
marker
孔洞填充
孔洞定义:被前景(白色)连通域包围的封闭的背景(黑色)区域,不限于圆形。如图所示。
原理:
以原图像的补集作为Mask,用来限制膨胀结果;以带有白色边框的黑色图像为初始Marker,用SE对其进行连续膨胀,直至收敛;最后对Marker取补即得到最终图像,与原图相减可得到填充图像。
M a r k e r ( x , y ) = { 255 , ( x , y ) ∈ B o u n d a r y 0 , o t h e r s Marker(x, y) = \left\{\begin{matrix} 255 & , & (x,y) \in Boundary\\ 0 & , & others \end{matrix}\right. M a r k e r ( x , y ) = { 2 5 5 0 , , ( x , y ) ∈ B o u n d a r y o t h e r s
代码示例:
import
numpy
as
np
import
cv2
as
cv
from
matplotlib
import
pyplot
as
plt
img
=
cv
.
imread
(
"text.jpg"
)
# 二值化
imgray
=
cv
.
cvtColor
(
img
,
cv
.
COLOR_BGR2GRAY
)
imgray
[
imgray
<
100
]
=
0
imgray
[
imgray
>=
100
]
=
255
# 原图取补得到MASK图像
mask
=
255
-
imgray
# 构造Marker图像
marker
=
np
.
zeros_like
(
imgray
)
marker
[
0
,
:
]
=
255
marker
[
-
1
,
:
]
=
255
marker
[
:
,
0
]
=
255
marker
[
:
,
-
1
]
=
255
marker_0
=
marker
.
copy
(
)
# 形态学重建
SE
=
cv
.
getStructuringElement
(
shape
=
cv
.
MORPH_CROSS
,
ksize
=
(
3
,
3
)
)
while
True
:
marker_pre
=
marker
dilation
=
cv
.
dilate
(
marker
,
kernel
=
SE
)
marker
=
np
.
min
(
(
dilation
,
mask
)
,
axis
=
0
)
if
(
marker_pre
==
marker
)
.
all
(
)
:
break
dst
=
255
-
marker
filling
=
dst
-
imgray
# 显示
plt
.
figure
(
figsize
=
(
12
,
6
)
)
# width * height
plt
.
subplot
(
2
,
3
,
1
)
,
plt
.
imshow
(
imgray
,
cmap
=
'gray'
)
,
plt
.
title
(
'src'
)
,
plt
.
axis
(
"off"
)
plt
.
subplot
(
2
,
3
,
2
)
,
plt
.
imshow
(
mask
,
cmap
=
'gray'
)
,
plt
.
title
(
'Mask'
)
,
plt
.
axis
(
"off"
)
plt
.
subplot
(
2
,
3
,
3
)
,
plt
.
imshow
(
marker_0
,
cmap
=
'gray'
)
,
plt
.
title
(
'Marker 0'
)
,
plt
.
axis
(
"off"
)
plt
.
subplot
(
2
,
3
,
4
)
,
plt
.
imshow
(
marker
,
cmap
=
'gray'
)
,
plt
.
title
(
'Marker'
)
,
plt
.
axis
(
"off"
)
plt
.
subplot
(
2
,
3
,
5
)
,
plt
.
imshow
(
dst
,
cmap
=
'gray'
)
,
plt
.
title
(
'dst'
)
,
plt
.
axis
(
"off"
)
plt
.
subplot
(
2
,
3
,
6
)
,
plt
.
imshow
(
filling
,
cmap
=
'gray'
)
,
plt
.
title
(
'Holes'
)
,
plt
.
axis
(
"off"
)
plt
.
show
(
)
选用不同尺寸的SE,进行填充对比:ksize=3x3(左),ksize=7x7(右)
由此可见, 如果选择的结构单元过大,膨胀操作会越过边界,膨胀到孔洞中,导致部分孔洞填充失败。就本例来看3x3的SE可以做到准确填充。
并且,对于大小不一的孔洞,3x3的SE同样可以做到准确填充。如图所示:
注: 关于孔洞填充的其他问题,可以参考博文 形态学填充孔洞的几个问题