如何基于二值图像中的边界提取所有区域(含接触边界区域)的填充结果
解决二值图像边界包围区域的填充问题(含接触边界的区域)
嘿,我完全懂你的困扰——scipy.ndimage.binary_fill_holes确实有个头疼的局限:它只会填充完全被前景包围、不接触图像边缘的洞,这在你的场景里根本不顶用。不过别慌,这里有两个实用的方法,能帮你搞定所有被边界包围的区域,哪怕是挨着图像边界的也没问题,而且完全支持你反转填充/非填充区域的取值:
方法一:扩展图像边界后再填充
核心思路是先给原始图像加一圈“虚拟背景”,让原本接触边界的区域变成“内部洞”,这样binary_fill_holes就能识别并填充了,最后再把扩展的边界裁掉就行。
代码示例
import numpy as np from scipy.ndimage import binary_fill_holes # 假设你的原始二值图像是img(1代表边界/前景,0代表背景,布尔或整数类型都可以) # 第一步:给图像上下左右各加一圈0(背景),把接触边界的区域变成内部区域 padded_img = np.pad(img, pad_width=1, mode='constant', constant_values=0) # 第二步:用binary_fill_holes填充所有洞(包括原来接触边界的) filled_padded = binary_fill_holes(padded_img) # 第三步:裁剪掉刚才加的一圈边界,得到最终结果 filled_img = filled_padded[1:-1, 1:-1] # 如果需要反转填充/非填充区域的取值,直接取反即可 filled_img_inverted = ~filled_img.astype(bool)
方法二:用OpenCV的FloodFill工具
OpenCV的floodFill可以从指定起点填充连通区域,非常适合处理接触边界的场景。我们可以先填充图像的背景区域,再反向提取出被边界包围的填充区域。
代码示例
import cv2 import numpy as np # 假设你的原始二值图像是img(uint8类型,0为背景,255为边界) h, w = img.shape # 创建掩码,注意floodFill要求掩码比原图大2个像素 mask = np.zeros((h + 2, w + 2), np.uint8) # 从图像的四个角落开始,把所有连通的背景区域填充为临时值(比如127) cv2.floodFill(img, mask, (0, 0), 127) cv2.floodFill(img, mask, (w - 1, 0), 127) cv2.floodFill(img, mask, (0, h - 1), 127) cv2.floodFill(img, mask, (w - 1, h - 1), 127) # 现在:原始边界是255,被包围的区域是0,背景是127 # 我们可以把被包围的区域设为255(填充),背景设为0,得到最终结果 filled_img = np.where(img == 0, 255, 0).astype(np.uint8) # 要是需要反转取值,调整判断条件就行,比如: # filled_img_inverted = np.where(img == 127, 255, 0).astype(np.uint8)
这两种方法都能完美覆盖你的需求:不管区域是否接触图像边界,都能准确填充,而且你完全可以根据需要反转填充和非填充区域的取值,只要边界能区分两类区域就好。
内容的提问来源于stack exchange,提问作者Tendero
相关产品推荐
相关产品推荐

