2012-04-25 12 views
4

matlab関数conv2の直接opencv関数はありますか?私はcvFilter2D()を使ってみましたが、conv2()とは異なる結果が出ているようです。例えばis opencvにmatlab conv2と同等の関数があります

CvMat * Aa = cvCreateMat(2, 2, CV_32FC1); 
CvMat * Bb = cvCreateMat(2, 2, CV_32FC1); 
CvMat * Cc = cvCreateMat(2, 2, CV_32FC1); 
cvSetReal2D(Aa, 0, 0, 1); 
cvSetReal2D(Aa, 0, 1, 2); 
cvSetReal2D(Aa, 1, 0, 3); 
cvSetReal2D(Aa, 1, 1, 4); 
cvSetReal2D(Bb, 0, 0, 5); 
cvSetReal2D(Bb, 0, 1, 5); 
cvSetReal2D(Bb, 1, 0, 5); 
cvSetReal2D(Bb, 1, 1, 5); 
cvFilter2D(Aa, Cc, Bb); 

This produces the matrix [20 30; 40 50] 


In MATLAB: 
>> A=[1 2; 3 4] 
A = 
1 2 
3 4 

>> B=[5 5; 5 5] 
B = 
5 5 
5 5 

>> conv2(A,B,'shape') 
ans = 
50 30 
35 20 

me.Thankあなたのためme.itsは非常に便利助けてください。

ありがとうございます。

アランガラガン。

+0

マイナー編集:正しい呼び出しは 'conv2(A、B、 'same')' – Amro

答えて

5

コンボリューションを使用している場合は、マトリックスの端に問題があります。畳み込みマスクは、マトリックスの外側にある値を必要とします。 OpenCVとmatlabのアルゴリズムは、この問題に対処するためにさまざまな戦略を使用しています。 OpenCVは境界線のピクセルを複製しますが、matlabはすべてのピクセルがゼロであると仮定します。

OpenCVのmatlabの動作をエミュレートするには、このゼロ埋めを手動で追加することができます。これ専用の機能もあります。私はあなたのコードを変更することができる方法の例を挙げてみましょう:

CvMat * Ccb = cvCreateMat(3, 3, CV_32FC1); 
CvMat * Aab = cvCreateMat(3, 3, CV_32FC1); 
cvCopyMakeBorder(Aa,Aab, cvPoint(0,0),IPL_BORDER_CONSTANT, cvScalarAll(0)); 
cvFilter2D(Aab, Ccb, Bb); 

これが与える結果は次のとおりです。

20.000 30.000 20.000 
40.000 50.000 30.000 
30.000 35.000 20.000 

あなただけの最初の列を削除しに行する必要があなたの意図した結果を取得するには追加した国境によって導入された追加データを取り除く。

+0

ありがとうございます。 – aranga

+4

+1関数 'cvFilter2D'は' 'conv2''が畳み込みを行いながら相関を実行することに注意してください。上の例ではこれは問題ではありませんが、カーネルが対称でない場合は、結果を180度回転させて一致させる必要があります。 – Amro

7

数値計算環境Matlab(またはその自由な代替GNUオクターブ)は、畳み込みカーネルを持つ与えられた行列の二次元畳み込みのためのconv2という関数を提供します。無料の画像処理ライブラリOpenCVに基づいていくつかのC++コードを書いている間、私はOpenCVが現在同等の方法を提供していないことを発見しました。

2次元相関を実装し、画像を与えられたカーネルで畳み込むのに使用できるfilter2D()メソッドがありますが(カーネルを反転し、アンカーポイントを正しい位置に移動することによって)、対応するOpenCVのドキュメントページ)、Matlabと同じボーダーハンドリングオプションを提供するメソッド( "フル"、 "有効"または "同じ"コンボリューション)を持つのはいいでしょう。 OpenCVを使用してMatlabとC++の両方で実装されている同じアルゴリズムの結果を比較します。ここで

は私が思いついたものです:私のユニットテストでは

enum ConvolutionType { 
/* Return the full convolution, including border */ 
    CONVOLUTION_FULL, 

/* Return only the part that corresponds to the original image */ 
    CONVOLUTION_SAME, 

/* Return only the submatrix containing elements that were not influenced by the border  
*/ 
    CONVOLUTION_VALID 
}; 

void conv2(const Mat &img, const Mat& kernel, ConvolutionType type, Mat& dest) { 
    Mat source = img; 
    if(CONVOLUTION_FULL == type) { 
    source = Mat(); 
    const int additionalRows = kernel.rows-1, additionalCols = kernel.cols-1; 
    copyMakeBorder(img, source, (additionalRows+1)/2, additionalRows/2,  
(additionalCols+1)/2, additionalCols/2, BORDER_CONSTANT, Scalar(0)); 
    } 

    Point anchor(kernel.cols - kernel.cols/2 - 1, kernel.rows - kernel.rows/2 - 1); 
    int borderMode = BORDER_CONSTANT; 
    filter2D(source, dest, img.depth(), flip(kernel), anchor, 0, borderMode); 

    if(CONVOLUTION_VALID == type) { 
    dest = dest.colRange((kernel.cols-1)/2, dest.cols - kernel.cols/2) 
      .rowRange((kernel.rows-1)/2, dest.rows - kernel.rows/2); 
    } 
} 

、この実装は、MATLABの実装とほぼ同じであった結果が得られました。 OpenCVとMatlabの両方が、カーネルが十分に大きければフーリエ空間で畳み込みを行うことに注意してください。 'large'の定義はどちらの実装でも異なりますが、大きなカーネルであっても結果は非常に似ています。

また、完全な畳み込みの場合、このメソッドのパフォーマンスは問題になる可能性があります。ソースマトリックス全体をコピーして境界線を追加する必要があるからです。最後に、filter2D()コールで例外を受け取り、カラムが1つしかないカーネルを使用している場合は、このバグが原因である可能性があります。その場合、borderMode変数を例えばに設定する。代わりにBORDER_REPLICATEを使用するか、OpenCVトランクのライブラリの最新バージョンを使用してください。

+0

+1これまでのベストアンサー。コードスニペットは良好で、MATLABの 'conv2'とよく似た何かを実行します。さらに、OpenCVの 'filter2D'が相関を行い、畳み込みを行わないことを思い出させるのは良いことです。 –

+0

優れた答え! – Itay

+0

flip()は少なくとも2つのパラメータを取るべきではありませんか? doc C++によると、void flip(InputArray src、OutputArray dst、int flipCode)です。したがって、cv :: flip(カーネル、カーネル、0) – iqbalnaved

関連する問題