高效计算适应边界的邻域平均值

6
我有一张图像,其中的值范围从0到1。我想做的是简单平均。
但更具体地说,对于图像边缘的单元格,我想计算邻域/核心部分中像素的平均值,该邻域/核心部分位于图像的范围内。实际上,这归结为调整“均值公式”的分母,即将总和除以的像素数。

我使用scipy.ndimage.generic_filter实现了这一点,但这远非高效。

def fnc(buffer, count):
    n = float(sum(buffer < 2.0))
    sum = sum(buffer) - ((count - b) * 2.0)
    return (sum / n)

avg = scipy.ndimage.generic_filter(image, fnc, footprint = kernel, \
                                   mode = 'constant', cval = 2.0,   \
                                   extra_keywords = {'count': countkernel})

详细信息

  • kernel = 正方形数组(圆由1表示)
  • 使用2的填充而不是0,因为这样我才能正确区分填充区域的零和实际栅格的零
  • countkernel = kernel中的1的数量
  • n = 不包括值为2的填充区域内的单元格的image内的单元格数
  • 从原始邻域总和中减去(填充单元格的数量* 2.0),以纠正sum

更新

1)使用NaN进行填充会增加计算约30%:

    def fnc(buffer):
        return (numpy.nansum(buffer) / numpy.sum([~numpy.isnan(buffer)]))

    avg = scipy.ndimage.generic_filter(image, fnc, footprint = kernel, \
                                       mode = 'constant', cval = float(numpy.nan)

2) 应用由Yves Daoust(被接受的答案)提出的解决方案,可以将处理时间降至最低:

    def fnc(buffer):
        return numpy.sum(buffer)

    sumbigimage = scipy.ndimage.generic_filter(image, fnc, \
                                               footprint = kernel, \
                                               mode = 'constant', \
                                               cval = 0.0)
    summask     = scipy.ndimage.generic_filter(mask, fnc, \
                                               footprint = kernel, \
                                               mode = 'constant', \
                                               cval = 0.0)
    avg = sumbigimage / summask

3) 基于 Yves 的提示使用额外的二进制图像,实际上是应用掩码,我偶然发现了 masked arrays 的原理。因此,只需要处理一个数组,因为掩码数组“混合”了图像和掩码数组。
关于掩码数组的一个小细节:与之前更新中所做的在内部(原始图像的范围)填充1并在外部(边框)填充0相反,您必须做相反的操作。掩码数组中的1表示“无效”,0表示“有效”。
这段代码甚至比更新2中提供的代码快50%:

    maskedimg = numpy.ma.masked_array(imgarray, mask = maskarray)

    def fnc(buffer):
        return numpy.mean(buffer)

    avg = scipy.ndimage.generic_filter(maskedimg, fnc, footprint = kernel, \
                                       mode = 'constant', cval = 0.0)

--> 我必须在这里更正自己!
我在验证过程中可能出现了错误,因为经过一些计算后,似乎scipy.ndimage.<filters>无法处理masked_array,在过滤操作期间不考虑掩码。
其他一些人也提到了这一点,比如这里这里


一张图片的力量...

  • 灰色:要处理的图像范围
  • 白色:填充区域(在我的情况下填充为2.0)
  • 红色阴影:内核范围
    • 暗红色:有效邻域
    • 浅红色:要忽略的邻域部分

enter image description here


如何修改这个相当实用的代码以提高计算性能?

非常感谢您的帮助!

2个回答

1

不确定这是否有帮助,因为我不精通scipy:在灰色区域使用一个辅助图像,其中1的像素值表示该区域,白色区域则为0(源图像中也是0)。然后对两个图像应用简单求和滤波器。

如果scipy提供了一个内置函数来进行求和,那么就有一些加速的希望。

完成上述步骤后,您需要逐像素地对两个图像进行除法运算。


0

我不确定这种方法的效率如何,但我正在使用带有“nan”的简化公式,可以处理边界和掩码。

无掩码情况:

avg = scipy.ndimage.generic_filter(image, np.nanmean, mode='constant', cval=np.nan, footprint=kernel)

掩码案例:

masked_image = np.where(mask, image, np.nan)
avg = scipy.ndimage.generic_filter(masked_image, np.nanmean, mode='constant', cval=np.nan, footprint=kernel)

您可以使用所有的numpy中的nan函数。


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