形态变换
\qquad 形态变换主要用于二值图像的形状操作,形态变换的实现原理基于数字形态学。数字形态学也称形态学,它主要从图像内部提取信息来描述图像形态。例如,通过形态运算获取手写文字的骨架信息。数字形态学广泛应用于视觉检测、文字识别、医学图像处理、图像压缩编码等领域。形态变换主要包括腐蚀、膨胀和高级形态学操作(开运算,闭运算等)。
\qquad 腐蚀和膨胀是数学形态学最基本的变换。膨胀就是把连接成分的边界扩大一层的处理,而收缩则是把连接成分的边界点去掉从而缩小一层的处理。对于二值图像来说,简单的腐蚀是消除物体的所有边界点的一种过程,其结果是使剩下的物体沿其周边比原物体小—个像素的面积。如果物体是圆的,它的直径在每次腐蚀后将减少两个像素,如果物体在某一点处任意方向上连通的像素小于 3 个,那么该物体经过一次腐蚀后将在该点处分裂为两个物体。简单的膨胀运算是将与某物体接触的所有背景点合并到该物体中的过程。膨胀的结果是使物体的面积增大相应数量的点,如果物体是圆的,它的直径在每次膨胀后将增大两个像素。如果两个物体在某一点的任意方向相隔少于 3 个像素,它们将在该点连通起来。
\qquad 开运算是先对且标图像进行腐蚀操作,后进行膨胀操作,用来消除小物体,平滑较大物体边界的同时不明显改变其面积。开运算通常是在需要去除小颗粒噪声,以及断开目标物之间粘连时使用,其主要作用与腐蚀相似。与腐蚀操作相比,具有可以基本保持目标原有大小不变的优点。闭运算则是先对目标图像进行膨胀操作,后进行腐蚀操作,常用来填充物体内细小空洞,连接邻近物体,平滑其迈界,同时不明显改变其面积。
\qquad 形态操作会使用一个内核(也称结构元)遍历图像,根据内核和图像的位置关系决定内核中心对应的图像像素点的输出结果。内核可以是自定义的矩阵(NumPy数组),也可以是 cv2.getSinucturingElement()函数返回的矩阵。
cv2.getStructuringElement()函数的基本格式如下:
retval=cv2.getStructuringElement(shape,ksize)
其参数说明如下:
参数 | 说明 |
---|---|
shape | 为内核的形状,可使用的常量包括 cv2.MORPH_RECT(矩形)、cv2.MORPH_CROSS(十字形)和 cv2.MORPH_ELLIPSE(椭圆形) |
ksize | 为内核的大小 |
import cv2
import numpy as np
print(cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))) # 返回矩形内核
print(cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))) # 返回十字形内核
print("自定义内核") # 自定义内核
kernel = np.ones((5, 5), np.uint8) # 自定义矩形内核
print(kernel)
腐蚀
\qquad 腐蚀操作遍历图像时,会根据内核和图像的位置决定内核中心对应的图像像素点的输出结果。在下图所示的示意图中,0 表示背景,1 表示前景,灰色方块表示大小为 3× 3 的矩形内核。执行腐蚀操作时,依次将内核中心对准每一个单元格,根据内核和前景的未知关系决定当前单元格的值。
1.当内核部分或全部处于前景之外时,内核中心对应单元格的值设置为 0,如图 (a)所示。
2.只有在内核完全出哟前景内部时, 内核中心对应单元格的值才设置为1,如图(b)所示。
通过腐蚀操作,图像的边界被侵蚀, 白色区域缩小,腐蚀结果如图(c)所示。
OpenCV 的 cv2.erode()函数用于实现腐蚀操作,其基本格式如下:
dst=cv2.erode(src,kernel[,anchor[,iterations[,borderType[,porderValue]]]])
其参数说明如下:
参数 | 说明 |
---|---|
dst | 为转换后的结果图像 |
src | 为原图像 |
kernel | 为内核 |
anchor | 为锚点,默认值为(-1,-1),表示锚点为内核中心 |
iterations | 为腐蚀操作的迭代次数 |
borderType | 为边界类型,默认为 BORDER_CONSTANT |
borderValue | 为边界值,一般由 OpenCV 自动确定 |
import cv2
import numpy as np
img = cv2.imread('zh2.jpg') # 读取图像
cv2.imshow('img', img) # 显示原图像
kernel = np.ones((5, 5), np.uint8) # 定义5×5核心
img2 = cv2.erode(img, kernel, iterations=1) # 腐蚀,迭代1次
cv2.imshow('img2', img2) # 显示转换结果图像
cv2.waitKey(0)
膨胀
\qquad 膨胀操作与腐蚀操作刚好相反,它对图像的边界进行扩张。其执行遍历操作时,只有在内核完全
处于前景外部时,内核中心对应像素点的值才设置为0,否则设置为1。在下图所示的示意图中,0表示背景,1表示前景,灰色方块表示大小为3×3的矩形内核。执行膨胀操作时,依次将内核中心对准每一个单元格,根据内核和前景的位置关系决定当前单元格的值。
1.只有在内核完全处于前景外部时,内核中心对应单元格的值才设置为0,如图(a)所示。
2.内核部分在前景内时,内核中心对应单元格的值设置为1,如图(b)所示。
通过膨胀操作,图像的边界被扩张,白色区域增大,膨胀结果如图(c)所示。
OpenCV的cv2.dilate()函数用于实现膨胀操作,其基本格式如下:
dst=cv2.dilate(src,kernel,anchor,iterations,borderType,borderValue)
各个参数的含义与cv2.erode()函数中的一致。
import cv2
import numpy as np
img = cv2.imread('zh.jpg') # 读取图像
cv2.imshow('img', img) # 显示原图像
kernel = np.ones((5, 5), np.uint8) # 定义5×5核心
img2 = cv2.dilate(img, kernel, iterations=2) # 膨胀,迭代2次
cv2.imshow('img2', img2) # 显示转换结果图像
cv2.waitKey(0)
如果觉得上面的文字不好理解腐蚀和膨胀操作,可以结合下面的动态视频来理解
腐蚀和膨胀动画演示
高级形态操作
\qquad 高级形态操作基于腐蚀和膨胀操作,包括开运算、闭运算、形态学梯度运算、黑帽运算和礼帽运算等。OpenCV的cv2.morphologyEx()函数用于实现形态学操作,其基本格式如下:
dst=cv2.morphologyEx(src,op,kernel,anchor,iterations,borderType,borderValue)
其中op为形态操作类型,op参数值cv2.MORPH_ERODE时执行腐蚀操作,op参数值为cv2.MORPH_DILATE时执行膨胀操作。其他参数与cv2.erode()函数中的一致。
开运算
开运算将先对图像执行腐蚀操作,再对腐蚀结果执行膨胀操作。
cv2.morphologyEx()函数的op参数值为cv2.MORPH_OPEN时,执行形态学的开运算操作
import cv2
import numpy as np
img = cv2.imread('zh2.jpg') # 读取图像
cv2.imshow('img', img) # 显示原图像
kernel = np.ones((5, 5), np.uint8) # 定义5×5核心
op = cv2.MORPH_OPEN # 设置形态操作类型
img2 = cv2.morphologyEx(img, op, kernel, iterations=2) # 形态操作,迭代2次
cv2.imshow('img2', img2) # 显示转换结果图像
cv2.waitKey(0)
闭运算
闭运算与开运算相反,它先对图像执行膨胀操作,再对膨胀结果执行腐蚀操作。
cv2.morphologyEx()函数的op参数值为cv2.MORPH_CLOSE时,执行形态学的闭运算操作
import cv2
import numpy as np
img = cv2.imread('zh.jpg') # 读取图像
cv2.imshow('img', img) # 显示原图像
kernel = np.ones((5, 5), np.uint8) # 定义5×5核心
op = cv2.MORPH_CLOSE # 设置形态操作类型
img2 = cv2.morphologyEx(img, op, kernel, iterations=5) # 形态操作,迭代5次
cv2.imshow('img2', img2) # 显示转换结果图像
cv2.waitKey(0)
形态学梯度运算
形态学梯度运算原理是用图像的膨胀操作结果减去腐蚀操作结果。
cv2.morphologyEx()函数的op参数值为cv2.MORPH_GRADIENT时,执行形态学梯度运算操作
import cv2
import numpy as np
img = cv2.imread('zh.jpg') # 读取图像
cv2.imshow('img', img) # 显示原图像
kernel = np.ones((5, 5), np.uint8) # 定义5×5核心
op = cv2.MORPH_BLACKHAT # 设置形态操作类型
img2 = cv2.morphologyEx(img, op, kernel, iterations=5) # 形态操作,迭代5次
cv2.imshow('img2', img2) # 显示转换结果图像
cv2.waitKey(0)
黑帽运算
黑帽运算原理是用图像的闭运算结果减去原图像。
cv2.morphologyEx()函数的op参数值为cv2.MORPH_BLACKHAT时,执行形态学的黑帽运算操作
import cv2
import numpy as np
img = cv2.imread('zh.jpg') # 读取图像
cv2.imshow('img', img) # 显示原图像
kernel = np.ones((5, 5), np.uint8) # 定义5×5核心
op = cv2.MORPH_BLACKHAT # 设置形态操作类型
img2 = cv2.morphologyEx(img, op, kernel, iterations=5) # 形态操作,迭代5次
cv2.imshow('img2', img2) # 显示转换结果图像
cv2.waitKey(0)
礼帽运算
礼帽运算原理是用原图像减去图像的开运算结果。
cv2.morphologyEx()函数的op参数值为cv2.MORPH_TOPHAT时,执行形态学的礼帽运算操作
import cv2
import numpy as np
img = cv2.imread('zh.jpg') # 读取图像
cv2.imshow('img', img) # 显示原图像
kernel = np.ones((5, 5), np.uint8) # 定义5×5核心
op = cv2.MORPH_TOPHAT # 设置形态操作类型
img2 = cv2.morphologyEx(img, op, kernel, iterations=2) # 形态操作,迭代2次
cv2.imshow('img2', img2) # 显示转换结果图像
cv2.waitKey(0)
高级形态操作总结
形态操作 | 优点 |
---|---|
开运算 | 先腐蚀后膨胀,可以用来消除小物体,在纤细点处分离物体,并且在平滑较大物体的边界的同时不明显改变其面积 |
闭运算 | 先膨胀后腐蚀,,可以用来排除小型黑洞(黑色区域) |
形态学梯度运算 | 膨胀图和腐蚀图之差,对二值图像进行这一操作,可以将团块(blob)的边缘突出出来,保留物体的边缘轮廓 |
礼帽运算 | 原图像和开运算结果图之差,常用来分离比邻近点亮一些的斑块,在一幅图像具有大幅的背景而微小物品比较有规律的情况下,可以使用顶帽运算进行背景提取 |
黑帽运算 | 闭运算结果图和原图像之差,突出了比原图像轮廓周围的区域更暗的区域,所以用来分离比邻近点暗一些的斑块,效果图有着非常完美的轮廓 |