14

//編集...

特に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メソッドの動作バージョンを共有してください!)

4

1 に答える 1

3

任意の画像サイズで作業を実行するには、入力値配列を次の 2 の累乗に適切にサイズ設定するだけでよいと言えます。

難しいのは、元の画像データをどこに置き、何を埋めるかです。画像または画像からデータマイニングに対して実際に何をしようとしているのかが重要です。

以下のリンク先の PDF で、12.4.2 のすぐ上の段落に特に注意して ください http://www.mathcs.org/java/programs/FFT/FFTInfo/c12-4.pdf

上記は 2 つの軸に沿った操作について述べていますが、2 番目の次元の前に同様のアイデアを実行し、2 番目の次元に続く可能性があります。私が正しければ、次の例が適用できます (これは決して正確なアルゴリズムではありません)。

900 x 900 の画像があるとします。まず、画像を 512、256、128、および 4 の垂直ストリップに分割できます。次に、各行に対して 4 つの 1D FFT を処理します。最初の 512 ピクセルに対して 1 つ、次の 512 ピクセルに対して 1 つです。次の 256 ピクセル、次の 128 ピクセル、最後に残りの 4 ピクセル。 )。次に、この同じ技術を 2 次元に押し進めることができます。この時点で、実際にパディングする必要なく、すべての入力ピクセルを考慮に入れることができます。

これは本当に単なる考察の材料です。私はこれを自分で試したことがなく、実際に自分で調査する必要があります。あなたが今、本当にこの種の仕事をしているなら、あなたはこの時点で私よりも多くの時間を持っているかもしれません.

于 2012-05-30T21:25:16.040 に答える