【问题标题】:Forward FFT an image and backward FFT an image to get the same result前向 FFT 图像和后向 FFT 图像以获得相同的结果
【发布时间】:2011-12-09 02:31:21
【问题描述】:

我正在尝试使用来自http://www.fftw.org/ 的库对图像进行 FFT,以便我可以在频域中进行卷积。但我不知道如何使它工作。 为了理解如何做到这一点,我试图将图像转发为像素颜色数组,然后向后 FFT 以获得相同的像素颜色数组。这是我的工作:

fftw_plan planR, planG, planB;
fftw_complex *inR, *inG, *inB, *outR, *outG, *outB, *resultR, *resultG, *resultB;

//Allocate arrays.
inR = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * width * width);
inG = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * width * width);
inB = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * width * width);

outR = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * width * width);
outG = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * width * width);
outB = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * width * width);

resultR = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * width * width);
resultG = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * width * width);
resultB = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * width * width);

//Fill in arrays with the pixelcolors.
for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x++) {
        int currentIndex = ((y * width) + (x)) * 3;
        inR[y * width + x][0] = pixelColors[currentIndex];
        inG[y * width + x][0] = pixelColors[currentIndex + 1];
        inB[y * width + x][0] = pixelColors[currentIndex + 2];
    }
}

//Forward plans.
planR = fftw_plan_dft_2d(width, width, inR, outR, FFTW_FORWARD, FFTW_MEASURE);
planG = fftw_plan_dft_2d(width, width, inG, outG, FFTW_FORWARD, FFTW_MEASURE);
planB = fftw_plan_dft_2d(width, width, inB, outB, FFTW_FORWARD, FFTW_MEASURE);

//Forward FFT.
fftw_execute(planR);
fftw_execute(planG);
fftw_execute(planB);

//Backward plans.
planR = fftw_plan_dft_2d(width, width, outR, resultR, FFTW_BACKWARD, FFTW_MEASURE);
planG = fftw_plan_dft_2d(width, width, outG, resultG, FFTW_BACKWARD, FFTW_MEASURE);
planB = fftw_plan_dft_2d(width, width, outB, resultB, FFTW_BACKWARD, FFTW_MEASURE);

//Backward fft
fftw_execute(planR);
fftw_execute(planG);
fftw_execute(planB);

//Overwrite the pixelcolors with the result.
for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x++) {
        int currentIndex = ((y * width) + (x)) * 3;
        pixelColors[currentIndex] = resultR[y * width + x][0];
        pixelColors[currentIndex + 1] = resultG[y * width + x][0];
        pixelColors[currentIndex + 2] = resultB[y * width + x][0];
    }
}

有人可以向我展示一个如何转发 FFT 图像然后使用 FFTW 向后 FFT 图像以获得相同结果的示例吗?我一直在查看很多示例,展示如何使用 FFTW 到 FFT,但我无法弄清楚它如何应用于我的情况,即我有一个代表图像的像素颜色数组。

【问题讨论】:

    标签: c++ c image-processing fft fftw


    【解决方案1】:

    在进行正向 FFT 和反向 FFT 时需要注意的重要一点是,这通常会导致将 N 的比例因子应用于最终结果,即最终的图像像素值需要按顺序除以 N以匹配原始像素值。 (N 是 FFT 的大小。)所以你的输出循环应该看起来像这样:

    //Overwrite the pixelcolors with the result.
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            int currentIndex = ((y * width) + (x)) * 3;
            pixelColors[currentIndex] = resultR[y * width + x][0] / (width * height);
            pixelColors[currentIndex + 1] = resultG[y * width + x][0] / (width * height);
            pixelColors[currentIndex + 2] = resultB[y * width + x][0] / (width * height);
        }
    }
    

    另请注意,您可能希望先执行实数到复数 FFT,然后执行复数到实数 IFFT(在内存和性能方面更有效)。现在虽然看起来你在两个方向上都在做复杂到复杂的事情,这很好,但是你没有正确地填充你的输入数组。如果您要坚持使用复杂到复杂,那么您可能希望将输入循环更改为以下内容:

    //Fill in arrays with the pixelcolors.
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            int currentIndex = ((y * width) + (x)) * 3;
            inR[y * width + x][0] = (double)pixelColors[currentIndex];
            inR[y * width + x][1] = 0.0;
            inG[y * width + x][0] = (double)pixelColors[currentIndex + 1];
            inG[y * width + x][1] = 0.0;
            inB[y * width + x][0] = (double)pixelColors[currentIndex + 2];
            inB[y * width + x][1] = 0.0;
        }
    }
    

    即像素值进入复数输入值的实部,虚部需要归零。

    还有一点需要注意:当您最终完成这项工作时,您会发现性能很糟糕 - 相对于实际 FFT 所花费的时间,制定计划需要很长时间。这个想法是您只创建一次计划,但使用它来执行许多 FFT。因此,您需要将计划创建与实际 FFT 代码分开,并将其放入初始化例程或构造函数或其他任何内容中。

    【讨论】:

      【解决方案2】:

      但是,如果您使用 realToComplex 或 ComplexToRealFunction,请注意图像将存储在尺寸为 [height x (width/2 +1)] 的矩阵中,并且如果您想在频域,他们会变得有点难......

      【讨论】:

        【解决方案3】:

        它不起作用的原因是 fftw_plan_dft_2d() 进行了一些基准测试以找到最佳算法并在此过程中更改输入数据,因此您必须在 fftw_plan_dft_2d() 之后填充输入数据,而不是之前。

        【讨论】:

        • 确实如此。另一种选择是使用FFTW_ESTIMATE 而不是FFTW_MEASURE,这样数组就不会被覆盖。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-03-15
        • 1970-01-01
        • 2017-09-28
        • 1970-01-01
        • 1970-01-01
        • 2015-11-16
        • 2016-05-03
        相关资源
        最近更新 更多