使用FFT进行高斯模糊的问题

5

我目前有一个使用常规卷积实现的高斯模糊。对于小核,它是足够高效的,但一旦核的大小变大,性能就会下降。因此,我考虑使用FFT来实现卷积。我以前没有任何FFT相关的图像处理经验,所以我有几个问题。

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

    • 如果是,是这样进行的吗 - 对每行进行1D FFT,然后对每列进行1D FFT,再与2D内核相乘,然后对每列进行逆变换和每行的逆变换?还是每个1D FFT变换后都要乘以一个1D内核?
  2. 现在我明白内核大小应该与图像大小相同(在1D情况下为行)。但这会如何影响边缘?我必须用零填充图像边缘吗?如果是,那么内核大小应该在填充之前或之后与图像大小相同吗?

另外,这是一个C++项目,我计划使用kissFFT,因为这是一个商业项目。如果你有更好的替代方案,请提出建议。谢谢。

编辑:感谢回复,但我还有几个问题。

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

  2. 我需要对不同尺度的相同图像进行模糊处理,即将相同的图像缩放到不同的尺寸并使用不同的核大小进行模糊处理。每次缩放图像时,我必须进行FFT操作吗?还是可以使用相同的FFT?

  3. 最后,如果我想要可视化FFT,我理解必须应用对数滤波器来进行FFT。但是我真的不知道应该使用哪一部分来可视化FFT?实部还是虚部。

  4. 另外,对于512x512的图像,实部和虚部的大小将是多少?它们的长度将相同吗?

再次感谢您详细的回复。


请问如何在Python中获取当前文件的目录? - Joe'
2个回答

12
  1. 2维FFT是可分离的,并且您在执行它时是正确的,除了您必须乘以2D核的2维FFT。如果您使用kissfft,执行2维FFT的更简单方法是只需使用kissfft包中的tools目录中的。这将执行多维FFT。

  2. 核大小不必是任何特定大小。如果核比图像小,则在执行2D FFT之前需要用零填充到图像大小。由于在频域中执行的卷积实际上是循环卷积并且结果在边缘处绕组,因此还应该将图像边缘填零。

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

  1. 创建任意大小的2维核(U x V)
  2. 将核用零填充到(M+U-1) x (N+V-1)
  3. 对核进行2D FFT
  4. 将图像用零填充到(M+U-1) x (N+V-1)
  5. 对图像进行2D FFT
  6. 将核的FFT与图像的FFT相乘
  7. 对结果进行逆2D FFT
  8. 裁剪掉边缘垃圾

如果您要在不同的图像上多次执行相同的滤波器,则不必每次执行1-3步骤。

注意: 为了比直接计算卷积更快,内核大小必须相当大。此外,你是否利用2D高斯滤波器是可分离的这个事实来实现你的直接卷积(参见本文“机制”部分的几段话)?也就是说,你可以将2D卷积作为行上的1D卷积,然后再进行列上的1D卷积。我发现除非内核很大,否则这比大多数基于FFT的方法要快。

对编辑的回应:

  1. 如果输入是实数,则输出仍将是复数,除非在极少数情况下。高斯核的FFT也将是复数,因此乘法必须是一个复数乘法。当执行逆FFT时,输出应该是实数,因为你的输入图像和内核是实数。输出将以复杂数组的形式返回,但虚部应该是零或非常小的(浮点误差),可以舍弃。

  2. 如果你正在使用同一图像,则可以重复使用图像FFT,但你需要根据最大内核大小进行零填充。你将不得不计算所有不同内核的FFT。

  3. 用于可视化的是复杂输出的幅度。对数比例只是在线性比例下更大的分量会淹没小分量时,帮助可视化输出的较小组成部分。分贝刻度经常被使用,由20*log10(abs(x))10*log10(x*x')给出,它们是等效的。(x是复FFT输出,x'x的复共轭)。

  4. FFT的输入和输出大小相同。同时实部和虚部大小相同,因为一个实数和一个虚数值组成一个样本。


谢谢您的回复。现在我明白FFT变换由'Real'和'Imaginary'两部分组成。假设我有一张512x512的图像,那么'Real'和'Imaginary'两部分的大小会是多少呢?我需要将它们都乘以卷积核的FFT吗? - rwb
请查看我在问题中的编辑。谢谢。 - rwb
谢谢您的回复。因此,图像的FFT即使缩放也不会改变。非常感谢您提供的信息。 - rwb
抱歉,我可能误解了。如果您正在缩放图像,则需要再次执行FFT。 - Jason B

5

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

你可能知道,在数字信号处理中,我们经常使用循环卷积而不是线性卷积。这是由于奇特的周期性。简单来说,这意味着DFT(以及其计算效率更高的FFT)假定您的信号是周期性的,并且当您以这种方式过滤信号时——假设您的图像为N x M像素——它将在某个m<M处取像素(1,m)到相邻的像素(Nm)。您的信号实际上会围绕自身旋转。这意味着您的高斯掩模将对最右侧的像素和最左侧的像素进行平均,顶部和底部也是如此。这可能是期望的,也可能不是期望的,但通常必须处理边缘伪影。然而,当处理FFT乘法时,很容易忘记这个问题,因为问题不再明显。有许多方法来解决这个问题。最好的方法是用零填充图像,稍后再删除额外的像素。
在频域中使用高斯滤波器的一个很好的特点是你不需要真正进行傅里叶变换。众所周知,高斯函数的傅里叶变换是高斯函数(一些技术细节 在此)。那么你要做的就是在图像上下两端填充零,生成频域中的高斯函数,将它们相乘并进行IFFT。然后你就完成了。
希望这有所帮助。

感谢您的回复。请查看我在问题中的编辑。 - rwb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接