使用fftconvolve

时间:2017-04-19 19:52:07

标签: python numpy scipy fft correlation

我有一组2D数组,我必须计算其2D相关性。我一直在尝试许多不同的东西(甚至在Fortran中编程),但我认为最快的方法是使用FFT计算它。

根据我的测试和this answer,我可以使用scipy.signal.fftconvolve,如果我尝试使用scipy.signal.correlate2d重现boundary='fill'的输出,则效果很好。所以基本上这个

scipy.signal.fftconvolve(a, a[::-1, ::-1], mode='same')

等于此(除了轻微的移位)

scipy.signal.correlate2d(a, a, boundary='fill', mode='same')

问题是数组应该以包装模式计算,因为它们是2D周期数组(即boundary='wrap')。所以,如果我试图重现

的输出
scipy.signal.correlate2d(a, a, boundary='wrap', mode='same')

我不能,或者至少我不知道该怎么做。 (我想使用FFT方法,因为它的速度更快。)

显然,Scipy曾经有something like that可能已经完成了这个伎俩,但显然它已经落后了我无法找到它,所以我认为Scipy可能会放弃对它的支持。

无论如何,有没有办法使用scipynumpy的FFT例程来计算周期数组的这种相关性?

1 个答案:

答案 0 :(得分:2)

可以使用FFT实现包装的相关性。这里有一些代码来演示如何:

In [276]: import numpy as np

In [277]: from scipy.signal import correlate2d

创建一个随机数组a以使用:

In [278]: a = np.random.randn(200, 200)

使用scipy.signal.correlate2d

计算2D相关性
In [279]: c = correlate2d(a, a, boundary='wrap', mode='same')

现在使用numpy.fft中的2D FFT函数计算相同的结果。 (此代码假定a是正方形。)

In [280]: from numpy.fft import fft2, ifft2

In [281]: fc = np.roll(ifft2(fft2(a).conj()*fft2(a)).real, (a.shape[0] - 1)//2, axis=(0,1))

验证两种方法都给出相同的结果:

In [282]: np.allclose(c, fc)
Out[282]: True

正如您所指出的,使用FFT的速度很多。对于这个例子,它快了大约1000倍:

In [283]: %timeit c = correlate2d(a, a, boundary='wrap', mode='same')
1 loop, best of 3: 3.2 s per loop

In [284]: %timeit fc = np.roll(ifft2(fft2(a).conj()*fft2(a)).real, (a.shape[0] - 1)//2, axis=(0,1))
100 loops, best of 3: 3.19 ms per loop

这包括fft2(a)的重复计算。当然,fft2(a)只应计算一次:

In [285]: fta = fft2(a)

In [286]: fc = np.roll(ifft2(fta.conj()*fta).real, (a.shape[0] - 1)//2, axis=(0,1))