图像形态学主要获取物体的形状与位置信息。利用具有一定形态的结构元素度量和提取图像中的对应形状,达到对图像分析和识别的目的。操作主要包括腐蚀、膨胀、开运算和闭运算。
像素距离与连通域
图像形态学中,将不与其他区域链接的独立区域称为集合或者连通域,这个集合中的元素就是连通域中的每一个像素,像素之间的距离可以表示两个连通域之间的关系。
图像像素距离
两个像素之间的距离有多种定义。常见的有欧式距离、街区距离和棋盘距离。
欧式距离
指两个像素之间的直线距离,与坐标系中两点间的距离求取方式一致。
d
=
(
x
1
−
x
2
)
2
+
(
y
1
−
y
2
)
2
d=\sqrt{(x_1-x_2)^2+(y_1-y_2)^2}
d=(x1−x2)2+(y1−y2)2
街区距离
指两个像素X差与Y差的和。欧式距离表示的是两点间最近距离,但有时我们并不能沿着直线行走,而是沿着一定的路径行走,如同城市街区一般。
d
=
∣
x
1
−
x
2
∣
+
∣
y
1
−
y
2
∣
d=|x_1-x_2|+|y_1-y_2|
d=∣x1−x2∣+∣y1−y2∣
棋盘距离
又称切比雪夫距离(Chebyshev Distance),指两像素点在横坐标和纵坐标上差的绝对值中的较大者。这相当于棋盘上王从一个格子到另一个格子所需的最少步数。
d
=
m
a
x
(
∣
x
1
−
x
2
∣
,
∣
y
1
−
y
2
∣
)
d=max(|x_1-x_2|,|y_1-y_2|)
d=max(∣x1−x2∣,∣y1−y2∣)
opencv中有计算不同距离的函数。
distanceTransform(src, dst, labels, distanceType, maskSize, labelType);
labels
为二维标签数组,与输入图像有相同的尺寸,数据类型为CV_32S
的单通道数据
distanceType
为方法标志,-1 为自定义距离,1 为街区距离,2 为欧式距离,3 为棋盘距离
maskSize
为距离变换掩码尺寸,可选 DIST_MASK_3
(
3
×
3
3\times3
3×3) 和 DIST_MASK_5
(
5
×
5
5\times5
5×5)
labelType
为标签数组类型,0 表示同一连通区域的零像素及其最近的非零像素点赋予相同的标签,1 表示每个零像素及其最近的非零像素点都有其独特的标签
distanceTransform(src, dst, distanceType, maskSize, dstType);
这个原型不生成labels
数组,占用资源小。
dstType
决定了输出图像的类型,CV_8U
或CV_32F
图像连通域分析
图像的连通域指图像中具有相同像素值且位置相邻的像素组成的区域。为了避免像素值波动的影响,连通域分析处理的一般是二值化后的图像。
像素的邻域定义了其“相邻”关系,常见的有4-邻域(仅考虑上、下、左、右四个方向的像素)和8-邻域(额外包含对角线方向的四个像素)。
邻域分析主要有两遍扫描法和种子填充法。
函数如下:
connectedComponents(image, labels, connectivity, ltype, ccltype);
image
为待标记图像,必须为CV_8U
单通道二值图像
labels
输出的标记图像,其中每个连通域被赋予一个唯一的整数标签。
connectivity
邻域种类,可选4(4-邻域)或8(8-邻域)
ltype
为输出图像数据类型,可为CV_32S
和CV_16U
ccltype
连通域标记算法类型,例如 cv::CCL_DEFAULT
、cv::CCL_WU
或 cv::CCL_GRANA
简化原型:
connectedComponents(image, labels, connectivity=8, ltype=CV_32S);
connectedComponentsWithStats(image, labels, stats, centroids, connectivity, ltype, ccltype);
connectedComponentsWithStats(image, labels, stats, centroids, connectivity=8, ltype=CV_32S);
stats
输出的统计信息矩阵。每一行对应一个连通域的统计数据(背景为第0行),列代表不同的统计属性
centroids
为每个连通域质心的坐标,CV_64F
stats
中包含的信息如下:
cv::CC_STAT_LEFT // 0 连通域外包矩形最左侧像素的x坐标
cv::CC_STAT_TOP // 1 连通域外包矩形最上方像素的y坐标
cv::CC_STAT_WIDTH // 2 连通域外包矩形的水平长度
cv::CC_STAT_HEIGHT // 3 连通域外包矩形的垂直长度
cv::CC_STAT_AREA // 4 连通域的面积(以像素为单位)
// cv::CC_STAT_MAX // 5 统计信息类型的总数,本身不代表具体统计值
腐蚀与膨胀
腐蚀与膨胀是形态学的基础操作,可用于去除图像噪声、分割独立的图像区域、连接邻近的区域等。
腐蚀
腐蚀与卷积相似,需要模板矩阵——结构元素。对于二值图像(通常前景为1或255,背景为0),腐蚀操作会检查结构元素是否能完全被图像中的前景像素区域所覆盖。若能,则结构元素中心(锚点)对应的像素在新图像中保持为前景;否则置为背景。其效果是“收缩”或“细化”图像中的前景区域,去除小的噪点和物体边界的一些像素。
getStructuringElement(shape, ksize, anchor = Point(-1, -1));
shape
为生成的结构元素种类
ksize
为结构元素大小
anchor
为中心点的位置
这个函数可以生成矩形、十字、椭圆结构元素。只有十字结构元素的中心点位置会影响图像腐蚀后的轮廓形状,其他的只影响操作结果的平移量。
cv::MORPH_RECT // 0 矩形结构元素
cv::MORPH_CROSS // 1 十字结构元素
cv::MORPH_ELLIPSE // 2 椭圆结构元素
图像腐蚀函数:
erode(src, dst, kernel, anchor=Point(-1, -1), iterations=1, borderType, borderValue);
kernel
为结构元素
iterations
为腐蚀次数,次数越多效果越明显
borderValue
为使用边界不变外推法时的边界值
此函数执行图像腐蚀。对于多通道图像,每个通道将独立进行腐蚀。在二值图像中,腐蚀会使前景物体“收缩”或“变细”。
膨胀
图像膨胀通常被认为是腐蚀的对偶运算。对于二值图像,如果结构元素的锚点对应于输入图像的某个位置,且结构元素覆盖的区域内至少有一个前景像素与输入图像的前景像素重叠,则输出图像中该锚点对应的像素被置为前景。其效果是“扩张”或“加粗”图像中的前景区域,填充小的空洞或连接断裂部分。
dilate(src, dst, kernel, anchor, iterations, borderType, borderValue);
对于多通道图像,各通道独立膨胀。在二值图像中,膨胀会使前景物体“扩张”或“变粗”。
膨胀只针对非0像素。
运算组合
针对不同的图像处理需求,OpenCV
提供了腐蚀与膨胀运算的不同组合形式,封装在 morphologyEx
函数中。
morphologyEx(src, dst, op, kernel, anshor, iterations, bord
op
为形态学操作类型标志。
cv::MORPH_ERODE // 0 腐蚀
cv::MORPH_DILATE // 1 膨胀
cv::MORPH_OPEN // 2 开运算
cv::MORPH_CLOSE // 3 闭运算
cv::MORPH_GRADIENT // 4 形态学梯度
cv::MORPH_TOPHAT // 5 顶帽运算
cv::MORPH_BLACKHAT // 6 黑帽运算
cv::MORPH_HITMISS // 7 击中击不中变换
开运算
开运算可以去除图像噪声,消除较小连通域,保留较大连通域,同时在两个物体纤细连接处分离,且能在不明显改变较大连通域面积的同时平滑连通域的边界。
开运算先对图像进行腐蚀,随后膨胀,使用相同的结构元素。
O
p
e
n
i
n
g
(
A
,
B
)
=
(
A
⊖
B
)
⊕
B
Opening(A,B)=(A\ominus B)\oplus B
Opening(A,B)=(A⊖B)⊕B
其中
A
A
A是图像,
B
B
B是结构元素,
⊖
\ominus
⊖代表腐蚀,
⊕
\oplus
⊕代表膨胀。
闭运算
闭运算常用于填充前景对象内部的小空洞,连接邻近的对象,以及平滑对象的轮廓(特别是填充轮廓的凹陷部分)。
闭运算先进行膨胀,再进行腐蚀。
C
l
o
s
i
n
g
(
A
,
B
)
=
(
A
⊕
B
)
⊖
B
Closing(A,B)=(A\oplus B)\ominus B
Closing(A,B)=(A⊕B)⊖B
其中
A
A
A是图像,
B
B
B是结构元素,
⊖
\ominus
⊖代表腐蚀,
⊕
\oplus
⊕代表膨胀。
形态学梯度
形态学梯度(cv::MORPH_GRADIENT
)用于突出对象的边缘。标准的形态学梯度是图像膨胀的结果与图像腐蚀的结果之差。梯度分为基本梯度、内部梯度、外部梯度。
基本梯度指图像膨胀后和腐蚀后的差值图像
G
r
a
d
i
e
n
t
(
A
,
B
)
=
(
A
⊕
B
)
−
(
A
⊖
B
)
Gradient(A,B)=(A\oplus B)-(A\ominus B)
Gradient(A,B)=(A⊕B)−(A⊖B)
内部梯度指原图像与腐蚀后图像间的差值
G
r
a
d
i
e
n
t
(
A
,
B
)
=
A
−
(
A
⊖
B
)
Gradient(A,B)=A-(A\ominus B)
Gradient(A,B)=A−(A⊖B)
外部梯度指膨胀后图像与原图像间的差值。
G
r
a
d
i
e
n
t
(
A
,
B
)
=
(
A
⊕
B
)
−
A
Gradient(A,B)=(A\oplus B)-A
Gradient(A,B)=(A⊕B)−A
内部梯度与外部梯度需自己实现。
顶帽运算
顶帽运算(cv::MORPH_TOPHAT
)是原图像与其开运算结果之间的差值。它常用于提取图像中相对于其周围环境更亮的细小区域或斑点,这些区域通常在开运算中被移除。
T
o
p
H
a
t
(
A
,
B
)
=
A
−
O
p
e
n
i
n
g
(
A
,
B
)
TopHat(A,B)=A−Opening(A,B)
TopHat(A,B)=A−Opening(A,B)
黑帽运算
黑帽运算(cv::MORPH_BLACKHAT
)是图像的闭运算结果与原图像之间的差值。它用于提取图像中相对于其周围环境更暗的细小区域或斑点。
B
l
a
c
k
H
a
t
(
A
,
B
)
=
C
l
o
s
i
n
g
(
A
,
B
)
−
A
BlackHat(A,B)=Closing(A,B)−A
BlackHat(A,B)=Closing(A,B)−A
击中击不中变换
击中击不中变换(cv::MORPH_HITMISS
)是一种用于查找特定像素模式的运算。
它使用一个特殊的结构元素,该结构元素不仅定义了需要匹配的前景(“击中”部分,通常标记为1),也定义了必须为背景的区域(“击不中”部分,通常标记为-1),其他部分为“不关心”(标记为0)。
只有当图像中的某个区域与结构元素的前景部分完全匹配,并且与背景部分也完全匹配时,输出图像中对应锚点位置的像素才会被标记。这是一种比简单腐蚀更精确的模式匹配方法,常用于查找角点、孤立点等特定配置。
在使用矩形结构元素时,结果与腐蚀相同。
图像细化
细化指从多像素宽度减少到单位像素宽度的过程,又称“骨架化”或“中轴变换”。图像细化常用于文字识别。图像细化一般要求保证细化后骨架的连通性、对原图像的细节特征有较好保留、线条的端点保留完好、线条交叉点不能发生畸变。主要应用于由线条形状构成的物体。
细化算法分为迭代细化和非迭代细化。迭代细化中,又可分为串行细化和并行细化。
opencv中提供了如下函数:
thinning(src, dst, thinningType=THINNING_ZHANGSUEN);
src
必须为CV_8UC1
thinningType
为细化算法选择标志
0 THINNING_ZHANGSUEN
1 THINNING_GUOHALL 复杂场景效果更好
需确保已链接 opencv_ximgproc
模块,并通过 cv::ximgproc::
命名空间调用