【发布时间】:2017-11-15 11:04:02
【问题描述】:
我正在尝试使用 pyfftw 来实现模仿 scipy.fftconvolve 的 FFT 卷积,以获得性能和图片作为输入:
import numpy as np
import pyfftw
a = np.ones((6000, 4000), dtype='float32')
b = np.kaiser(25, 8)
b = np.outer(b, b).astype('float32')
class fftconvolve:
def __init__(self, A, B, domain, threads=8):
MK = B.shape[0]
NK = B.shape[1]
M = A.shape[0]
N = A.shape[1]
if domain =="same":
Y = M
X = N
elif domain == "valid":
Y = M - MK + 1
X = N - NK + 1
elif domain == "full":
Y = M + MK - 1
X = N + NK - 1
self.fft_A_obj = pyfftw.builders.rfft2(A, s=(M + MK -1, N + NK -1), threads=threads)
self.fft_B_obj = pyfftw.builders.rfft2(B, s=(M + MK -1, N + NK -1), threads=threads)
self.ifft_obj = pyfftw.builders.irfft2(self.fft_A_obj.output_array, s=(Y, X), threads=threads)
def __call__(self, A, B):
return self.ifft_obj(np.fft.ifftshift(
np.fft.fftshift(self.fft_A_obj(A)) * np.fft.fftshift(self.fft_B_obj(B))
))
调用它:
plan = fftconvolve(a, b, "full", threads=8)
c_1 = plan(a, b)
c_1
输出:
array([[ 3.89971137e-06, 3.51986018e-05, 1.24518745e-04, ...,
1.25271297e-04, 3.56316777e-05, 4.04627326e-06],
[ 4.91737483e-05, 2.60021159e-04, 8.61040782e-04, ...,
8.63055116e-04, 2.61142646e-04, 4.95371969e-05],
[ 1.26523402e-04, 8.49825097e-04, 2.90915114e-03, ...,
2.90881563e-03, 8.49568460e-04, 1.26304061e-04],
...,
[ 1.28503540e-04, 8.52331228e-04, 2.91197700e-03, ...,
2.91016186e-03, 8.51134886e-04, 1.28111642e-04],
[ 2.14206957e-05, 2.32703838e-04, 8.34190170e-04, ...,
8.34319100e-04, 2.32750244e-04, 2.14206957e-05],
[ -8.42595455e-06, 2.29651105e-05, 1.12404508e-04, ...,
1.12760317e-04, 2.31778213e-05, -8.35505125e-06]], dtype=float32)
调用 scipy 等效项:
c_2 = scipy.signal.fftconvolve(a, b, "full").astype(np.float32)
c_2
输出:
array([[ 5.47012860e-06, 3.68362089e-05, 1.26135841e-04, ...,
1.26135841e-04, 3.68362089e-05, 5.47012769e-06],
[ 3.68362089e-05, 2.48057506e-04, 8.49407224e-04, ...,
8.49407224e-04, 2.48057506e-04, 3.68362089e-05],
[ 1.26135841e-04, 8.49407224e-04, 2.90856976e-03, ...,
2.90856976e-03, 8.49407224e-04, 1.26135841e-04],
...,
[ 1.26135841e-04, 8.49407224e-04, 2.90856976e-03, ...,
2.90856976e-03, 8.49407224e-04, 1.26135841e-04],
[ 3.68362089e-05, 2.48057506e-04, 8.49407224e-04, ...,
8.49407224e-04, 2.48057506e-04, 3.68362089e-05],
[ 5.47012814e-06, 3.68362089e-05, 1.26135841e-04, ...,
1.26135841e-04, 3.68362089e-05, 5.47012814e-06]], dtype=float32)
检查输出:
c_1 == c_2
给:
array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]], dtype=bool)
还有:
np.allclose(c_1, c_2)
给:
False
所以输出不正确。删除 fftshift 并不会改变任何事情。
在我的project 中,scipy 版本给出了正确的图像,我实现的 pyfftw 给出了模糊的输出。
编辑
我也在 double 类型 (np.float64) 中进行了测试,虽然卷积的原始结果足够接近(实际上,scipy 将卷积进行了两倍),但图片仍然很糟糕:
在这里使用自定义卷积进行反卷积:它不仅模糊,而且边缘会出现条纹:
a = np.ones((6000, 4000), dtype='float64')
b = np.kaiser(25, 8)
b = np.outer(b, b).astype('float64')
现在:
np.allclose(c_1, c_2)
返回:
True
什么可以给出这个结果?
【问题讨论】:
-
顺便说一句,这是比较浮点数组的错误方法,请参阅docs.scipy.org/doc/numpy-1.13.0/reference/generated/…
-
谢谢@IgnacioVergaraKausel,我不知道这个
-
由于许可证问题,SciPy 不使用
fftw,而是使用fftpack。因此,可能存在实现差异,很可能在转换等前面有一个标量1/sqrt(n)。顺便说一下,你不需要一个类来做到这一点。这只是一个函数。 -
似乎 FFTW 会自动对 FFT 进行标准化,因此 ifft(fft(a)) = a.此外,pyfftw 在转换之前进行规划的方式使得类变得必要,fft 构建器不是 ufunc 而是内存规划器。
-
如果该部分仍然相关,您应该使用 allclose 函数更新问题。在我看来,使用 pyfftw 您会观察到一个伪影,很可能是包装中的问题。测试用正弦或余弦等更简单的东西会发生什么。
标签: python scipy convolution fftw pyfftw