You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 03:09:44