如何用fill_holes填充分割区域?ndi.binary_fill_holes效果不明显原因咨询
问题描述
我希望跟踪分割区域的灰度值随时间的变化情况,但ndi.binary_fill_holes函数的填充效果并不明显,想咨询原因及如何正确使用该函数完成分割区域的填充操作。
相关代码
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) sigma = 3 img_smooth = ndi.gaussian_filter(gray, sigma) thresh = threshold_otsu(img_smooth) new = img_smooth > thresh fill = ndi.binary_fill_holes(new) fig, ax = plt.subplots(1, 2, figsize=(10,7)) ax[0].imshow(mem, interpolation='none', cmap='gray') ax[1].imshow(fill, interpolation='none', cmap='gray') ax[0].set_title('Thresh') ax[1].set_title('Fill')
相关图像
原始图

灰度图、平滑图


填充结果图

问题分析与解决方法
一、ndi.binary_fill_holes效果不明显的原因
- 二值化轮廓不闭合:该函数仅填充完全被前景像素包围的孔洞。如果二值化后的目标区域边缘存在缺口,无法形成闭合轮廓,函数会判定内部区域不属于“孔洞”,自然不会填充。
- 平滑与阈值参数不当:你使用的
sigma=3高斯平滑可能过度模糊边缘,导致二值化后目标边界断裂;Otsu阈值是自动全局阈值,可能不适合当前图像的局部对比度,造成前景区域不连续。 - 前景/背景逻辑反转:函数默认将值为1的像素(白色)视为前景,若你的目标区域是黑色(值为0),函数会把图像外部区域当成前景,完全无法触发内部孔洞的填充逻辑。
二、正确使用ndi.binary_fill_holes的方法
1. 调整二值化参数,确保轮廓闭合
- 减小高斯平滑的
sigma值(如改为1或2),保留更多边缘细节; - 尝试手动设置阈值替代Otsu自动阈值,比如
thresh = 130(根据图像实际亮度调整),确保目标区域形成完整闭合轮廓。
2. 修正前景/背景的逻辑
如果目标区域是黑色(背景为白色),先反转二值图像再填充:
# 反转二值图,让目标变为前景(白色) new_inverted = 1 - new fill = ndi.binary_fill_holes(new_inverted) # 按需反转回原逻辑 fill_inverted = 1 - fill
3. 配合形态学操作优化边缘
用闭运算先闭合边缘缺口,再进行孔洞填充:
from scipy.ndimage import binary_closing, generate_binary_structure # 生成十字形结构元素,可根据需求调整大小 struct = generate_binary_structure(2, 1) # 闭运算闭合边缘缺口 closed = binary_closing(new, structure=struct, iterations=2) # 填充孔洞 fill = ndi.binary_fill_holes(closed)
4. 提取填充区域的灰度值
填充完成后,即可用掩码提取目标区域,跟踪灰度值变化:
# 提取填充后目标区域的灰度值 target_gray = gray[fill] # 计算当前帧的平均灰度,视频场景下可循环保存每帧结果 mean_gray = target_gray.mean()
内容的提问来源于stack exchange,提问作者nancy M
相关产品推荐
相关产品推荐

