简体   繁体   English

使用 FFT 实现二维卷积

[英]Implement 2D convolution using FFT

TensorFlow.conv2d() is impractically slow for convolving large images with large kernels (filters). TensorFlow.conv2d()在卷积具有大内核(过滤器)的大图像时速度慢得不切实际。 It takes a few minutes to convolve a 1024x1024 image with a kernel of the same size.使用相同大小的内核对 1024x1024 图像进行卷积需要几分钟时间。 For comparison, cv2.filter2D() returns the result immediately.为了进行比较, cv2.filter2D()立即返回结果。

I found tf.fft2() and tf.rfft() .我找到了tf.fft2()tf.rfft()

However it was not clear to me how to perform simple image filtering with these functions.但是,我不清楚如何使用这些函数执行简单的图像过滤。

How can I implement fast 2D image filtering with TensorFlow using FFT?如何使用 FFT 使用 TensorFlow 实现快速 2D 图像过滤?

A linear discrete convolution of the form x * y can be computed using convolution theorem and the discrete time Fourier transform (DTFT).可以使用卷积定理和离散时间傅立叶变换 (DTFT) 计算x * y形式的线性离散卷积。 If x * y is a circular discrete convolution than it can be computed with the discrete Fourier transform (DFT).如果x * y是圆形离散卷积,则可以使用离散傅立叶变换 (DFT) 进行计算。

The convolution theorem states x * y can be computed using the Fourier transform as卷积定理状态x * y可以使用傅立叶变换计算为

卷积定理

where在哪里傅里叶变换 denotes the Fourier transform and表示傅里叶变换和傅里叶逆变换 the inverse Fourier transform.傅里叶逆变换。 When x and y are discrete and their convolution is a linear convolution this is computed using the DTFT asxy是离散的并且它们的卷积是线性卷积时,这是使用 DTFT 计算的

离散卷积定理

If x and y are discrete and their convolution is a circular convolution the DTFT above is replaced by the DFT.如果xy是离散的并且它们的卷积是循环卷积,则上面的 DTFT 将被 DFT 替换。 Note: linear convolution problems can be embedded in circular convolution problems.注意:线性卷积问题可以嵌入到循环卷积问题中。


I'm more familiar with MATLAB but from reading the TensorFlow documentation for tf.signal.fft2d and tf.signal.ifft2d the solution below should be easily convertible to TensorFlow by replacing the MATLAB functions fft2 and ifft2 .我更熟悉 MATLAB,但通过阅读tf.signal.fft2dtf.signal.ifft2d的 TensorFlow 文档,下面的解决方案应该可以通过替换 MATLAB 函数fft2ifft2轻松转换为 TensorFlow。

In MATLAB (and TensorFlow) fft2 (and tf.signal.fft2d ) computes the DFT using the fast Fourier transform algorithm.在 MATLAB(和 TensorFlow)中, fft2 (和tf.signal.fft2d )使用快速傅立叶变换算法计算 DFT。 If the convolution of x and y is circular this can be computed by如果xy的卷积是圆形的,则可以通过以下方式计算

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

where .* represents element by element multiplication in MATLAB.其中.*表示 MATLAB 中逐个元素的乘法。 However, if it is linear then we zero pad the data to length 2N-1 where N is the length of one dimension (1024 in the question).但是,如果它是线性的,那么我们将数据零填充到长度2N-1 ,其中N是一维的长度(问题中的 1024)。 In MATLAB this can be computed one of two ways.在 MATLAB 中,这可以通过两种方式之一计算。 Firstly, by首先,通过

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

where MATLAB computes the 2*N-1 -point 2D Fourier transform of x and y by zero padding and then the 2*N-1 -point 2D inverse Fourier transform.其中 MATLAB 通过零填充计算xy2*N-1点二维傅立叶变换,然后是2*N-1点二维傅立叶逆变换。 This method can't be used in TensorFlow (from my understanding of the documentation) so the next is the only option.这个方法不能在 TensorFlow 中使用(根据我对文档的理解)所以 next 是唯一的选择。 In MATLAB and TensorFlow the convolution can be computed by first extending x and y to size 2*N-1 x 2*N-1 and then computing the 2*N-1 -point 2D Fourier transform and inverse Fourier transform在 MATLAB 和 TensorFlow 中,可以通过首先将xy扩展到2*N-1 x 2*N-1 ,然后计算2*N-1点二维傅里叶变换和傅里叶逆变换来计算卷积

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

In MATLAB, h and h_extended are exactly equal.在 MATLAB 中, hh_extended完全相等。 The convolution of x and y can be computed without the Fourier transform with xy的卷积可以在没有傅立叶变换的情况下计算

hC = conv2(x, y);

in MATLAB.在 MATLAB 中。


In MATLAB on my laptop conv2(x, y) takes 55 seconds whereas the Fourier transform approach takes less than 0.4 seconds.在我的笔记本电脑上的 MATLAB 中, conv2(x, y)需要 55 秒,而傅立叶变换方法需要不到 0.4 秒。

This can be done in a way similar to which for instance scipy.signal.fftconvolve is implemented.这可以通过类似于scipy.signal.fftconvolve实现的方式来完成。

Here is an example, assume we have an image (2 dimensions, if you have also multiple channels you can use the 3d instead of 2 functions) (im), and a filter (eg gaussian).这是一个例子,假设我们有一个图像(二维,如果你还有多个通道,你可以使用 3d 而不是 2 个函数)(im)和一个过滤器(例如高斯)。

First, take the Fourier transform of the image and define the fft_lenghts (useful if the filter is of a different shape, in which case it will get zero padded.)首先,对图像进行傅立叶变换并定义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])

Next, take the FFT of the filter (note, for instance for a 2d gaussian filter make sure the center is in the top left corner, ie use only a 'quarter')接下来,取滤波器的 FFT(注意,例如对于 2d 高斯滤波器,请确保中心位于左上角,即仅使用“四分之一”)

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

Finally, take the inverse transform back to get the convolved image最后取回逆变换得到卷积后的图像

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM