8

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に使用する方法を示す多くの例を見てきましたが、画像を表すピクセルカラーの配列がある私の状況にそれがどのように適用されるかを理解できません。

4

3 に答える 3

16

順方向FFTの後に逆方向FFTを実行する場合、注意すべき重要な点の1つは、通常、最終結果に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;
    }
}

つまり、ピクセル値は複素数入力値の実数部に入り、虚数部はゼロにする必要があります。

もう1つ注意すべき点は、最終的にこれが機能するようになると、パフォーマンスがひどいことに気付くでしょう。実際のFFTにかかる時間に比べて、計画の作成には長い時間がかかります。計画は一度だけ作成し、それを使用して多くのFFTを実行するという考え方です。したがって、プランの作成を実際のFFTコードから分離し、初期化ルーチンやコンストラクターなどに配置する必要があります。

于 2011-10-17T08:21:36.513 に答える
2

ただし、realToComplexまたはComplexToRealFunctionを使用する場合は、画像が次元の行列[height x(width / 2 +1)]に格納されることに注意してください。また、周波数領域で中間計算を実行する場合は、彼らは少し難しくなります...

于 2011-10-18T07:40:18.177 に答える
2

それが機能しなかった理由は、fftw_plan_dft_2d()がいくつかのベンチマークを実行して最適なアルゴリズムを見つけ、プロセスで入力データを変更するため、入力データをfftw_plan_dft_2d()の前ではなく、後に入力する必要があるためです。

于 2020-09-17T05:09:17.583 に答える