OpenCV形态学开运算不满足幂等性的问题排查
问题描述
编辑说明:最初提问时色彩映射反转造成了部分误解,我已调整对应图像与代码以匹配标准行为。
形态学开运算(Opening)与闭运算(Closing)属于*幂等(idempotent)*操作:
开运算是幂等操作:对图像完成一次开运算后,使用相同结构元对结果再次执行开运算不会产生额外效果,满足如下公式:
(f ∘ s) ∘ s = f ∘ s
测试素材
本次测试使用的图像如下:
异常现象
使用OpenCV尝试移除图像右上角的细矩形时发现,使用相同核对图像迭代执行开运算时,每次运算都会产生新的处理效果,迭代多次后才能得到预期的移除结果,和幂等操作的特性不符。
测试代码如下:
import cv2 as cv import numpy as np %matplotlib inline import matplotlib import matplotlib.pyplot as plt matplotlib.rc('image', cmap='gray') # 读取图像 img = cv.imread("image.jpg", 0) # 二值化处理消除jpg压缩带来的灰度值干扰 img = (img > 128).astype(np.uint8) # 给图像添加边框即可解决该问题 # img = cv.copyMakeBorder(img, 1, 1, 1, 1, cv.BORDER_CONSTANT) kernel = cv.getStructuringElement(cv.MORPH_RECT,(20,5)) A = cv.morphologyEx(img, cv.MORPH_OPEN, kernel) B = cv.morphologyEx(A, cv.MORPH_OPEN, kernel) C = cv.morphologyEx(B, cv.MORPH_OPEN, kernel) f, ax = plt.subplots(1,3) ax[0].imshow(A) ax[0].set_title("第一次开运算结果A") ax[1].imshow(B) ax[1].set_title("第二次开运算结果B") ax[2].imshow(C) ax[2].set_title("第三次开运算结果C") plt.show()
运行结果如下图所示,可观察到每次迭代后图像右边界的矩形都会被进一步移除:
原因说明
这既不是对形态学原理的理解存在偏差,也不是OpenCV的相关实现有问题,核心原因是OpenCV形态学操作的默认边界处理规则:
- OpenCV的腐蚀、膨胀以及由二者组合得到的开/闭运算都属于邻域滑动操作,当结构元滑动到图像边缘、部分区域超出图像边界时,需要对边界外的像素值做填充才能完成计算。OpenCV默认使用
BORDER_REFLECT_101镜像填充规则,也就是把图像边缘的像素镜像复制到边界外作为采样值,不会默认判定图像外为全黑或全白。 - 本次测试中要移除的细矩形恰好紧贴图像右边缘:第一次执行开运算的腐蚀步骤时,结构元滑到右边界位置,超出图像的部分采样到的是镜像复制的白色矩形像素,无法满足“结构元覆盖区域全为前景才保留像素”的腐蚀条件,只会腐蚀掉矩形靠图像内侧的一段,剩余贴边的残段会被后续的膨胀步骤保留。
- 第二次执行开运算时,上一轮残留的贴边矩形宽度更窄,结构元在边缘位置采样时能覆盖到更多黑色背景区域,就会再腐蚀掉一截,多次迭代后矩形才会被完全清除,也就出现了看似违反幂等性的现象。
- 代码中注释掉的
cv.copyMakeBorder添加黑色常量边框的方案,本质就是提前把图像边界外的采样值固定为0(黑色背景),第一次开运算时结构元在边界位置就能满足腐蚀条件,一次操作就能完全移除细矩形,后续再做相同的开运算不会产生任何变化,完全符合幂等性的定义。
内容的提问来源于stack exchange,提问作者okolaris
相关产品推荐
相关产品推荐

