【问题标题】:Image Gaussian convolution in Fourier domain: works, while should't傅里叶域中的图像高斯卷积:有效,但不应该
【发布时间】:2015-12-17 04:12:13
【问题描述】:

问题是我无法完全理解频域卷积的原理。

我有一个image of size 256x256,我想与3x3 gaussian matrix 进行卷积。它的系数是(1/16, 1/8, 1/4):

PlainImage<float> FourierRunner::getGaussMask(int sz)
{
    PlainImage<float> G(3,3);
    *G.at(0, 0) = 1.0/16; *G.at(0, 1) = 1.0/8; *G.at(0, 2) = 1.0/16;
    *G.at(1, 0) = 1.0/8; *G.at(1, 1) = 1.0/4; *G.at(1, 2) = 1.0/8;
    *G.at(2, 0) = 1.0/16; *G.at(2, 1) = 1.0/8; *G.at(2, 2) = 1.0/16;
    return G;
}


为了获得图像和滤波器内核的 FFT,我对它们进行了零填充。 sz_common 代表扩展大小。图像和内核分别移动到hgComplexImages的中心,因此在右、左、下和上补零。


由于循环卷积属性,我已经读过尺寸应该是sz_common &gt;= sz+gsz-1:过滤器可以改变边界上不需要的图像值。
但它不起作用:只有当sz_common = szsz_common = sz+gsz-1sz_common = 2*sz 时,IFFT 后才能得到足够的结果,我得到的卷积图像要小 2-3 倍!
为什么?
我也很困惑过滤矩阵值应该乘以 256,比如像素值:关于 SO 的其他问题包含没有这种标准化的 Matlab 代码。与之前的情况一样,如果没有这样的乘法,它会很糟糕:我得到黑色图像。 为什么?
// fft_in 是移动傅里叶图像,中心在[sz/2;sz/2]
void FourierRunner::convolveImage(ComplexImage& fft_in)
{
    int sz = 256; // equal to fft_in.width()

    // Get original complex image (backward fft_in)
    ComplexImage original_complex = fft_in;
    fft2d_backward(fft_in, original_complex);

    int gsz = 3;
    PlainImage<float> filter = getGaussMask(gsz);
    ComplexImage filter_complex = ComplexImage::fromFloat(filter);

    int sz_common = pow2ceil(sz); // should be sz+gsz-1 ???

    ComplexImage h = ComplexImage::zeros(sz_common,sz_common);
    ComplexImage g = ComplexImage::zeros(sz_common,sz_common);

    copyImageToCenter(h, original_complex);
    copyImageToCenter(g, filter_complex);

    LOOP_2D(sz_common, sz_common) g.setPoint(x, y, g.at(x, y)*256);

    fft2d_forward(g, g);
    fft2d_forward(h, h);
    fft2d_fft_shift(g);

    // CONVOLVE
    LOOP_2D(sz_common,sz_common) h.setPoint(x, y, h.at(x, y)*g.at(x, y));

    copyImageToCenter(fft_in, h);
    fft2d_backward(fft_in, fft_in);
    fft2d_fft_shift(fft_in);

    // TEST DIFFERENCE BTW DOMAINS
    PlainImage<float> frequency_res(sz,sz);
    writeComplexToPlainImage(fft_in, frequency_res);

    fft2d_forward(fft_in, fft_in);
}

我尝试在右侧和底部对图像进行零填充,以便将较小的图像复制到较大的开头,但它也不起作用。
我在空间域中编写了卷积来比较结果,频率模糊结果几乎与空间域中的相同(平均误差 btw 像素为 5),仅当 sz_common = sz 时。


那么,您能解释一下这种情况下的零填充和归一化现象吗?提前致谢。

【问题讨论】:

    标签: c++ image-processing fft gaussian convolution


    【解决方案1】:

    空间域中的卷积相当于傅里叶域中的乘法。

    这是到处定义的连续函数的真相。
    然而在实践中,我们有离散信号和卷积核。
    需要更温柔的呵护。

    如果您有一个大小为 M x N 的图像和一个大小为 MM x NN 的内核,如果您对它们应用 DFT(FFT 是计算 DFT 的一种有效方法),您将获得大小为分别为 M x N 和 MM x NN。
    此外,上述定理,关于乘法等价性要求将相同的频率彼此相乘。

    由于实际上内核比图像小得多,因此通常将零填充到图像的大小。
    现在,通过应用 DFT,您将得到相同 M x N 大小的矩阵,并且能够将它们相乘。
    然而,这相当于图像和内核之间的循环卷积。

    要应用线性卷积,您应该使它们的大小都为 (M + MM - 1) x (N + NN - 1)。
    通常这是通过在图像上应用“复制”边界条件并对内核进行零填充。

    享受...

    附: 您能否在 http://area51.stackexchange.com/proposals/86832/ 支持新的 SE 社区提案。
    我们需要更多的人来关注,对少于 10 票的问题进行投票,并提出更多问题。

    谢谢。

    【讨论】:

      猜你喜欢
      • 2019-07-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多