对图像进行前向 FFT 和后向 FFT 以获得相同的结果

发布于 2024-12-10 07:22:40 字数 2561 浏览 1 评论 0原文

我正在尝试使用 http://www.fftw.org/ 中的库对图像进行 FFT,以便我可以在频域。但我不知道如何让它发挥作用。 为了了解如何执行此操作,我尝试将图像作为像素颜色数组进行前向 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,但我无法弄清楚它如何应用于我有代表图像的像素颜色数组的情况。

I am trying to FFT an image using the library from http://www.fftw.org/ so that I can do a convolution in the frequency domain. But I can't figure out how to make it work.
To understand how to do this I am trying to forward FFT an image as an array of pixelcolors and then backward FFT it to get the same array of pixelcolors. Here's what I do:

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];
    }
}

Could someone please show me an example of how to forward FFT an image and then backward FFT the image using FFTW to get the same result? I have been looking at a lot of examples showing how to use FFTW to FFT, but I can't figure out how it applies to my situation where I have an array of pixelcolors representing an Image.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

前事休说 2024-12-17 07:22:40

当您先进行正向 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 代码分开,并将其放入初始化例程或构造函数等中。

One important thing to note when you do forward FFT followed by inverse FFT is that this normally results in a scaling factor of N being applied to the final result, i.e. the resulting image pixel values will need to be divided by N in order to match the original pixel values. (N being the size of the FFT.) So your output loop should probably look something like this:

//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);
    }
}

Also note that you probably want to do a real-to-complex FFT followed by a complex-to-real IFFT (somewhat more efficient in terms of both memory and performance). For now though it looks like you're doing complex-to-complex in both directions, which is fine, but you're not filling your input arrays correctly. If you're going to stick with complex-to-complex then you probably want to change your input loop to something like this:

//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;
    }
}

i.e. the pixel values go into the real parts of the complex input values and the imaginary parts need to be zeroed.

One more thing to note: when you eventually get this working you'll find that performance is terrible - it takes a long time to create a plan relative to the time taken for the actual FFT. The idea is that you create the plan just once, but use it to perform many FFTs. So you'll want to separate out the plan creation from the actual FFT code and put it in an initialisation routine or constructor or whatever.

粉红×色少女 2024-12-17 07:22:40

但如果您使用 realToComplex 或 ComplexToRealFunction 请注意图像将存储在维度 [height x (width/2 +1)] 的矩阵中,并且如果您想在频域中进行一些中间计算,他们会变得更加困难......

But if you use the realToComplex or the ComplexToRealFunction pay attention to the fact that the image will be stored in a matrix of dimensions [height x (width/2 +1)] and if you want to do some intermediate calculations in the frequency domain, they will become a bit harder...

森末i 2024-12-17 07:22:40

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

The reason it didn't work is that fftw_plan_dft_2d() does some bench-marking to find the best algorithm and changes input data in the process, so you have to fill the input data after fftw_plan_dft_2d(), not before it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文