前言
二值图像中一类主要处理是对提取的目标图形进行形态分析。形态学处理中最基本的是腐蚀和膨胀。
腐蚀和膨胀是两个互为对偶的运算。腐蚀的作用是将目标图像收缩,而膨胀是将图像扩大。
结构元素是指具有某种确定形状的基本结构元素,例如,一定大小的矩形、圆形等。结构元素具有原点。如下图所示:
这就是一个矩形的结构元素(四个 1 构成矩形),标有颜色的位置就是结构元素的原点。
这是一个三角形的结构元素(三个 1 构成三角形),标有颜色的位置就是结构元素的原点。
一、腐蚀
1.概念
腐蚀是一种消除边界点,使边界向内部收缩的过程。可以用来消除小且无意义的目标物。如果两目标物间有细小的连通,可以选取足够大的结构元素,将细小连通腐蚀掉。
2.算法的具体步骤
- 构建结构元素
- 扫描原图,找到第一个像素值为1(因为是二值图,非0即1)的点。
- 将预先设定好形状以及原点位置的结构元素的原点移动到该点
- 判断该结构元素覆盖范围内的图像的像素值是否全部为1,如果是,则腐蚀后图像相同位置上的像素值为1,如果至少有一个像素的值为0,则腐蚀后图像的相同位置上的像素值为0
- 对原图中所有像素值为1的点重复进行步骤3和步骤4
3.举例
设原图像
f
f
f如下图所示:
结构元素选择三角形的结构元素,结构元素原点在左上角,如下图所示:
按照算法步骤,将结构元素的原点移动到第一个像素值为1的点,如下图所示:
可以清楚的看到,结构元素覆盖范围内的像素值全为1。所以腐蚀后的图像在第一行第二列的像素值
g
(
1
,
2
)
=
1
g(1,2)=1
g(1,2)=1。
接下来我们寻找下一个像素值为1的点,发现在该点是边缘点。此时的结构元素的原点移动到该点,会出现边界溢出的现象,所有我们对此像素不做处理(也就是说要确保结构元素的覆盖范围在原图内)。
下一个像素值为1的像素点位于第二行,第二列,将结构元素的原点移动到该点。如下图所示:
可以看到,结构元素覆盖范围内的像素值有两个1,一个0。所以腐蚀后的图像在第二行、第二列的像素值
g
(
2
,
2
)
=
0
g(2,2)=0
g(2,2)=0。
以此类推,对所有像素值为1的像素点重复上述操作。便可得到腐蚀后的图像
g
g
g,如下图所示:
4.python代码
二、膨胀
1.概念
膨胀是将目标区域接触的背景点合并到该目标物中,使目标边界向外扩张的处理。膨胀可以用来填补目标区域存在的某些空洞,也可以用来消除包含在目标区域中的小颗粒噪声。膨胀处理是腐蚀处理的对偶。
2.算法步骤
- 将预先设定好形状以及原点位置的结构元素移动到图像中可包容(可包容的意思是说:结构元素的覆盖范围必须完全落在图像内)的所有像素点
- 判断该结构元素覆盖范围内的像素值是否存在至少一个为1的点,如果存在,则膨胀后图像中与结构元素原点相同位置的像素值为1,如果该覆盖范围内所有的像素值为0,则膨胀后图像相同位置上的像素值为0
- 对原图中的所有像素重复进行步骤2
3.举例
设原图像
f
f
f如下图所示:
三角形的结构元素如下图所示,带有颜色的位置为结构元素的原点:
第一步:将结构元素的原点移动到图像中的第一个像素点,如下图所示:
结构元素覆盖的范围内有两个0,一个1,所以膨胀后的图像在第一行,第一列位置处的像素值
g
(
1
,
1
)
=
1
g(1,1)=1
g(1,1)=1。
依次遍历原图中的每个像素点(结构元素无法全部落在原图内的像素点除外)。
当遍历到
f
(
3
,
1
)
f(3,1)
f(3,1)点时,如下图所示:
此时结构元素覆盖范围内有三个0,0个1,所以膨胀后的图像在第三行、第三列位置处的像素值
g
(
3
,
1
)
=
0
g(3,1)=0
g(3,1)=0。
膨胀后的图像
g
g
g如下图所示:
4.C++代码
# 膨胀算法
import cv2
import numpy as np
# 读取二值图像
input_image = cv2.imread('test1.png', cv2.IMREAD_GRAYSCALE)
height = input_image.shape[0]
width = input_image.shape[1]
# 定义结构元素,左上角为结构元素原点
s = np.array([[1, 0], [1, 1]], dtype=np.bool8)
m, n = s.shape[0], s.shape[1]
output_image = input_image.copy()
# 进行膨胀操作
for row in range(height-m+1): # 对边界不做处理
for col in range(width-n+1):
result = input_image[row:row+m, col:col+n] & s
if result.sum() >= 1:
output_image[row, col] = 255
else:
output_image[row, col] = 0
cv2.imshow('input-image', input_image)
cv2.imshow('output-image', output_image)
cv2.waitKey(0)
5. 结果展示
可以看到,右图(膨胀后的图像)相较于左边的原图,轮廓变粗。
参考资料
- 数字图像处理基础.朱虹