[32/64bit] 1 次元または 2 次元の浮動小数点型配列に対して,離散フーリエ変換または逆変換を行います.
core_dft p1,p2,p3,p4
p1 = sptr : IntPtr src p2 = sptr : IntPtr dst p3 = int : int flags p4 = int : int nonzeroRows
(プラグイン / モジュール : OpenCvSharpExtern.dll)
関数 cv::dft は,以下のいずれかの処理を行います: N 個の要素を持つ 1 次元ベクトルのフーリエ変換を行います. \Y = F^{(N)} ?cdot X,?]となります. ここで、\(F^{(N)}_{jk}=\exp(-2pi i j k/N)\)、\(i=sqrt{-1}\)とします。 N個の要素を持つ1次元ベクトルのフーリエ変換を逆変換します。 \♪♪♪♪♪~X'= ?? (F^{(N)})\(1/N) ????? ) ????? ) ここで、F^*=\left(F^{(N)})-\textrm{Im}(F^{(N)})\right)^T\) M x N の行列の 2 次元フーリエ変換を進めます。 Y = F^{(M)} \cdot X \cdot F^{(N)}\[Y = F^{(M)} \cdot X ?cdot F^{(N)}\]となります。 M×Nの行列の2次元フーリエ変換を逆にします。 \♪♪♪♪♪♪~♪ X'= ♪ ♪ left (F^{(M)})Y\\\\\♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪\実データ(シングルチャンネル)の場合、フーリエ変換の出力スペクトルや逆フーリエ変換の入力スペクトルは、CCS(complex-conjugate-symmetrical)というパック形式で表現できます。これはIPL(Intel* Image Processing Library)から拝借したものです。2次元CCSスペクトルはこんな感じです。Re Y_{0,0} & Re Y_{0,1} & Im Y_{0,1} & Re Y_{0,2} & Im Y_{0,2} & ????? ) Re Y_{0,N/2-1} & Im Y_{0,N/2-1} & Re Y_{0,N/2} ????? ) Re Y_{1,0} & Re Y_{1,1} & Im Y_{1,1} & Re Y_{1,2} & Im Y_{1,2} & ????? & Re Y_{1,N/2-1} & Im Y_{1,N/2-1} & Re Y_{1,N/2} ????? Im Y_{1,0} & Re Y_{2,1} & Im Y_{2,1} & Re Y_{2,2} & Im Y_{2,2} & \\ & Re Y_{2,N/2-1} & Im Y_{2,N/2-1} & Im Y_{1,N/2} \\\Re Y_{M/2-1,0} & Re Y_{M-3,1} & Im Y_{M-3,1} & \\\\N/2} ¶ Im Y_{M/2-1,0} & Re Y_{M-2,1} & Im Y_{M-2,1} & ¶hdotsfor{3} & Re Y_{M-2,N/2-1} & Im Y_{M-2,N/2-1}& Im Y_{M/2-1,N/2} \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\そこで,この関数は,フラグと入力配列のサイズに応じて処理モードを選択します: DFT_ROWS がセットされている場合,あるいは入力配列が1行あるいは1列の場合,この関数は,行列の各行に対して1次元の順変換あるいは逆変換を行います.それ以外の場合は,2次元変換を行います. 入力配列が実数で,DFT_INVERSE がセットされていない場合,この関数は 1 次元または 2 次元の順変換を行います。 DFT_COMPLEX_OUTPUT がセットされている場合,入力と同じサイズの複素行列が出力されます. DFT_COMPLEX_OUTPUT がセットされていない場合,出力は入力と同じサイズの実数行列です.2次元変換の場合は,上記のようなパック形式を使用します。1つの1次元変換の場合,上述の行列の最初の行のようになります。複数の1次元変換の場合(DFT_ROWS フラグを利用した場合),出力行列の各行は,上述の行列の最初の行のようになります. 入力配列が複素数で,かつ DFT_INVERSE や DFT_REAL_OUTPUT がセットされていない場合,出力は入力と同じサイズの複素数配列になります.この関数は,フラグ DFT_INVERSE と DFT_ROWS に応じて,入力配列全体,あるいは入力配列の各行に対して,個別に 1 次元または 2 次元の順変換,逆変換を行います。 DFT_INVERSEがセットされていて,入力配列が実数の場合,あるいは複素数だがDFT_REAL_OUTPUTがセットされている場合,出力は入力と同じサイズの実数配列になります。この関数は,フラグ DFT_INVERSE と DFT_ROWS に応じて,入力配列全体,あるいは各行に対して,1次元あるいは2次元の逆変換を行います.DFT_SCALE がセットされている場合は,変換後にスケーリングが行われます.しかし,効率的に処理されるのは,そのサイズが小さな素数(現在の実装では,2,3,5)の積で因数分解できる配列だけです.このような効率的なDFTサイズは,getOptimalDFTSizeメソッドを用いて計算することができます.以下のサンプルは,2つの2次元実数配列のDFTベースの畳み込みを計算する方法を示しています: void convolveDFT(InputArray A, InputArray B, OutputArray C){ // 必要に応じて出力配列を再配置する C.create(abs(A.rows - B.rows)+1, abs(A.cols - B.cols)+1, A.type()); Size dftSize; // DFT 変換のサイズを計算する dftSize.width = getOptimalDFTSize(A.cols + B.cols - 1); dftSize.height = getOptimalDFTSize(A.rows + B.rows - 1); // 一時的なバッファを確保し,0 で初期化する Mat tempA(dftSize, A.type(), Scalar::all(0)); Mat tempB(dftSize, B.type(), Scalar::all(0)); // A と B をそれぞれ tempA と tempB の左上隅にコピーします. Mat roiA(tempA, Rect(0,0,A.cols,A.rows)); A.copyTo(roiA); Mat roiB(tempB, Rect(0,0,B.cols,B.rows)); B.copyTo(roiB); // パディングされた A & B をインプレースで変換します. // 高速処理のために "nonzeroRows" ヒントを利用します dft(tempA, tempA, 0, A.rows); dft(tempB, tempB, 0, B.rows); // スペクトルを乗算します. // すべての結果行が非ゼロになるとしても, // 最初の C.rows だけが必要なので, // nonzeroRows == C.rows を渡します. dft(tempA, tempA, DFT_INVERSE + DFT_SCALE, C.rows); // ここで,結果を C にコピーします.copyTo(C); // すべての一時バッファは自動的に解放されます}fragmentこのサンプルを最適化するために,以下の方法を考えます: nonzeroRows != 0 が順変換の呼び出しに渡され,A と B はそれぞれ tempA と tempB の左上隅にコピーされるので,tempA と tempB 全体をクリアする必要はありません.tempA.cols - A.cols ( tempB.cols - B.cols ) の右端の列をクリアするだけでよいのです。 このDFTベースの畳み込みは,特にBがAよりもかなり小さい場合やその逆の場合には,大きな配列全体に適用する必要はありません.その代わりに,部分的に畳み込みを計算することができます.そのためには,出力配列Cを複数のタイルに分割する必要があります.各タイルについて、そのタイルでコンボリューションを計算するために、AとBのどの部分が必要かを推定します。Cのタイルが小さすぎると、繰り返し作業が発生するため、速度が大きく低下します。究極的には、Cの各タイルが1ピクセルの場合、このアルゴリズムは、ナイーブコンボリューションアルゴリズムと同等になる。タイルが大きすぎると、一時的な配列であるtempAとtempBが大きくなりすぎ、また、キャッシュの局所性が悪くなるため、速度が低下してしまいます。つまり、中間に最適なタイルサイズがあるのです。 C の異なるタイルが並行して計算され,その結果,畳み込みが部分的に行われるのであれば,ループをスレッド化することができます.上記の改良点はすべて matchTemplate と filter2D に実装されています.以上の改良点はすべてmatchTemplateとfilter2Dに実装されていますので,これらを使用すれば,上記の理論的に最適な実装よりもさらに優れた性能を得ることができます.ただし,この2つの関数は,実際には畳み込みではなく相互相関を計算しているので,flip.Noteを使って,2番目の畳み込みオペランドBを縦横に反転させる必要があります. 離散フーリエ変換を用いた例は、opencv_source_code/samples/cpp/dft.cppにあります。 (Python) dft 機能を使って Wiener デコンボリューションを行う例は opencv_source/samples/python/deconvolution.py にあります。 (Python) フーリエ画像の象限を並べ替える例は、opencv_source/samples/python/dft.pyにあります。 元関数名(C#): core_dft 元DLLエクスポート名: core_dft 参照元CSファイル: Internal\PInvoke\NativeMethods\core\NativeMethods_core.cs ▼ C言語側関数定義
CVAPI(ExceptionStatus) core_dft(cv::_InputArray *src, cv::_OutputArray *dst, int flags, int nonzeroRows) { BEGIN_WRAP cv::dft(*src, *dst, flags, nonzeroRows); END_WRAP }
プラグイン / モジュール | OpenCvSharpExtern.dll |
バージョン | 1.00 |
作成日 | 2021/11/30 |
著作者 | inovia |
URL | https://hsp.moe/ |
備考 | #include "OpenCvSharpExtern32.as"
#include "OpenCvSharpExtern64.as" 使用するHSPランタイムのビット数に合わせたインクルードファイルを使用すること |
タイプ | OpenCVSharpラッパーDLL |
グループ | NativeMethods_core |
対応環境 |
|
hs ファイル | hsphelp\OpenCvSharpExtern.hs |