Python:在图像的掩模内执行模糊

3
我有一张灰度图像和一个边界为ROI的二进制掩膜。我想对灰度图像执行模糊操作,但仅限于掩膜内部。目前我是在整个图像上进行模糊处理,然后只是移除掩膜外的物品,但我不希望掩膜外的像素影响我的ROI。是否有一种方法可以在不构建自定义模糊函数的情况下完成此操作?
希望得到类似以下的东西:
import scipy
blurredImage = scipy.ndimage.filters.gaussian_filter(img, sigma = 3, weight = myMask)

@stefan:

blur = 3
invmask = np.logical_not(mask).astype(int)

masked = img * mask
remaining = img * invmask

blurred = scipy.ndimage.filters.gaussian_filter(masked, sigma = blur)
blurred = blurred+remaining

扩张方法:
blur = 3
invmask = np.logical_not(mask).astype(int)    
masked = img * mask
masked2 = scipy.ndimage.morphology.grey_dilation(masked,size=(5,5))
masked2 = masked2 *invmask
masked2 = masked + masked2
blurred = scipy.ndimage.filters.gaussian_filter(masked2, sigma = blur)

掩码与图像相乘仅包含roi内的像素。掩码的反转与图像相乘是剩余像素。因此,模糊掩蔽像素并添加剩余像素。 - Stefan
您可以通过切片提取要模糊的ROI,然后让您在边缘周围需要的“虚拟像素”合成为更远处重复ROI内部内容。 - Mark Setchell
@stefan,谢谢,我已经添加了代码,以我理解你的评论。我可能误解了,但这与我的当前方法类似,只是我的ROI的边缘会在0背景上模糊。你能澄清一下吗? - user3470496
@马克,谢谢马克,我也有类似的想法,但是找不到任何灰度膨胀函数,有没有一种不需要使用混乱的自定义函数来实现这个功能的方法? - user3470496
实际上,我刚意识到链接的答案并没有完全回答你的问题。我会在下面补充完整。 - Cris Luengo
2个回答

8
应用线性滤波器到有限域的正确方法是使用归一化卷积。该方法在每个邻域内计算(加权)均值,然后通过该邻域中存在的(加权)像素数量进行归一化。它仅使用两次滤波器应用和一些微不足道的逐像素操作来实现此目的。
# normalized convolution of image with mask
filter = scipy.ndimage.gaussian_filter(img * mask, sigma = blur)
weights = scipy.ndimage.gaussian_filter(mask, sigma = blur)
filter /= weights
# after normalized convolution, you can choose to delete any data outside the mask:
filter *= mask

请注意,mask不仅限于0和1,它可以包含中间值,表示您对该像素值的正确性有多么“确定”。但通常情况下,0表示“缺失数据”,1表示可用数据。 gaussian_filter必须使用浮点格式进行计算,并返回一个浮点值图像。在这里,整数运算将无法得到正确的结果。
这是一个例子:

enter image description here

第二张图片:先进行简单的滤波,然后去除掩模外的内容。这表明掩模外的数据会影响滤波结果。
第三张图片:先进行简单的滤波,但是先将掩模外的内容设为零。这表明掩模外的零值会影响滤波结果。
第四张图片:使用归一化卷积:掩模外的数据对滤波结果没有任何影响。

这给了我一个奇怪的输出,大多数掩蔽ROI都被侵蚀了,也许我应用错了? - user3470496
@user3470496:注意最后一段话:你必须使用浮点运算。最安全的方法是将mask转换为浮点数组。 - Cris Luengo
@user3470496:我已经附上一个示例输出。 - Cris Luengo
成功了!输出看起来有些奇怪,里面有一些NaN值,但是“filter = np.nan_to_num(filter,nan=0.0)”解决了问题。谢谢! - user3470496
为了避免NaN,你也可以这样做:filter /= weights + 0.0001 - Cris Luengo

2

你想要实现的目标比你想象的更加困难和不确定。

模糊操作对应于每个像素邻域中像素的某种(各向同性的)平均。但在域的边界附近,邻域是不完整的,需要通过以下方式进行修复:

  • 通过局部重新定义滤波器系数来避免“查询”外部像素;一种简单的方法是将这些像素的滤波权重设置为零;或者

  • 通过外推ROI之外的像素值。应该以一种避免沿边界出现不连续性的方式进行处理,例如通过Poisson重建。

对于第一种方法,可以按照以下方式劫持标准滤波器:

  • 将外部像素设置为0并模糊整个图像;当滤波器跨越轮廓时,您将仅得到内部权重和内部像素的组合;

  • 将内部像素设置为1并模糊图像;您将仅得到内部权重的总和;

  • 取两个模糊图像的比率,以便正确地重新归一化权重。

如果图像是整数类型,则使用255而不是1以保持足够的精度。请注意,ROI之外,比率将具有零分母。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接