基于数学定义的Python二值图像孔洞填充自定义函数实现问题求助
孔洞填充代码问题排查与修正
核心错误点
- 初始点选取逻辑完全错误:你当前找的是二值图中最亮的前景区域点,该位置在反转图
imginv中为纯黑(值为0),导致初始化的initial矩阵全为0,后续所有运算结果都是0,最终输出和原图完全一致 - 迭代语法错误:
for k in (0,10000)仅会执行2次循环(k=0和k=10000),而非你预期的10000次迭代 - 迭代公式逻辑错误:孔洞填充的标准公式是
X_k = (cv.erode(X_{k-1}, B)) & imginv,你当前写的X_k=initial & erosion是和上一轮的X做与运算,不符合算法要求 - 单初始点覆盖不全:单个随机初始点只能填充对应一个孔洞,要填充所有孔洞需要批量标记所有孔洞的种子点
修正后的代码
import numpy as np import cv2 as cv import matplotlib.pyplot as plt def holefiling(img, B): # 先统一转换为标准二值图,0为黑,255为白 _, img_bin = cv.threshold(img, 127, 255, cv.THRESH_BINARY) imginv = cv.bitwise_not(img_bin) # 初始化标记矩阵:排除图像边缘的背景暗区,剩下的内部暗区都是待填充孔洞 initial = np.zeros_like(img_bin) h, w = img_bin.shape for i in range(1, h-1): for j in range(1, w-1): if img_bin[i,j] == 0: # 原图暗区 initial[i,j] = 255 # 所有内部暗区都设为初始种子点 # 迭代直到收敛(前后两次结果无变化就停止) prev = np.zeros_like(initial) while not np.array_equal(prev, initial): prev = initial.copy() erosion = cv.erode(initial, B, iterations=1) initial = erosion & imginv # 填充结果 = 填充好的孔洞区域 + 原图原有前景 output = initial | img_bin return output # 调用测试 kernel = cv.getStructuringElement(cv.MORPH_CROSS, (3,3)) # 此处closing为你提前做完闭运算的二值图 Holefilled = holefiling(closing, kernel) # 结果展示 plt.figure() plt.suptitle('头部CT孔洞填充结果') plt.subplot(131) plt.title('原始图像') plt.imshow(img, cmap='gray', vmin=0, vmax=np.max(img)) plt.axis(False) plt.subplot(132) plt.title('闭运算结果') plt.imshow(closing, cmap='gray', vmin=0, vmax=np.max(closing)) plt.axis(False) plt.subplot(133) plt.title('孔洞填充结果') plt.imshow(Holefilled, cmap='gray', vmin=0, vmax=np.max(Holefilled)) plt.axis(False) plt.show()
补充说明
- 十字形结构元的选型符合你参考的算法要求,没有问题
- 用收敛判断代替固定迭代次数,在保证填充完全的前提下大幅提升运行效率
- 如果你的CT图像孔洞区域明确,也可以手动指定种子点替换批量种子点逻辑,减少不必要的运算
内容的提问来源于stack exchange,提问作者user16077513
相关产品推荐
相关产品推荐

