基于FFT的Python二维卷积与相关性

24 投票
6 回答
40844 浏览
提问于 2025-04-15 12:46

有没有基于快速傅里叶变换(FFT)的二维交叉相关或卷积函数,内置在scipy(或其他流行的库)中?

有一些这样的函数:

  • scipy.signal.correlate2d - “直接使用convolveND的方法在处理大数据时会很慢。”
  • scipy.ndimage.correlate - “这个数组会和给定的核进行精确计算的相关(也就是说,不使用FFT)。”
  • scipy.fftpack.convolve.convolve,我不是很明白,但感觉好像不太对。

numarray曾经有一个correlate2d()函数,带有fft=True的选项,但我猜numarray已经合并到numpy里了,我找不到这个函数是否被包含在内。

6 个回答

5

我觉得你想要的是scipy.stsci这个包:

http://docs.scipy.org/doc/scipy/reference/stsci.html

In [30]: scipy.__version__
Out[30]: '0.7.0'

In [31]: from scipy.stsci.convolve import convolve2d, correlate2d
8

你可以看看scipy库里的几个函数,比如fftconvolve、convolve和correlate。还有一个叫signal.correlate2d的函数,不过它返回的数组好像是偏移的,而不是居中的。

25

我发现了 scipy.signal.fftconvolve,正如 magnus 也提到过的,但当时没意识到它是支持多维的。因为这个函数是内置的,并且能产生正确的结果,所以看起来是个理想的解决方案。

来自 二维卷积的例子

In [1]: a = asarray([[ 1, 2, 3],
   ...:              [ 4, 5, 6],
   ...:              [ 7, 8, 9]])

In [2]: b = asarray([[-1,-2,-1],
   ...:              [ 0, 0, 0],
   ...:              [ 1, 2, 1]])

In [3]: scipy.signal.fftconvolve(a, b, mode = 'same')
Out[3]: 
array([[-13., -20., -17.],
       [-18., -24., -18.],
       [ 13.,  20.,  17.]])

没错!而 STSCI 版本则需要额外的工作来处理边界问题,对吧?

In [4]: stsci.convolve2d(a, b, fft = True)
Out[4]: 
array([[-12., -12., -12.],
       [-24., -24., -24.],
       [-12., -12., -12.]])

(STSCI 方法还需要编译,我尝试过但没成功(我只是把非 Python 的部分注释掉了),还有一些 bug,比如 这个,以及输入需要修改(比如 [1, 2] 变成 [[1, 2]])等等。所以我把我之前认可的答案改成了内置的 fftconvolve() 函数。)

当然,相关性和卷积是一样的,只不过一个输入是反向的:

In [5]: a
Out[5]: 
array([[3, 0, 0],
       [2, 0, 0],
       [1, 0, 0]])

In [6]: b
Out[6]: 
array([[3, 2, 1],
       [0, 0, 0],
       [0, 0, 0]])

In [7]: scipy.signal.fftconvolve(a, b[::-1, ::-1])
Out[7]: 
array([[ 0., -0.,  0.,  0.,  0.],
       [ 0., -0.,  0.,  0.,  0.],
       [ 3.,  6.,  9.,  0.,  0.],
       [ 2.,  4.,  6.,  0.,  0.],
       [ 1.,  2.,  3.,  0.,  0.]])

In [8]: scipy.signal.correlate2d(a, b)
Out[8]: 
array([[0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0],
       [3, 6, 9, 0, 0],
       [2, 4, 6, 0, 0],
       [1, 2, 3, 0, 0]])

而且 最新的版本通过使用二的幂的大小在内部加快了速度(然后我通过 对真实输入使用真实 FFT使用 5 平滑长度而不是 2 的幂 进一步加快了速度 :D)。

撰写回答