Python OpenCV图像形态学操作详解:腐蚀、膨胀与高级运算
本文详细解析Python OpenCV中的图像形态学操作。从基础的腐蚀与膨胀入手,讲解卷积核与迭代次数的影响;深入介绍开运算、闭运算、梯度运算及礼帽黑帽的原理与代码实现,帮助开发者掌握图像去噪、边缘提取及细节增强技巧。
腐蚀
在处理部分图像时,常会遇到类似毛刺的异常区域,例如:

针对此类情况,可应用形态学操作。需注意,腐蚀操作仅适用于二值图像,即像素值仅为0(黑色)或255(白色)。先通过代码与效果进行说明:
import cv2
import numpy as np
img = cv2.imread('dagongren.png')
# 腐蚀的代码
kernel = np.ones((3,3),np.uint8)
erosion = cv2.erode(img,kernel,iterations = 1)
cv2.imshow('erosion', erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()

经过处理后,图像中的毛刺已基本消除,但文字部分略有缩小,这正是腐蚀操作的效果。具体而言,腐蚀操作通过设置一个n×n的矩阵(视为卷积核)在原图上滑动。若卷积核覆盖的像素中存在0(黑色),则卷积核中心位置置为0;若卷积核内全为255,则中心位置保持不变:

注意:腐蚀操作生成的是基于原图的新图像,而非直接修改原图数据。
接下来展示腐蚀操作的具体代码:
kernel = np.ones((3,3),np.uint8)
erosion = cv2.erode(img,kernel,iterations = 1)
首先,利用numpy库生成一个n×n的全1矩阵kernel作为卷积核,并指定数据类型为无符号8位整数(uint8)。随后调用erode()函数,其参数包括图像矩阵、kernel矩阵及迭代次数。迭代次数决定了腐蚀操作的重复执行次数。以下通过圆形图像展示不同迭代次数的腐蚀效果:
import cv2
import numpy as np
kernel = np.ones((30,30),np.uint8)
pie = cv2.imread('pie.png')
# 观察不同的迭代次数
erosion_1 = cv2.erode(pie,kernel,iterations = 1)
erosion_2 = cv2.erode(pie,kernel,iterations = 2)
erosion_3 = cv2.erode(pie,kernel,iterations = 3)
res = np.hstack((erosion_1,erosion_2,erosion_3))
cv2.imshow('res', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

膨胀
腐蚀操作虽能去除二值图像边缘的毛刺,但不可避免地会损失部分有效图像内容。膨胀操作则是腐蚀的反向过程:若卷积核包裹的像素中包含255,则卷积核中心位置置为255,否则保持不变。因此,膨胀操作会使图像范围扩大:
import cv2
import numpy as np
img = cv2.imread('dagongren.png')
kernel = np.ones((3,3),np.uint8)
# 膨胀操作
dige_dilate = cv2.dilate(img,kernel,iterations = 1)
cv2.imshow('dilate', dige_dilate)
cv2.waitKey(0)
cv2.destroyAllWindows()

可见,膨胀操作后图像整体范围扩大,毛刺也随之放大。通常,膨胀操作会与腐蚀操作结合使用,即先腐蚀后膨胀,这样可在基本保持有效内容尺寸不变的前提下去除毛刺:
import cv2
import numpy as np
img = cv2.imread('dagongren.png')
kernel = np.ones((3,3),np.uint8)
# 腐蚀
erosion = cv2.erode(img,kernel,iterations = 1) # 对原图像进行腐蚀
# 膨胀
dige_dilate = cv2.dilate(erosion,kernel,iterations = 1) # 对腐蚀后图像进行膨胀
cv2.imshow('dilate', dige_dilate)
cv2.waitKey(0)
cv2.destroyAllWindows()

其原理与参数含义与腐蚀操作类似,此处不再赘述。
开运算与闭运算
开运算与闭运算均基于腐蚀与膨胀操作处理原图像。区别在于:开运算是先腐蚀后膨胀,闭运算是先膨胀后腐蚀。两者均使用morphologyEx()函数,仅需调整参数即可实现不同操作。
开运算
执行开运算的函数调用如下:
cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
kernel仍为n×n矩阵,cv2.MORPH_OPEN指定执行开运算:
import cv2
import numpy as np
img = cv2.imread('dagongren.png')
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
cv2.imshow('opening', opening)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果如下:

闭运算
与开运算基本相同,只需将morphologyEx()函数的第二个参数改为cv2.MORPH_CLOSE即可:
import cv2
import numpy as np
img = cv2.imread('dagongren.png')
kernel = np.ones((3,3),np.uint8)
closing = cv2.morphologyEx(img,cv2.MORPH_CLOSE,kernel)
cv2.imshow('closing', closing)
cv2.waitKey(0)
cv2.destroyAllWindows()

结果显示,先膨胀后腐蚀的操作与原图相比并无显著差异,仅整体大了一圈,因此闭运算的应用频率低于开运算。
梯度运算
梯度运算本质为膨胀减去腐蚀。由此可知,梯度运算提取的是原图的边缘部分。获取梯度同样使用morphologyEx()函数,将第二个参数改为cv2.MORPH_GRADIENT即可:
import cv2
import numpy as np
img = cv2.imread('dagongren.png')
kernel = np.ones((3,3),np.uint8)
# 先用开运算把毛刺去掉:
img = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
cv2.imshow('gradient', gradient)
cv2.waitKey(0)
cv2.destroyAllWindows()
最终结果如下所示:

礼帽与黑帽
礼帽和黑帽为翻译术语,需避免望文生义。礼帽操作定义为原始图像减去开运算结果,黑帽操作定义为闭运算结果减去原始输入。同样使用morphologyEx()函数,通过修改第二个参数实现。
礼帽
礼帽操作所需的参数为cv2.MORPH_TOPHAT。根据定义,礼帽操作可提取图像中的“毛刺”部分:
import cv2
import numpy as np
img = cv2.imread('dagongren.png')
kernel = np.ones((3,3),np.uint8)
# 礼帽操作
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
cv2.imshow('tophat', tophat)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果如下:

黑帽
黑帽操作所需的参数为cv2.MORPH_BLACKHAT,该运算输出闭运算后图像比原图多出的轮廓部分:
import cv2
import numpy as np
img = cv2.imread('dagongren.png')
kernel = np.ones((5,5),np.uint8) # kernel矩阵维度大一些会让黑帽操作的结果更明显
# 黑帽操作
tophat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
cv2.imshow('tophat', tophat)
cv2.waitKey(0)
cv2.destroyAllWindows()

至此,关于Python常用图像形态学操作的详解介绍完毕。如需了解更多Python图像形态学相关内容,请搜索本站往期文章或继续浏览后续文章,感谢支持!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









