//編集...
特に2の累乗以外の画像を操作する問題に対処するために、質問を少し編集しています。256x256や1024x1024のようなサイズの正方形のグレースケール画像で機能する基本構造がありますが、任意のサイズの画像に一般化する方法がわかりません。fft関数では、幅と高さのlog2を含める必要があるようですが、結果のデータを解凍する方法や、データがスクランブルされているだけではないかどうかが不明です。明らかなことは、npot画像をより大きな、すべて黒の画像の中央に配置し、データを見るときにそれらの位置の値を無視することだと思います。しかし、npotデータを操作するためのそれほど厄介な方法があるかどうか疑問に思います。
//...編集終了
AccelerateFrameworkのドキュメントに少し問題があります。通常はFFTW3を使用しますが、実際のIOSデバイスでコンパイルするのに問題があります(この質問を参照)。誰かが私に次のようなことをするAccelerateを使用した非常に単純な実装を指摘できますか?
1)画像データをAccelerateのFFTメソッドに渡すことができる適切なデータ構造に変換します。
FFTW3では、最も単純な場合、グレースケールイメージを使用して、符号なしバイトを「fftw_complex」配列に配置します。これは、2つのfloatの構造体であり、1つは実数値を保持し、もう1つは虚数(および虚数はピクセルごとにゼロに初期化されます)。
2)このデータ構造を取得し、FFTを実行します。
3)振幅と位相を出力します。
4)その上でIFFTを実行します。
5)IFFTの結果のデータから元の画像を再作成します。
これは非常に基本的な例ですが、Appleのサイトのドキュメントを使用するのに問題があります。ここでのPiによるSOの回答は非常に役立ちますが、グレースケール(またはカラー)2D画像を使用してこの基本機能を実行するためにAccelerateを使用する方法についてはまだ多少混乱しています。
とにかく、2D画像を処理するポインタや特にいくつかの単純な作業コードは非常に役立ちます!
\\\ 編集 \\\
さて、ドキュメントとSOおよびpkmitalのgithubリポジトリに関するいくつかの非常に役立つコードを詳しく調べた後、1)から理解するのに時間がかかったと思った実用的なコードがいくつかあります。それと2)残りの質問がいくつかあるので...
FFT「計画」を初期化します。2乗の正方形の画像を想定すると、次のようになります。
#include <Accelerate/Accelerate.h>
...
UInt32 N = log2(length*length);
UInt32 log2nr = N / 2;
UInt32 log2nc = N / 2;
UInt32 numElements = 1 << ( log2nr + log2nc );
float SCALE = 1.0/numElements;
SInt32 rowStride = 1;
SInt32 columnStride = 0;
FFTSetup setup = create_fftsetup(MAX(log2nr, log2nc), FFT_RADIX2);
2乗の2乗グレースケール画像のバイト配列を渡し、それをCOMPLEX_SPLITに変換します。
COMPLEX_SPLIT in_fft;
in_fft.realp = ( float* ) malloc ( numElements * sizeof ( float ) );
in_fft.imagp = ( float* ) malloc ( numElements * sizeof ( float ) );
for ( UInt32 i = 0; i < numElements; i++ ) {
if (i < t->width * t->height) {
in_fft.realp[i] = t->data[i] / 255.0;
in_fft.imagp[i] = 0.0;
}
}
変換された画像データに対してFFTを実行してから、大きさと位相を取得します。
COMPLEX_SPLIT out_fft;
out_fft.realp = ( float* ) malloc ( numElements * sizeof ( float ) );
out_fft.imagp = ( float* ) malloc ( numElements * sizeof ( float ) );
fft2d_zop ( setup, &in_fft, rowStride, columnStride, &out_fft, rowStride, columnStride, log2nc, log2nr, FFT_FORWARD );
magnitude = (float *) malloc(numElements * sizeof(float));
phase = (float *) malloc(numElements * sizeof(float));
for (int i = 0; i < numElements; i++) {
magnitude[i] = sqrt(out_fft.realp[i] * out_fft.realp[i] + out_fft.imagp[i] * out_fft.imagp[i]) ;
phase[i] = atan2(out_fft.imagp[i],out_fft.realp[i]);
}
これで、out_fftデータに対してIFFTを実行して、元の画像を取得できます...
COMPLEX_SPLIT out_ifft;
out_ifft.realp = ( float* ) malloc ( numElements * sizeof ( float ) );
out_ifft.imagp = ( float* ) malloc ( numElements * sizeof ( float ) );
fft2d_zop (setup, &out_fft, rowStride, columnStride, &out_ifft, rowStride, columnStride, log2nc, log2nr, FFT_INVERSE);
vsmul( out_ifft.realp, 1, SCALE, out_ifft.realp, 1, numElements );
vsmul( out_ifft.imagp, 1, SCALE, out_ifft.imagp, 1, numElements );
または、マグニチュードに対してIFFTを実行して、自己相関を取得することもできます...
COMPLEX_SPLIT in_ifft;
in_ifft.realp = ( float* ) malloc ( numElements * sizeof ( float ) );
in_ifft.imagp = ( float* ) malloc ( numElements * sizeof ( float ) );
for (int i = 0; i < numElements; i++) {
in_ifft.realp[i] = (magnitude[i]);
in_ifft.imagp[i] = 0.0;
}
fft2d_zop ( setup, &in_fft, rowStride, columnStride, &out_ifft, rowStride, columnStride, log2nc, log2nr, FFT_INVERSE );
vsmul( out_ifft.realp, 1, SCALE, out_ifft.realp, 1, numElements );
vsmul( out_ifft.imagp, 1, SCALE, out_ifft.imagp, 1, numElements );
最後に、ifftの結果を画像配列に戻すことができます。
for ( UInt32 i = 0; i < numElements; i++ ) {
t->data[i] = (int) (out_ifft.realp[i] * 255.0);
}
Accelerateフレームワークを使用して2の累乗以外の画像を処理する方法がわかりません。セットアップで十分なメモリを割り当てると、FFTを実行し、続いてIFFTを実行して元のイメージを取得できます。しかし、(FFTの大きさで)自己相関を行おうとすると、私の画像は不安定な結果になります。画像を適切にパディングする最善の方法がわからないので、誰かがこれを行う方法を知っているといいのですが。(または、vDSP_convメソッドの動作バージョンを共有してください!)