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

如何用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效果不明显的原因

  1. 二值化轮廓不闭合:该函数仅填充完全被前景像素包围的孔洞。如果二值化后的目标区域边缘存在缺口,无法形成闭合轮廓,函数会判定内部区域不属于“孔洞”,自然不会填充。
  2. 平滑与阈值参数不当:你使用的sigma=3高斯平滑可能过度模糊边缘,导致二值化后目标边界断裂;Otsu阈值是自动全局阈值,可能不适合当前图像的局部对比度,造成前景区域不连续。
  3. 前景/背景逻辑反转:函数默认将值为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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 09:06:01