使用FFT实现2D卷积

时间:2018-05-21 17:38:04

标签: python image-processing tensorflow fft

对于使用大内核(过滤器)卷积大图像,

TensorFlow.conv2d()实际上很慢。将1024x1024图像与相同大小的内核进行卷积需要几分钟。为了进行比较,cv2.filter2D()会立即返回结果。

我找到了tf.fft2()tf.rfft()

然而,我不清楚如何使用这些功能执行简单的图像过滤。

如何使用FFT实现TensorFlow的快速2D图像滤波?

2 个答案:

答案 0 :(得分:2)

形式x * y的线性离散卷积可以使用卷积定理和离散时间傅立叶变换(DTFT)来计算。如果x * y是圆形离散卷积,则可以使用离散傅立叶变换(DFT)计算。

卷积定理状态x * y可以使用傅里叶变换计算

Convolution theorem

其中Fourier transform表示傅立叶变换,Inverse Fourier transform表示逆傅里叶变换。当xy是离散的并且它们的卷积是线性卷积时,这是使用DTFT计算的

Discrete convolution theorem

如果xy是离散的并且它们的卷积是循环卷积,则上面的DTFT将被DFT取代。 注意:线性卷积问题可以嵌入循环卷积问题中。

我对MATLAB更熟悉,但是通过阅读tf.fft2dtf.ifft2d的TensorFlow文档,下面的解决方案应该可以通过替换MATLAB函数fft2轻松转换为TensorFlow。 ifft2

在MATLAB(和TensorFlow)中fft2(和tf.fft2d)使用快速傅里叶变换算法计算DFT。如果xy的卷积是循环的,则可以通过

计算
ifft2(fft2(x).*fft2(y))

其中.*表示MATLAB中的逐元素乘法。但是,如果它是线性的,则必须计算DTFT。这可以通过将数据填充为零来计算长度为2N-1,其中N是一维的长度(问题中为1024)。在MATLAB中,这可以通过两种方式之一进行计算。首先,通过

h = ifft2(fft2(x, 2*N-1, 2*N-1).*fft2(y, 2*N-1, 2*N-1));

其中MATLAB通过零填充计算2*N-1 - 点xy的二维傅立叶变换,然后计算2*N-1 - 点二维傅里叶逆变换。这个方法不能在TensorFlow中使用(根据我对文档的理解),所以下一个是唯一的选择。在MATLAB和TensorFlow中,可以通过首先将xy扩展到大小2*N-1 x 2*N-1然后计算2*N-1 - 点2D傅里叶变换来计算卷积。和傅里叶逆变换

x_extended = x;
x_extended(2*N-1, 2*N-1) = 0;

y_extended = y;
y_extended(2*N-1, 2*N-1) = 0;

h_extended = ifft2(fft2(x_extended).*fft2(y_extended));

在MATLAB中,hh_extended完全相同。 xy的卷积可以在没有使用

的傅立叶变换的情况下计算
hC = conv2(x, y);

在MATLAB中。

在我的笔记本电脑conv2(x, y)上的MATLAB中需要55秒,而傅立叶变换方法需要不到0.4秒。

答案 1 :(得分:0)

这可以通过类似于实现scipy.signal.fftconvolve的方式来完成。

这里是一个例子,假设我们有一个图像(2维,如果您还有多个通道,则可以使用3d而不是2个功能)(im)和一个滤镜(例如高斯)。

首先,对图像进行傅立叶变换并定义fft_lenghts(如果滤镜的形状不同,则很有用,在这种情况下,滤镜的填充为零。)

fft_lenght1 = tf.shape(im)[0]
fft_lenght2 = tf.shape(im)[1]
im_fft = tf.signal.rfft2d(im, fft_length=[fft_lenght1, fft_lenght2])

接下来,对滤波器进行FFT(例如,对于2d高斯滤波器,请确保中心在左上角,即仅使用“四分之一”)

kernel_fft = tf.signal.rfft2d(kernel, fft_length=[fft_lenght1, fft_lenght2])

最后,进行逆变换以获取卷积图像

im_blurred = tf.signal.irfft2d(im_fft * kernel_fft, [fft_lenght1, fft_lenght2])