5

我有一个使用常规卷积的当前高斯模糊实现。它对于小内核来说足够高效,但是一旦内核大小变大一点,性能就会受到影响。所以,我正在考虑使用 FFT 实现卷积。我从来没有任何与 FFT 相关的图像处理的经验,所以我有几个问题。

  1. 基于 2D FFT 的卷积是否也可以分成两个 1D 卷积?

    • 如果是真的,它是这样的吗 - 每行的 1D FFT,然后每列的 1D FFT,然后乘以 2D 内核,然后每列的逆变换和每行的逆变换?或者我是否必须在每次一维 FFT 变换后乘以一维内核?
  2. 现在我明白内核大小应该与图像大小相同(一维的情况下为行)。但它将如何影响边缘?我必须用零填充图像边缘吗?如果是这样,内核大小应该等于填充之前或之后的图像大小?

另外,这是一个 C++ 项目,我打算使用 KissFFT,因为这是一个商业项目。欢迎您提出任何更好的替代方案。谢谢你。

编辑:感谢您的回复,但我还有一些问题。

  1. 我看到输入图像的虚部将全为零。但是输出虚部也会为零吗?我是否必须将高斯核乘以实部和虚部?

  2. 我有相同图像的实例以不同的比例模糊,即相同的图像被缩放到不同的大小并在不同的内核大小下模糊。每次缩放图像时都必须执行 FFT,还是可以使用相同的 FFT?

  3. 最后,如果我想可视化 FFT,我知道必须将日志过滤器应用于 FFT。但是我真的迷失了应该使用哪个部分来可视化 FFT?实部或虚部。

  4. 同样对于大小为 512x512 的图像,实部和虚部的大小是多少。它们的长度会一样吗?

再次感谢您的详细回复。

4

2 回答 2

12
  1. 2-D FFT 是可分离的,除了必须乘以 2D 内核的 2-D FFT 之外,您在如何执行它方面是正确的。如果您使用的是 Kissfft,执行 2-D FFT 的更简单方法是kiss_fftnd在 Kissfft 包的工具目录中使用。这将执行多维 FFT。

  2. 内核大小不必是任何特定大小。如果内核小于图像,则只需在执行 2-D FFT 之前将零填充到图像大小。您还应该对图像边缘进行零填充,因为在频域中通过乘法执行的卷积实际上是循环卷积,并且结果在边缘处环绕。

总结一下(假设图像大小为 M x N):

  1. 提出任意大小 (U x V) 的二维内核
  2. 将内核补零至 (M+U-1) x (N+V-1)
  3. 取内核的二维 fft
  4. 将图像补零至 (M+U-1) x (N+V-1)
  5. 获取图像的二维 FFT
  6. 将内核的 FFT 乘以图像的 FFT
  7. 取结果的逆二维 FFT
  8. 修剪边缘的垃圾

如果您对不同的图像多次执行相同的过滤器,则不必每次执行 1-3 次。

注意: 内核大小必须相当大,才能比直接计算卷积更快。另外,您是否利用二维高斯滤波器是可分离的这一事实实现了直接卷积(请参阅“力学”部分的这几段)?也就是说,您可以在行和列上执行二维卷积作为一维卷积。我发现这比大多数基于 FFT 的方法要快,除非内核非常大。

对编辑的回应

  1. 如果输入是真实的,那么除了极少数情况外,输出仍然会很复杂。您的高斯核的 FFT 也将是复数,因此乘法必须是复数乘法。当您执行逆 FFT 时,输出应该是真实的,因为您的输入图像和内核是真实的。输出将以复数数组的形式返回,但虚数部分应为零或非常小(浮点误差)并且可以丢弃。

  2. 如果您使用相同的图像,您可以重用图像 FFT,但您需要根据您的最大内核大小进行零填充。您将必须计算所有不同内核的 FFT。

  3. 对于可视化,应使用复数输出的幅度。当较大的组件会以线性比例淹没它们时,对数刻度仅有助于可视化输出的较小组件。分贝标度经常被使用,并且由等效的20*log10(abs(x))10*log10(x*x')等效的任何一个给出。(x是复数 fft 输出并且x'是 的复数共轭x)。

  4. FFT 的输入和输出大小相同。此外,实部和虚部的大小相同,因为一个实部和一个虚部形成一个样本。

于 2011-08-16T14:40:53.727 回答
5

请记住,空间中的卷积相当于频域中的乘法。这意味着一旦您对图像和掩码(内核)执行 FFT,您只需进行逐点乘法,然后对结果进行 IFFT。话虽如此,这里有几句话要小心。

您可能知道,在数字信号处理中,我们经常使用循环卷积,而不是线性卷积。这是因为奇怪的周期性。简而言之,这意味着 DFT(以及 FFT 是其计算效率高的变体)假设您的信号是周期性的,并且当您以这种方式过滤信号时 - 假设您的图像是N x M像素 - 它需要对于某些m < M _ _ _ _ _. 您的信号几乎环绕在自身上。这意味着您的高斯蒙版将平均最右边的像素和最左边的像素,顶部和底部也是如此。这可能需要也可能不需要,但总的来说,无论如何都必须处理边缘伪影。然而,在处理 FFT 乘法时更容易忘记这个问题,因为问题不再明显。有很多方法可以解决这个问题。最好的方法是简单地用零填充您的图像,然后删除多余的像素。

在频域中使用高斯滤波器的一个非常巧妙的事情是,您永远不必真正采用它的 FFT。众所周知,高斯的傅里叶变换是高斯的(这里有一些技术细节)。然后你所要做的就是用零(顶部和底部)填充你的图像,在频域中生成一个高斯,将它们相乘并进行 IFFT。然后你就完成了。

希望这可以帮助。

于 2011-08-16T14:49:08.633 回答