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

kad*_*éem 6 python performance image-processing boundary filter

我有一个值为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})
Run Code Online (Sandbox Code Playgroud)

细节

  • kernel =方阵(圆圈表示)
  • 从那时起填充2而不是零,我无法正确分隔填充区域的零和实际栅格的零
  • countkernel =中的数量 kernel
  • n= image通过排除由值2标识的填充区域的单元而位于其中的单元的数量
  • sum通过从原始邻域总和中减去(填充单元的数量*2.0)来校正

更新)

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)
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

3)在Yves的尖端上构建使用额外的二进制图像,实际上是应用了一个掩码,我偶然发现了掩码数组的原理.因此,只需要处理一个阵列,因为掩蔽的阵列将图像和掩模阵列"混合"在一起.
关于掩模阵列的一个小细节:不是用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)
Run Code Online (Sandbox Code Playgroud)

- >我必须在这里纠正自己!
我必须在验证过程中弄错,因为经过一些计算运行后,似乎scipy.ndimage.<filters>无法处理masked_arrays,在这种意义上,在过滤操作期间不考虑掩码.
其他人也提到了这一点,比如这里这里.


图像的力量......

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

在此输入图像描述


如何改变这种相当实用的代码片段以提高计算性能?

提前谢谢了!

小智 1

不确定这是否有帮助,因为我不精通 scipy:在灰色区域使用 1 的辅助图像,在白色区域使用 0 的辅助图像(源图像中也使用 0)。然后通过简单的求和将过滤器应用于两个图像。

如果 scipy 提供带有内置求和函数的专用过滤器版本,则有望实现加速。

完成后,您需要将两个图像逐像素划分。