文章目录
前言
形态学图像处理是一种基于形态学理论的图像处理方法,它通过对图形中的物体形态进行描述和分析,实现图像的处理、分割和特征提取等操作,主要操作包括腐蚀、膨胀、开操作、闭操作等。
9.1 预备知识
1.数学形态学的语言是集合论,用集合来表示图像中对象。
2.一个集合B的反射表示为:
B
^
=
{
w
∣
w
=
−
b
,
b
∈
B
}
\hat{B}=\begin{Bmatrix}w|w=-b,b\in B\end{Bmatrix}
B^={w∣w=−b,b∈B}
3.一个集合B按照点z=(z1,z2)表示平移:
(
B
)
z
=
{
c
∣
c
=
b
+
z
,
b
∈
B
}
(B)_z=\begin{Bmatrix}c|c=b+z,b\in B\end{Bmatrix}
(B)z={c∣c=b+z,b∈B}
4.在形态学中集合的反射和平移广泛用来表达基于结构元(SE)的操作:研究一幅图像中感兴趣特征所用的小集合或子图像。如图
9.2 腐蚀和膨胀
9.2.1 腐蚀
作为
Z
2
Z^2
Z2中的集合A和B,表示为
A
⊖
B
A{\ominus}B
A⊖B的B对A的腐蚀定义为:
A
⊖
B
=
{
z
∣
(
B
)
z
⊆
A
}
A{\ominus}B=\left\{z\mid\left(B\right)_{z}\subseteq A\right\}
A⊖B={z∣(B)z⊆A}
也等价为:
A
⊖
B
=
{
z
∣
(
B
)
z
∩
A
c
=
∅
}
A{\ominus}B=\left\{z\left|\left(B\right)_{z}\cap A^{c}=\emptyset\right\}\right.
A⊖B={z∣(B)z∩Ac=∅}
腐蚀能够对二值图像中的对象进行“收缩”或“细化”,执行滤波的功能,可用来去除图像中某些我们不需要的部分。
9.2.2 膨胀
作为
Z
2
Z^2
Z2中的集合A和B,表示为
A
⊕
B
A\oplus B
A⊕B的B对A的膨胀定义为:
A
⊕
B
=
{
z
∣
[
(
B
^
)
z
∩
A
]
⊆
A
}
A\oplus B=\left\{z\mid[(\hat{B})_{z}\cap A]\subseteq A\right\}
A⊕B={z∣[(B^)z∩A]⊆A}
也等价为:
A
⊕
B
=
{
z
∣
(
B
^
)
z
∩
A
≠
∅
}
A\oplus B=\left\{z\mid\left(\hat{B}\right)_{z}\cap A\neq\emptyset\right\}
A⊕B={z∣(B^)z∩A=∅}
与腐蚀不同,膨胀时腐蚀的逆操作,会增长或粗化二值图像中的物体。
9.2.3 对偶性
腐蚀和膨胀关于集合求补运算和反射运算是对偶的,即: ( A ⊖ B ) c = A c ⊕ B ^ ( A ⊕ B ) c = A c ⊖ B ^ \begin{aligned}(A{\ominus}B)^c&=A^c\oplus\hat{B}\\\\(A\oplus B)^c&=A^c{\ominus}\hat{B}\end{aligned} (A⊖B)c(A⊕B)c=Ac⊕B^=Ac⊖B^
实验:腐蚀
腐蚀函数:dst cv2.erode(src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])。其中,src 表示输入的图像,kernel 表示腐蚀操作的核,dst 表示输出的图像,anchor 表示锚点的位置,` 表示腐蚀的次数,borderType表示边界处理方式,borderValue 表示边界填充的值。
import cv2
import numpy as np
# 读取图像
img = cv2.imread('pic/word_happy_bin.png')
# 定义腐蚀核
kernel = np.ones((5,5), np.uint8)
# 对图像进行腐蚀操作
erosion = cv2.erode(img, kernel, iterations=2)
# 显示原始图像和腐蚀后的图像
cv2.imshow('image', img)
cv2.imshow('erosion', erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
可见腐蚀缩小了一幅图像中的组成部分。
实验:膨胀
膨胀函数:cv2.dilate(img, kernel, iteration)
import cv2
import numpy as np
# 读取图像
img1 = cv2.imread('pic/word_happy_bin.png',0)
# 定义膨胀核
kernel = np.ones((5,5), np.uint8)
# 对图像进行膨胀操作
dilate = cv2.dilate(img1, kernel, iterations=1)
# 显示原始图像和膨胀后的图像
cv2.imshow('image', img1)
cv2.imshow('dilate', dilate)
cv2.waitKey(0)
cv2.destroyAllWindows()
可见膨胀扩大了一幅图像中的组成部分。
9.3 开操作与闭操作
下面要学习到的开操作和闭操作实际上就是上面膨胀和腐蚀的结合操作。
9.3.1 开操作
1.开操作一般用来平滑物体的轮廓、断开较窄的狭颈并消除细的突出物。
2.结构元B对集合A的开操作,定义为:
A
∘
B
=
(
A
⊖
B
)
⊕
B
A\circ B=(A\ominus B)\oplus B
A∘B=(A⊖B)⊕B
开操作先腐蚀再膨胀。
9.3.2 闭操作
1.闭操作也会平滑轮廓的一部分,但与开操作相反,它通常会弥合较窄的间断和细长的沟壑,消除小的孔洞,填补轮廓线中的断裂。
2.结构元B对集合A的开操作,定义为:
A
•
B
=
(
A
⊕
B
)
⊖
B
A•B=(A\oplus B)\ominus B
A•B=(A⊕B)⊖B
闭操作先膨胀再腐蚀。
9.3.2 对偶性
如同腐蚀和膨胀情形那样,开操作与闭操作彼此关于集合求补和反射也是对偶的:
(
A
∙
B
)
c
=
(
A
c
∘
B
^
)
(A{\bullet}B)^{c}=(A^{c}{\circ}\hat{B})
(A∙B)c=(Ac∘B^)
(
A
∘
B
)
c
=
(
A
c
∙
B
^
)
(A{\circ}B)^{c}=(A^{c}{\bullet}\hat{B})
(A∘B)c=(Ac∙B^)
实验:开操作
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
from collections import Counter
def show(img):
if img.ndim == 2:
plt.imshow(img, cmap='gray')
else:
img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
plt.imshow(img)
plt.show()
img = cv.imread('pic/ninety_bin50x50.png', -1)
# 腐蚀 + 膨胀
K = cv.getStructuringElement(cv.MORPH_RECT, (3,3))
img_open = cv.dilate(cv.erode(img, K), K)
img_open2 = cv.morphologyEx(img, cv.MORPH_OPEN, K)
show(np.hstack([img, img_open, img_open2]))
分析:开操作先执行腐蚀操作将图像周围的一些小白色点腐蚀掉,再通过膨胀操作将图像指定区域恢复,开操作平滑轮廓,消除噪声,消除边缘粗糙,断开狭窄间断。
实验:闭操作
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
from collections import Counter
def show(img):
if img.ndim == 2:
plt.imshow(img, cmap='gray')
else:
img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
plt.imshow(img)
plt.show()
img = cv.imread('pic/bulk_bin120x100.png', -1)
K = cv.getStructuringElement(cv.MORPH_RECT, (3,3))
img_close = cv.morphologyEx(img, cv.MORPH_CLOSE, K)
show(np.hstack([img, img_close]))
分析:闭操作先执行膨胀操作消除了黑色的小块,填充闭合区域,再通过腐蚀操作将图像指定区域恢复,闭操作填充细小空洞,消除狭窄间断。
9.4 击中或击不中变换
击中或击不中变换是两种基本形态学操作,是图形检测的一个基本工具,用于精确匹配目标。
A中对B进行的匹配(击中)表示为:
A
⊛
B
=
(
A
⊖
B
1
)
∩
(
A
c
⊖
B
2
)
A\circledast B=(A\ominus B_1)\cap(A^c\ominus B_2)
A⊛B=(A⊖B1)∩(Ac⊖B2)
其中
B
1
∩
B
2
=
∅
,
B
=
B
1
∪
B
2
。
B_1\cap B_2=\varnothing,B=B_1\cup B_2\text{。}
B1∩B2=∅,B=B1∪B2。
B
1
B_1
B1是与物体有关的结构元,
B
2
B_2
B2是与背景有关的结构元。
9.5 一些基本的形态学算法
9.5.1 边界提取
边界提取如字面意思是用来提取二值图像或灰度图像的边界,通过腐蚀操作与差操作来实现,公式如下: β ( A ) = A − ( A ⊖ B ) \beta(A)=A-(A\ominus B) β(A)=A−(A⊖B)
9.5.2 孔洞填充
一个孔洞可被定义为由前景像素相连接的边界所包围的一个背景区域,对孔洞进行填充,先找到一个较大的结构元来对原图像进行膨胀操作,然后将膨胀后的结果与原图像的补集进行交操作,公式如下: X k = ( X k − 1 ⊕ B ) ∩ A c k = 1 , 2 , 3 , ⋯ X_{k}=(X_{k-1}\oplus B)\cap A^{c}\quad k=1,2,3,\cdots Xk=(Xk−1⊕B)∩Ack=1,2,3,⋯
9.5.3 连通分量的提取
一幅图像一般可以由多个连通分量构成,我们对它的所有连通分量进行提取可以表示为:
X
k
=
(
X
k
−
1
⊕
B
)
∩
A
k
=
1
,
2
,
3
,
⋯
X_{k}=(X_{k-1}\oplus B)\cap A\quad k=1,2,3,\cdots
Xk=(Xk−1⊕B)∩Ak=1,2,3,⋯
对比与孔洞填充的公式我们可以发现,只是将
A
C
A^{C}
AC替换为了A,因为这里我们寻找的是前景点,而孔洞填充时候我们寻找的是背景点。
9.5.4 凸壳
如果在集合A内连接任意两个点的直线段都在A的内部,则称集合A是凸形的。任意集合S的凸壳H是包含于S的最小凸集,集合差 H-S 称为S的凸缺。
获得集合A的凸壳公式可以表示为:
X
k
i
=
(
X
k
−
1
⊗
B
i
)
∪
A
,
i
、
k
=
1
,
2
,
3
…
X_k^i=(X_{k-1}\otimes B^i)\cup A,i\text{、}k=1,2,3\ldots
Xki=(Xk−1⊗Bi)∪A,i、k=1,2,3…
其中
X
k
0
=
A
X_k^0=A
Xk0=A。
9.5.5 细化
细化把一个平面区域简化成图的机构形状表示法,将一个图形的骨架提取出来,可用于文字识别等。
结构元B对集合A的细化可以表示为:
A
⊗
B
=
A
−
(
A
⊛
B
)
=
A
∩
(
A
⊛
B
)
c
A\otimes B=A-(A\circledast B)=A\cap(A\circledast B)^{c}
A⊗B=A−(A⊛B)=A∩(A⊛B)c
9.5.6 粗化
粗话是细化的形态学对偶,公式可表示为: A ∙ B = A ⋃ ( A ⊛ B ) A{\bullet}B=A\bigcup(A{\circledast }B) A∙B=A⋃(A⊛B)
9.5.7 骨架
在二值图像的内部任意给定一点,如果以该点为圆心存在一个最大圆盘,其整个盘体都在图像的内部, 且至少有两点与目标边界相切,则该点便是骨架上的点。所有最大圆盘的圆心构成了图像的骨架。
9.5.8 裁剪
由于手写字符自动识别的过程中,骨架经常会带有许多毛刺(寄生分量)的特征,裁剪可用于去除这些毛刺或者截取出图象中一个子区域。
9.5.9 形态学重建
形态学重建涉及两幅图像和一个结构元,一幅图像是标记,它包含变换的起始点,另一副图像是模板,它约束该变换,结构元用来定义连接性。形态学重建的核心是测地膨胀和测地腐蚀这两个概念,通过不断地进行膨胀和腐蚀操作,反复迭代来实现形状或区域的重建。
实验:形态学梯度
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
from collections import Counter
def show(img):
if img.ndim == 2:
plt.imshow(img, cmap='gray')
else:
img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
plt.imshow(img)
plt.show()
img = cv.imread('pic/flower_bin500x500.png', -1)
K = np.ones((3,3), np.uint8)
img_grad1 = cv.morphologyEx(img, cv.MORPH_GRADIENT, K)# 形态学梯度
img_grad2 = cv.subtract(cv.dilate(img, K), img)
show(np.hstack([img, img_grad1, img_grad2]))
分析:形态学梯度实质上为图中膨胀图和腐蚀图之差,第一张为原图,第二张为经过膨胀后的图像减去经过腐蚀后的图像,第三张为经过膨胀后的图像减去原图像,可见这两种方法都可以得到物体的轮廓,对比后两幅图像可知,第二种方法得到的轮廓图像更清晰。
9.6 灰度级形态学
在灰度级形态学中,对灰度图像进行形态学处理,这里是基于灰度值的处理,灰度级形态学中的结构元属于两类:非平坦的和平坦的结构元。
9.6.1 腐蚀和膨胀
当b的远点位于(x,y)处时,用一个平坦的结构元b在(x,y)处对图像f的腐蚀定义为图像f中与b重合区域的最小值,用公式表示为: [ f ⊖ b ] ( x , y ) = min ( s , t ) ∈ b { f ( x + s , y + t ) } [f\ominus b](x,y)=\min_{(s,t)\in b}\{f(x+s,y+t)\} [f⊖b](x,y)=(s,t)∈bmin{f(x+s,y+t)}
类似的平坦结构元b在任何位置(x,y)处对图像f的膨胀定义为图像f中与b重合区域的最小值,用公式表示为: [ f ⊕ b ] ( x , y ) = max ( s , t ) ∈ b { f ( x − s , y − t ) } [f\oplus b](x,y)=\max_{(s,t)\in b}\{f(x-s,y-t)\} [f⊕b](x,y)=(s,t)∈bmax{f(x−s,y−t)}
非平坦结构元具有随定义域而变化的灰度级,非平坦结构元
b
N
b_N
bN对图像f的腐蚀定义为:
[
f
⊖
b
N
]
(
x
,
y
)
=
min
(
s
,
t
)
∈
b
N
{
f
(
x
+
s
,
y
+
t
)
−
b
N
(
s
,
t
)
}
[f\ominus b_N](x,y)=\min_{(s,t)\in b_N}\{f(x+s,y+t)-b_N(s,t)\}
[f⊖bN](x,y)=(s,t)∈bNmin{f(x+s,y+t)−bN(s,t)}
类似的使用非平坦结构元的膨胀定义如下:
[
f
⊕
b
N
]
(
x
,
y
)
=
max
(
s
,
t
)
∈
b
s
{
f
(
x
−
s
,
y
−
t
)
+
b
N
(
s
,
t
)
}
[f\oplus b_{N}](x,y)=\max_{(s,t)\in b_{s}}\{f(x-s,y-t)+b_{N}(s,t)\}
[f⊕bN](x,y)=(s,t)∈bsmax{f(x−s,y−t)+bN(s,t)}
9.6.2 开操作和闭操作
灰度级图像的开操作和闭操作表达式与二值图像对应操作有相同的形式,通常,开操作用于去除较小的明亮细节,而保持灰度级和较大的明亮细节特征相对不变,相反,闭操作削弱了暗特征,亮的细节和背景相对来说未受影响。
9.6.3 灰度级形态学算法
形态学平滑:常常将开操作和闭操作结合起来来实现图像平滑和噪声去除。
形态学梯度:膨胀和腐蚀可与图像相减结合起来得到一幅图像的形态学梯度,用公式表示为:
g
=
(
f
⊕
b
)
−
(
f
⊕
b
)
g=(f\oplus b)-(f\oplus b)
g=(f⊕b)−(f⊕b)
顶帽变换和底帽变换:
灰度级图像f的顶帽变换定义为f减去其开操作:
T
h
a
t
(
f
)
=
f
−
(
f
∘
b
)
T_{\mathrm{hat}}\left(f\right)=f-\left(f\circ b\right)
That(f)=f−(f∘b)
f的底帽变换定义为闭操作减去f:
B
h
a
t
(
f
)
=
(
f
∙
b
)
−
f
B_{\mathrm{hat}}(f)=(f\bullet b)-f
Bhat(f)=(f∙b)−f
顶帽变换用于暗背景上的亮物体,而底帽变换则用于相反的情况。
粒度测定:在图像处理方面,粒度测定是属于判断图像中颗粒的尺寸分布的领域,对于比背景亮且具有规则形状的颗粒,该方法由使用逐渐增大的结构元对图像执行开操作完成。
纹理分割:将一幅图像分为区域的处理称为分割。