问题描述
我需要一个 3x3 相邻单元的总和数组,其乘积基于具有相同大小的不同数组的内核(到目前为止正好是 scipy.ndimage.correlate)。但是当计算新数组的值时,它必须立即更新,而不是使用原始数组中的值进行下一次涉及该值的计算。我已经编写了这个缓慢的代码来自己实现它,它运行得非常好(虽然对我来说太慢了)并提供了预期的结果:
for x in range(width):
for y in range(height):
AArr[y,x] += laplaceNeighborDifference(x,y)
def laplaceNeighborDifference(x,y,z):
global w,h,AArr
return -AArr[y,x]+AArr[(y+1)%h,x]*.2+AArr[(y-1)%h,x]*.2+AArr[y,(x+1)%w]*.2+AArr[y,(x-1)%w]*.2+AArr[(y+1)%h,(x+1)%w]*.05+AArr[(y-1)%h,(x+1)%w]*.05+AArr[(y+1)%h,(x-1)%w]*.05+AArr[(y-1)%h,(x-1)%w]*.05
在我的方法中,内核是直接编码的。虽然作为一个数组(用作内核)它会写成这样:
[[.05,.2,.05],[.2,-1,.2 ],[.05,.05]]
SciPy 实现的工作方式如下:
AArr += correlate(AArr,kernel,mode='wrap')
但很明显,当我使用 scipy.ndimage.correlate 时,它完全根据原始数组计算值,并且在计算它们时不会更新它们。至少我认为这是我的实现和 SciPy 实现之间的区别,如果我遗漏了其他差异,请随时指出其他差异。我的问题是是否有与上述类似的功能并具有所需的结果,或者是否有一种比我更快的编码方法?
感谢您的宝贵时间!
解决方法
您可以使用 Numba 来高效地做到这一点:
import numba as nb
@nb.njit
def laplaceNeighborDifference(AArr,w,h,x,y):
return -AArr[y,x]+AArr[(y+1)%h,x]*.2+AArr[(y-1)%h,x]*.2+AArr[y,(x+1)%w]*.2+AArr[y,(x-1)%w]*.2+AArr[(y+1)%h,(x+1)%w]*.05+AArr[(y-1)%h,(x+1)%w]*.05+AArr[(y+1)%h,(x-1)%w]*.05+AArr[(y-1)%h,(x-1)%w]*.05
@nb.njit('void(float64[:,::1],int64,int64)')
def compute(AArr,width,height):
for x in range(width):
for y in range(height):
AArr[y,x] += laplaceNeighborDifference(AArr,height,y)
请注意,模量通常很慢。最好通过单独计算主循环的边界来删除它们。生成的代码应该快得多,没有任何模数。