< 目次

高速フーリエ変換を使用したコンピューター・トモグラフィー・イメージの復元

目的

高速フーリエ変換 (FFT) 関数を使用してコンピューター・トモグラフィー (CT) データから元のイメージを復元する。

解決方法

表記規則:

仮定:

離散イメージ復元アルゴリズムは次のステップからなります。

  1. p 1 次元 (1D) フーリエ変換 (j = 0 : p - 1 および r = -q : q) を評価します。

  2. g1[j, r] をラジアルグリッド (πr/q)(cosθj , sinθj) からデカルトグリッド (ξ, η) = (-q : q, -q : q) に補間し、f2(πξ/q, πη/q) を取得します。

  3. 逆 2 次元複素数-複素数 FFT を評価して、複素数値の復元イメージ f1 を取得します。

    ここで、f(m/q, n/q) f1[m, n] (m = -q : q および n = -q : q) です。

ステップ 1 と 3 の計算は、oneMKL FFT インターフェイスを呼び出します。ステップ 2 の計算は、oneMKL FFT で使用されるデータレイアウトに合わせた、単純なバージョンの補間を実装します。

元の CT イメージの復元 (C/C++)

// 宣言
int Nq = 2*(q+1); // インプレースr2c FFT 用の空間
void       *gmem = mkl_malloc( sizeof(float)*p*Nq, 64 ); 
float       *g = gmem;   // g[j*Nq + ell+q] 
complex *g1 = gmem; // g1[j*Nq/2 + r+q]
 
// g をCT データで初期化
for (int j = 0; j < p; ++j) 
    for (int ell = 0; ell < 2*q+1; ++ell) { 
        g[j*Nq + ell+q] = get_g(theta_j,s_ell); 
    } 

// ステップ1: 1D 実数-複素数FFT を構成して計算 
DFTI_DESCRIPTOR_HANDLE h1 = NULL; 
DftiCreateDescriptor(&h1,DFTI_SINGLE,DFTI_REAL,1,(MKL_LONG)2*q); 
DftiSetValue(h1,DFTI_CONJUGATE_EVEN_STORAGE,DFTI_COMPLEX_COMPLEX); 
DftiSetValue(h1,DFTI_NUMBER_OF_TRANSFORMS,(MKL_LONG)p); 
DftiSetValue(h1,DFTI_INPUT_DISTANCE,(MKL_LONG)Nq); 
DftiSetValue(h1,DFTI_OUTPUT_DISTANCE,(MKL_LONG)Nq/2); 
DftiSetValue(h1,DFTI_FORWARD_SCALE,fscale); 
DftiCommitDescriptor(h1); DftiComputeForward(h1,g); // gmem にg1 が含まれる 

// ステップ2: g1 をf2 に補間- ここでは省略 
complex *f = mkl_malloc( sizeof(complex) * 2*q * 2*q, 64 ); 

// ステップ3: 2D 複素数-複素数FFT を構成して計算 
DFTI_DESCRIPTOR_HANDLE h3 = NULL; 
MKL_LONG sizes[2] = {2*q, 2*q}; DftiCreateDescriptor(&h3,DFTI_SINGLE,DFTI_COMPLEX,2,sizes); 
DftiCommitDescriptor(h3); 
DftiComputeBackward(h3,f); // f が複素数値で復元される

ソースコード、イメージファイル、メイクファイル: サンプル (https://www.intel.com/content/dam/develop/external/us/en/documents/mkl-cookbook-samples-120115.zip (英語)) の fft-ct フォルダーを参照してください。GitHub の block_lu_decomposition (英語) も参照してください。

説明

このコードは、最初に DftiComputeForward 関数の単一の呼び出しで 1 次元フーリエ変換のバッチを計算する oneMKL FFT ディスクリプターを構成した後、バッチ変換を計算します。複数の変換の距離は、対応する領域 (入力は実数、出力は複素数) の要素で設定されます。デフォルトでは、変換はインプレースです。

メモリーのフットプリントを小さくするため、FFT は「インプレース」で計算されます。つまり、計算の結果は入力データに上書きされます。インプレースの実数-複素数 FFT では、FFT の結果を格納するのに必要なメモリーが入力よりもやや多くなるため、入力配列は余分な空間を予約します。

ステップ 1 の入力で、配列 g には p x (2q+1)実数値のデータ要素 g(θj, sl) が含まれます。このステップの出力の同じメモリーには、p x (q + 1) 複素数値の出力要素 g1(θj, πr/q) が含まれます。結果の複素共役部分は格納されません。そのため、配列 g1 は、rq + 1 値のみを指します。

g1 から f2 に補間するため、ステップ 3 の逆 FFT の複素数値のデータ f2(ξ, η) と複素数値の出力 f1(x, y) を格納する追加の配列 f が割り当てられます。補間ステップは oneMKL 関数を呼び出しません。C++ 実装は、この手法のソースコード (main.cpp) の step2_interpolation 関数を参照してください。補間の最も単純な実装は次のとおりです。

ステップ 1 の FFT は、計算された出力が ei(πr/q)q= (-1)r で乗算される、表現区間の半分でオフセットされたデータに適用されることに注意してください。個別のパスで修正する代わりに、補間は乗数を考慮しています。

同様に、ステップ 3 の 2D FFT はイメージの中心を隅にシフトする出力を生成し、ステップ 2 はステップ 3 に入力をシフトする過程でこれを防いでいます。

ステップ 3 は、配列 f に含まれる補間されたデータについて 2 次元 (2q) x (2q) 複素数-複素数 FFT を計算します。この計算の後、複素数値のイメージ f1 からビジュアルピクチャーへの変換が行われます。CT イメージ復元を実装する完全な C++ プログラムは、この手法のソースコード (main.cpp) を参照してください。