形态学,即数学形态学(Mathematical Morphology),是图像处理过程中一个非常重要的研 究方向。形态学主要从图像内提取分量信息,该分量信息通常对于表达和描绘图像的形状具有 重要意义,通常是图像理解时所使用的最本质的形状特征。例如,在识别手写数字时,能够通
过形态学运算得到其骨架信息,在具体识别时,仅针对其骨架进行运算即可。形态学处理在视觉检测、文字识别、医学图像处理、图像压缩编码等领域都有非常重要的应用。
形态学操作主要包含:腐蚀、膨胀、开运算、闭运算、形态学梯度(Morphological Gradient)运算、顶帽运算(礼帽运算)、黑帽运算等操作。腐蚀操作和膨胀操作是形态学运算的基础,
将腐蚀和膨胀操作进行结合,就可以实现开运算、闭运算、形态学梯度运算、顶帽运算、黑帽运算、击中击不中等不同形式的运算。
腐蚀原理
腐蚀是最基本的形态学操作之一,它能够将图像的边界点消除,使图像沿着边界向内收缩,也可以将小于指定结构体元素的部分去除。
说白了就是让图片中的胖子慢慢的变成瘦子
腐蚀用来"收缩"或者"细化"二值图像中的前景,借此实现去除噪声、元素分割等功能。
例如,在图 8-1 中,左图是原始图像,右图是对其腐蚀的处理结果。
在腐蚀过程中,通常使用一个结构元来逐个像素地扫描要被腐蚀的图像,并根据结构元和被腐蚀图像的关系来确定腐蚀结果。
例如,在图 8-2 中,整幅图像的背景色是黑色的,前景对象是一个白色的圆形。图像左上角的深色小方块是遍历图像所使用的结构元。在腐蚀过程中,要将该结构元逐个像素地遍历整幅图像,并根据结构元与被腐蚀图像的关系,来确定腐蚀结果图像中对应结构元中心点位置的像素点的值。
需要注意 的是,腐蚀操作等形态学操作是逐个像素地来改变值的,每次判定的点都是与结构元中心点所对应的点。
图 8-3 中的两幅图像表示结构元与前景色的两种不同关系。
根据这两种不同的关系来决定,腐蚀结果图像中的结构元中心点所对应位置像素点的像素值。
- 如果结构元完全处于前景图像中(图 8-3 的左图),就将结构元中心点所对应的腐蚀结果图像中的像素点处理为前景色(白色,像素点的像素值为 1)。
- 如果结构元未完全处于前景图像中(可能部分在,也可能完全不在,图 8-3 的右图),就将结构元中心点对应的腐蚀结果图像中的像素点处理为背景色(黑色,像素点的像素值为 0)。
针对图 8-3 中的图像,腐蚀的结果就是前景色的白色圆直径变小。上述结构元也被称为核。
例如,有需要被腐蚀的图像 img,其值如下,其中 1 表示白色前景,0 表示黑色背景:
[[0 0 0 0 0]
[0 1 1 1 0]
[0 1 1 1 0]
[0 1 1 1 0]
[0 0 0 0 0]]
有一个结构元 kernel,其值为:
[[1]
[1]
[1]]
如果使用结构元 kernel 对图像 img 进行腐蚀,则可以得到腐蚀结果图像 rst:
[[0 0 0 0 0]
[0 0 0 0 0]
[0 1 1 1 0]
[0 0 0 0 0]
[0 0 0 0 0]]
这是因为,当结构元 kernel 在图像 img 内逐个像素遍历时,只有当核 kernel 的中心点 "kernel[1,0]"位于 img 中的 img[2,1]、img[2,2]、img[2,3]时,核才完全处于前景图像中。
所以在腐蚀结果图像 rst 中,只有这三个点的值被处理为 1,其余像素点的值被处理为 0。
上述示例如图 8-4 所示,其中:
- 图(a)表示要被腐蚀的 img。
- 图(b)是核 kernel。
- 图©中的阴影部分是 kernel 在遍历 img 时,kernel 完全位于前景对象内部时的 3 个全部
可能位置;此时,核中心分别位于 img[2,1]、img[2,2]和 img[2,3]处。 - 图(d)是腐蚀结果 rst,即在 kernel 完全位于前景图象中时,将其中心点所对应的 rst 中像素点的值置为 1;当 kernel 不完全位于前景图像中时,将其中心点对应的 rst 中像素点的值置为 0。
函数 cv2.erode() 说明
在 OpenCV 中,使用函数 cv2.erode()实现腐蚀操作,其语法格式为:
dst = cv2.erode( src, kernel[, anchor[, iterations[, borderType[,
borderValue]]]] )
式中:
-
dst 是腐蚀后所输出的目标图像,该图像和原始图像具有同样的类型和大小。
-
src 是需要进行腐蚀的原始图像,图像的通道数可以是任意的。但是要求图像的深度必须是 CV_8U、CV_16U、CV_16S、CV_32F、CV_64F 中的一种。
-
kernel 代表腐蚀操作时所采用的结构类型。它可以自定义生成,也可以通过函数cv2.getStructuringElement()生成。
-
anchor 代表 element 结构中锚点的位置。该值默认为(-1,-1),在核的中心位置。
-
iterations 是腐蚀操作迭代的次数,该值默认为 1,即只进行一次腐蚀操作。
-
borderType 代表边界样式,一般采用其默认值 BORDER_CONSTANT。该项的具体值如表 8-1 所示。
- borderValue 是边界值 ,一般采用默认值。在 C++中提供了函数 morphologyDefaultBorderValue()来返回腐蚀和膨胀的"魔力(magic)"边界值,Python 不支持该函数。
代码示例 :使用数组演示腐蚀的基本原理
代码如下:
import cv2
import numpy as np
img=np.zeros((5,5),np.uint8)
#对图像进行赋值
img[1:4,1:4]=1
#设置卷积核
kernel = np.ones((3,1),np.uint8)
#对图像进行腐蚀操作
erosion = cv2.erode(img,kernel)
print("img=\n",img)
print("kernel=\n",kernel)
print("erosion=\n",erosion)
运行结果:
img=
[[0 0 0 0 0]
[0 1 1 1 0]
[0 1 1 1 0]
[0 1 1 1 0]
[0 0 0 0 0]]
kernel=
[[1]
[1]
[1]]
erosion=
[[0 0 0 0 0]
[0 0 0 0 0]
[0 1 1 1 0]
[0 0 0 0 0]
[0 0 0 0 0]]
从本例中可以看到,只有当核 kernel 的中心点位于 img 中的 img[2,1]、img[2,2]、img[2,3]处时,核才完全处于前景图像中。
所以,在腐蚀结果图像中,只有这三个点的值为 1,其余点的值皆为 0。
示例2:使用函数 cv2.erode()完成图像腐蚀
代码如下:
import cv2
import numpy as np
o=cv2.imread("fushi.bmp",cv2.IMREAD_UNCHANGED)
#创建结构元素
kernel = np.ones((7,7),np.uint8)
#腐蚀
erosion = cv2.erode(o,kernel)
cv2.imshow("orriginal",o)
cv2.imshow("erosion",erosion)
cv2.waitKey()
cv2.destroyAllWindows()
运行效果:
左图是原始图像,右图是腐蚀处理结果。从图中可
以看到,腐蚀操作将原始图像内的毛刺腐蚀掉了。
调节函数 cv2.erode()的参数,观察不同参数控制下的图像腐蚀效果
使用参数 iterations = 5 对函数 cv2.erode()的迭代次数进行控制,让其迭代 5 次。
代码如下:
import cv2
import numpy as np
o=cv2.imread("fushi.bmp",cv2.IMREAD_UNCHANGED)
#创建结构元素
kernel = np.ones((7,7),np.uint8)
#腐蚀
erosion = cv2.erode(o,kernel,iterations = 5)
cv2.imshow("orriginal",o)
cv2.imshow("erosion",erosion)
cv2.waitKey()
cv2.destroyAllWindows()
从结果中可以看出迭代的次数越多,腐蚀的越明显
更多参数调整测试可以自己多动手试试