1、预备知识
数学形态学的语言是集合论。
在形态学中集合的反射和平移广泛用来表达基于结构元(SE)的操作:研究一幅图像中感兴趣特性所用的小集合或子图像。
在二值图像中,除了元素是SE的成员的定义之外,还必须指定结构元的原点。
在形态学处理语言中,二值图像A和结构元素B都是定义在二维笛卡尔网格上的集合。当一个结构元素的原点位移到点(x,y)处时,将其记为 B x y B_{x y} Bxy
注意:当使用“结构元包含在集合中”这样的术语时,需明确指出A和B的元素完全重叠。不被包含的集合的边界会被腐蚀。
腐蚀和膨胀是形态学处理的基础,本章中讨论的许多形态学算法都是以这两种原始操作为基础的。
2、腐蚀和膨胀
1、腐蚀
B对A的腐蚀定义为
A
⊖
B
=
{
z
∣
(
B
)
z
⊆
A
}
A \ominus B=\left\{z \mid(B)_{z} \subseteq A\right\}
A⊖B={z∣(B)z⊆A}
B对A的腐蚀是用一个z平移的B包含在A中的所有点z的集合,即如果B的原点位移到(x,y),那么B将完全包含在A中。
腐蚀缩小或细化了二值图像中的物体,可以将腐蚀看成是形态学滤波操作,这种操作将小于结构元的图像细节从图像中滤除了。腐蚀执行线滤波功能。
腐蚀对从一幅图像中去除小且无意义的物体来说是很有用的。
2、膨胀
B对A的膨胀定义为
A
⊕
B
=
{
z
∣
(
B
^
)
z
∩
A
≠
∅
}
A \oplus B=\left\{z \mid(\hat{B})_{z} \cap A \neq \varnothing\right\}
A⊕B={z∣(B^)z∩A=∅}
B对A的膨胀是所有位移z的集合,
B
^
\hat{B}
B^和A至少有一个元素是重叠的。如果B的原点位移到(x,y),那么它与A的交集非空。
膨胀以集合操作为基础,是一种非线性操作。
膨胀在填补分割后物体中的空洞很有用。
3、对偶性
腐蚀和膨胀彼此关于集合求补运算和反射运算是对偶的。
(
A
⊖
B
)
c
=
A
c
⊕
B
^
(
A
⊕
B
)
c
=
A
c
⊖
B
^
\begin{array}{l} (A \ominus B)^{c}=A^{c} \oplus \hat{B} \\ (A \oplus B)^{c}=A^{c} \ominus \hat{B} \end{array}
(A⊖B)c=Ac⊕B^(A⊕B)c=Ac⊖B^
腐蚀和膨胀效果图如下:
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('C:/Users/13121/Desktop/c.png', 0) # 读取灰度图
# 得到一个3x3的十字交叉结构元,实际就是numpy矩阵
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3)) #卷积核
erode_res = cv2.erode(img, kernel) # 腐蚀结果
dilate_res = cv2.dilate(img, kernel) # 膨胀结果
plt.subplot(1,3,1)
plt.imshow(erode_res, cmap=plt.cm.gray)
plt.title("erode")
plt.axis('off')
plt.subplot(1,3,2)
plt.imshow(img, cmap=plt.cm.gray)
plt.title("img")
plt.axis('off')
plt.subplot(1,3,3)
plt.imshow(dilate_res, cmap=plt.cm.gray)
plt.title("dilate")
plt.axis('off')
plt.show()
3、开操作和闭操作
膨胀会扩大一幅图像的组成部分,腐蚀会缩小一幅图像的组成部分。接下来学习的是形态学的另一组操作,开操作和闭操作。
- 开操作会平滑物体的轮廓、断开较窄的狭颈并消除细的突出物;
A ∘ B = ( A ⊖ B ) ⊕ B A \circ B=(A \ominus B) \oplus B A∘B=(A⊖B)⊕B
B对A的开操作即B对A腐蚀,再用B对结果膨胀。
- 闭操作会平滑轮廓的一部分,但会弥合较窄的间断和细长的沟壑,消除小的空洞,填补轮廓线中的断裂。
A ⋅ B = ( A ⊕ B ) ⊖ B A \cdot B=(A \oplus B) \ominus B A⋅B=(A⊕B)⊖B
B对A的闭操作即B对A膨胀,再用B对结果腐蚀。
开操作和闭操作效果图如下:
import cv2
import numpy as np
import matplotlib.pyplot as plt
img1 = cv2.imread('C:/Users/13121/Desktop/h.png', 0) # 读取灰度图
img2 = cv2.imread('C:/Users/13121/Desktop/g.png', 0) # 读取灰度图
# 得到一个5x5的矩形结构元
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
iterations = 50 #迭代次数
open_res = cv2.morphologyEx(img1, cv2.MORPH_OPEN, kernel, iterations)
close_res = cv2.morphologyEx(img2, cv2.MORPH_CLOSE, kernel, iterations)
plt.subplot(2,2,1)
plt.imshow(img, cmap=plt.cm.gray)
plt.title("img1")
plt.axis('off')
plt.subplot(2,2,2)
plt.imshow(open_res, cmap=plt.cm.gray)
plt.title("open")
plt.axis('off')
plt.subplot(2,2,3)
plt.imshow(img2, cmap=plt.cm.gray)
plt.title("img2")
plt.axis('off')
plt.subplot(2,2,4)
plt.imshow(close_res, cmap=plt.cm.gray)
plt.title("close")
plt.axis('off')
plt.show()
4、一些基本的形态学算法
在处理二值图像时,形态学的主要应用之一是提取用于表示和描述形状的图像成分。本节中我们用1表示阴影区域0表示白色。
1、边界提取
即用一个结构元素对原图像进行腐蚀,腐蚀保留的都是物体的内部点,再用原图像减去腐蚀后的图像,留下的就是边界像素。
β
(
A
)
=
A
−
(
A
⊖
B
)
\beta(A)=A-(A \ominus B)
β(A)=A−(A⊖B)
import cv2
import numpy as np
# import matplotlib.pyplot as plt
from matplotlib import pyplot as plt
I = cv2.imread('C:/Users/13121/Desktop/c.png',0)
ret,img = cv2.threshold(I,127,255,cv2.THRESH_BINARY_INV)
kernel = np.ones((3,3),np.uint8)
r=cv2.erode(img,kernel,iterations=1)
#边缘提取
e=img-r
plt.subplot(121)
plt.imshow(img)
plt.title("original")
plt.axis('off')
plt.subplot(122)
plt.imshow(e)
plt.title("after")
plt.axis('off')
plt.show()
2、孔洞填充
X
k
=
(
X
k
−
1
⊕
B
)
∩
A
c
k
=
1
,
2
,
3
,
⋯
X_{k}=\left(X_{k-1} \oplus B\right) \cap A^{c} \quad k=1,2,3, \cdots
Xk=(Xk−1⊕B)∩Ack=1,2,3,⋯
对A图进行孔洞填充,先求出A集的补集,构建X0一幅全黑图像加上孔洞中的一点白作为初始图象,用B对X0进行膨胀,结果膨胀的结果超过了孔洞的大小,于是用之前构造的Ac对其求交集,将其结果限制在孔洞内,然后迭代,直到x{k-1}与xk相同没变化,最后得到X8孔洞的填充图像,最后与原图像求并集,就刚好把空洞填补了。
孔洞填充效果图如下:
3、连通分量的提取
给原图像中的每个连通区分配给一个唯一代表该区域的编号,在输出图像中该连通区内的所有像素的像素值为该区域的编号,我们将这样的输出图像称为标注图像。
4、凸壳
如果连接物体A内的任意两点的直线段都在A的内部,则称A是凸的。
图像二值化后,如果光照不均,物体本身的形状可能会发生缺损,用凸壳进行处理可弥补凹损,算法会找到包含原始形状的最小凸多边形。
5、细化
细化分为两步过程,第一步是正常的腐蚀,但那些被标为可除去的像素点不立即消去,第二步将那些消除后并不破坏连通性的点消除,否则保留。
细化将一个曲线形物体细化为一条单像素宽的线,从而图形化地显示出其拓扑性质。
6、粗化
膨胀也可以在不合并邻近的物体的条件下实现。
可提取图像的补并用细化运算处理背景。实际上当每种腐蚀的变形作用于一幅图像的补时,就会获得一种相应的膨胀型运算。
粗化可在不合并彼此分离的物体的前提下扩大边界。
7、骨架
A的骨架可用腐蚀和开操作来表达。
S
(
A
)
=
⋃
k
=
0
K
S
k
(
A
)
S(A)=\bigcup_{k=0}^{K} S_{k}(A)
S(A)=k=0⋃KSk(A)
S k ( A ) = ( A ⊖ k B ) − ( A ⊖ k B ) ∘ B S_{k}(A)=(A \ominus k B)-(A \ominus k B) \circ B Sk(A)=(A⊖kB)−(A⊖kB)∘B
一个与细化有关的运算是骨架,骨架是所有与物体在两个或更多非邻接边界点处相切的圆心的轨迹,但骨架很少通过在物体内拟合圆来实现。
骨架的实现与细化相似,可采用一个两步有条件腐蚀实现,但是删除像素的规则略有不同。
8、裁剪
通常细化和骨架过程会在所生成的图中留下毛刺,这些毛刺是一些小的分支,每个分支在距分叉处3个像素左右处有一个端点。毛刺是由边界上单像素尺寸的起伏造成的,这些起伏产生了小的分支。可以通过一些列的消除端点的3×3运算除去,然后再重建那些留下的分支。
小结
本章的知识比较连贯,学起来比较有意思…,腐蚀、膨胀、开操作、闭操作在之后的图像分割方面比较有用。