我有一张图像,其中的值范围从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)
- 红色阴影:内核范围
- 暗红色:有效邻域
- 浅红色:要忽略的邻域部分
如何修改这个相当实用的代码以提高计算性能?
非常感谢您的帮助!