2017-04-19 52 views
0

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

基于我的测试和this answer我可以使用scipy.signal.fftconvolve,它工作正常,如果我试图重现scipy.signal.correlate2dboundary='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可能已经放弃了对它的支持。

无论如何,有没有办法使用scipy's或numpy的FFT例程来计算周期数组的相关性?

+0

你的'a'看起来怎么样? – kmario23

+0

@ kmario23这是私人实验数据,所以我不能在这里分享。但是它是200x200的数组,它们在x和y中是周期性的。 – TomCho

+1

我目前没有很好的答案,但是你提到的“遗留”代码可以在这里找到(https://github.com/scipy/scipy/blob/maintenance/0.7。X/SciPy的/ STScI提供/卷积/ LIB/Convolve.py#L144) – jakevdp

回答

1

包装的相关性可以使用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的二维相关:

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))