说明
在此篇文章中,请把思维转换到矩阵的角度来,图像是矩阵,结构元也是矩阵,在此,我们约定俗成的是,结构元(SE)的中心是矩阵的正中心。
又如一个集合 B 按照点
z
=
(
z
1
,
z
2
)
z = (z_1, z_2)
z=(z1,z2) 表示
(
B
)
z
(B)_z
(B)z 的平移定义如下:
(
B
)
z
=
{
c
∣
c
=
b
+
z
,
b
∈
B
}
(B)_z = \{c|c = b+z,b ∈ B\}
(B)z={c∣c=b+z,b∈B}
这个
(
B
)
z
(B)_z
(B)z实际上就是一个走路的卷积模板,在下面腐蚀和膨胀的定义式中有用到,但实际上,看公式很容易懵!
上面这个公式实际上只是个矩阵的平移变换而已!
结构元
设有两幅图像
A
A
A 和
B
B
B,若
A
A
A 表示被处理的图像,而
B
B
B 是用来处理
A
A
A,则称
B
B
B 为一个结构元。
结构元一般表示为
0
0
0 和
1
1
1 构成的结构元数组。 可以是任意形状,但通常是对称的,结构元原点是区域的中心。
上面是冈萨雷斯老师的书中对结构元的说明,那么简单点,说人话。
例如,我们下面有一个小色块(矩阵),你也可以认为是卷积中的模板, 同时它也是一个三行一列的值都为
1
1
1 的矩阵。
那么它的中心就是中间那块方块(第二行的
1
1
1 值),让中心一直走过要被操作的矩阵(例如腐蚀、膨胀)的矩阵。
腐蚀
腐蚀是一种使图像缩小的方法,作为
Z
2
Z^2
Z2 中的集合,
A
A
A 和
B
B
B,表示为
A
⊖
B
A \ominus B
A⊖B,
B
B
B 对
A
A
A的腐蚀为
A
⊖
B
=
{
z
∣
(
B
)
z
∩
A
c
=
∅
}
A \ominus B=\{z|(B)_z \cap A^c = \varnothing \}
A⊖B={z∣(B)z∩Ac=∅}
就是
B
B
B 结构元平移之后属于
A
A
A 的部分。
乍一眼看过去可能不大理解,毕竟是集合论里的东西,其实就是让
B
B
B 做类似卷积一样的事情,前提是我们默认已经对
A
A
A 图像做了padding,即扩边的操作(且边缘填充值为全部为
0
0
0 ,否则你在MATLAB中得到的结果会和这里不一样,冈萨雷斯老师书中默认填充为
0
0
0 ),然后开始寻访,
例如:
A
A
A 是一个
6
×
6
6 \times 6
6×6 的矩阵,白色部分是背景,它的值为
0
0
0,绿色部分是有值的部分,值为
1
1
1,
可能看了图还是不大理解,那么
我们用MATLAB代码来说明这一问题。
A =[0,1,0,0,0,0;
0,1,0,0,0,0;
0,1,0,0,0,0;
0,0,1,1,0,0;
0,0,1,1,0,0;
0,0,1,1,0,0]; %A矩阵,要被操作的矩阵
B = ones(1,3); %B结构元,可以当作模板理解
这就是我们要操作的矩阵和结构元,让B的第2行去走整个
A
A
A 矩阵,即整个
3
×
1
3 \times 1
3×1的矩阵的第二行,从
A
A
A第一行一列开始走,但是出现了问题,SE的第一行凸了出去,所以我们需要padding,那么开始padding。padarray的具体例子请参考doc!。
c = padarray(A,[1,1],'both') %具体用法可以doc padarray
好了,然后就可以调用imerode的函数了。
D = imerode(C,B) %腐蚀后矩阵
real_corrode = D(2:end-1,2:end-1) %实际腐蚀后的矩阵
那么就来对比一下结果。
用玩俄罗斯方块的感觉去做腐蚀,我们定义结构元的中心是“构”字,然后用它开始去扫整个方块。
第一次,“结构元”的“构”字与“start” 所在的上下邻域内进行比较
第二次,“结构元”这个俄罗斯方块移动。
某一次,“n”和“结构元”完全一致了,那么保留下这个斑块。
就经过
M
×
N
M \times N
M×N (矩阵的大小)次操作之后,找到符合的点,最后取出扩边之后2:end-1,2:end-1 的原始矩阵,得到腐蚀后的结果,在最上面有了结果,但是消除方块要在最后消除,否则其实你会出现第
3
3
3 行
2
2
2 列这个也会被消除。
可以这样理解,腐蚀的要求非常高,需要做到一个击中变换,只有SE的结构与矩阵某点的SE形状的邻域完全重合,这个点才不会被擦掉(值不会变成
0
0
0 )。
注:这里的击中变换实际上就是结构元完全和经过的点一致,可以理解成俄罗斯分方块能被完美的嵌入。
膨胀
使图像扩大,如用于桥接文字裂缝。若
A
A
A 和
B
B
B 是
Z
2
Z^2
Z2 中的集合,表示为
A
⊕
B
A \oplus B
A⊕B 对
A
A
A 的膨胀定义为
A
⊕
B
=
{
z
∣
[
(
B
)
^
z
∩
A
]
⊆
A
}
A\oplus B=\{z|[\hat{(B)}_z \cap A] \subseteq A \}
A⊕B={z∣[(B)^z∩A]⊆A}
看集合论估计还是看不懂,还是举例子然后看图说话吧。由于上面腐蚀讲的过程比较细了,那么我就直接贴图和代码了。
在这里,可以这样对比着看,有助于把图的思维转换为矩阵的思维!
膨胀和腐蚀同样的例子,只不过,只要结构元中心邻边有一个色块和旁边有交集,那么结构元中心扫过的中心点就被留下或者说是被“涂色”。
A = [0,0,0,0,0,0;
0,1,0,0,0,0;
0,1,0,0,0,0;
0,0,0,0,0,0;
0,0,1,1,0,0;
0,0,0,0,0,0] %A矩阵,要被操作的矩阵
B = ones(3,3) %B结构元,可以当作模板理解
C = padarray(A,[1,1],'both'); %扩充边缘
D = imdilate(C,B); %膨胀后矩阵
after_inflaction = D(2:end-1,2:end-1) %实际膨胀后的矩阵
可以这样理解,膨胀的要求非常低,需要做到一个符合变换,只有SE的结构与矩阵某点的SE形状的邻域有一个值相重合了,这个点就会被填充上去了。
注:这里的符合变换就是只要结构元中心或者中心的邻域内有一个点和要扫过的地方有交集,那么就是符合。
注意
腐蚀、膨胀看起来和卷积非常的像,但实际上他们是非线形的操作,而我们接触到的卷积是线性操作。
总结
总结,其实腐蚀、膨胀、和击中和不击中变换是整个形态学处理的核心,在前期学理论的时候用的是二值图像,而实际操作的时候我们处理的是灰度图像,因为灰度图像的应用空间更广,更实际,后续的开、闭操作,形态学的应用都是以腐蚀、膨胀作为基础,如果想不通集合理论,可以考虑用我的这种方式来思考腐蚀和膨胀等等一系列操作,我们实际中车牌识别、裁剪等等都需要形态学的知识,但是形态学用集合论来讲晦涩难懂。