用FFT实现二维卷积
问题描述
TensorFlow.conv2d()
对于卷积大图像和大核(滤镜)来说,速度非常慢。将1024x1024图像与相同大小的内核进行卷积需要几分钟时间。为了进行比较,cv2.filter2D()
立即返回结果。
我找到tf.fft2()
和tf.rfft()
。
但是,我不清楚如何使用这些函数执行简单的图像过滤。
如何使用FFT使用TensorFlow实现快速2D图像过滤?
解决方案
x * y
形式的线性离散卷积可以使用卷积定理和离散时间傅里叶变换计算。如果x * y
是圆形离散卷积,则可以使用离散傅里叶变换(DFT)进行计算。
卷积定理状态x * y
可以使用傅里叶变换计算为
其中表示傅里叶变换和傅立叶逆变换。当x
和y
是离散的并且它们的卷积是线性卷积时,这是使用DTFT计算的
x
和y
是离散的,并且它们的卷积是循环卷积,则用DFT代替上面的DTFT。注意:线性卷积问题可以嵌入到循环卷积问题中。
我对MatLab比较熟悉,但通过阅读tf.signal.fft2d
和tf.signal.ifft2d
的TensorFlow文档,下面的解决方案应该可以通过替换MatLab函数fft2
和ifft2
轻松转换为TensorFlow。
(和TensorFlow)fft2
(和tf.signal.fft2d
)使用快速傅立叶变换算法计算DFT。如果x
和y
的卷积是循环的,则可以通过
ifft2(fft2(x).*fft2(y))
其中.*
表示在MatLab中逐个元素相乘。然而,如果它是线性的,那么我们将数据零填充到长度2N-1
,其中N
是一维的长度(在问题中是1024)。在MatLab中,这可以用两种方法之一来计算。首先,由
h = ifft2(fft2(x, 2*N-1, 2*N-1).*fft2(y, 2*N-1, 2*N-1));
其中,MatLab通过填零来计算x
和y
的2*N-1
点2D傅立叶变换,然后计算2*N-1
点2D逆傅立叶变换。此方法不能在TensorFlow中使用(根据我对文档的理解),因此下一步是唯一的选择。在MatLab和TensorFlow中,可以通过首先将x
和y
扩展到大小2*N-1
x2*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中,h
和h_extended
完全相等。x
和y
的卷积可以在不进行傅里叶变换的情况下计算
hC = conv2(x, y);
在MatLab中。
在我笔记本电脑上的MatLab中conv2(x, y)
需要55秒,而傅里叶变换方法只需不到0.4秒。
相关文章