C ++-OpenCVピット

  私はopencvピットに1日間足を踏み入れたが、嘔吐が避けられなかった。

  通常の2つの行列演算は一連の8U画像には適用できません。これは最大の穴です。たとえば、2つの画像行列を追加する場合は、次のようにします。

マットim1 = imread( "../ opencv / samples / data / pic5.png"、CV_8UC1); 
マットim2 = imread( "../ opencv / samples / data / pic6.png"、CV_8UC1); 
マットの重なり= im1 + im2;

  これを書いた場合、結果の画像は完全に間違っています!いくつかの特別な変換を行う必要があります。

  まあ、それを最初に実行した後、結果が表示されます:

  ここで、im1とim2は次のようになります(opencvに付属するサンプルイメージ)。

 

  (IM1)

  (im2)

  一見、それは正しいように見えますが、実際にはそれは正しいです(python opencvで実行):

  これは、C ++での理由は、8Uイメージの値の範囲が0〜255であり、Matが追加されると、255より大きい値がオーバーフローするためです。その後、加算によりオーバーフローしたピクセルの値は255になります。最初に、このメソッドを記述して修正しました。

Mat matr_add(Mat im1、Mat im2)
{ 
    CV_Assert(im1.size()== im2.size()); 
    Mat uxx = Mat :: zeros(im1.size()、CV_8UC1); 
    for(int i = 0; i <uxx.rows; i ++)
    { 
        for(int j = 0; j <uxx.cols; j ++)
        { 
            uxx.at <uchar>(i、j)=(im1.at <uchar >(i、j)+ im2.at <uchar>(i、j))%256; 
        } 
    } 
    return uxx; 
}

  演算結果:

  正解です。

  これは、行列乗算(C ++ opencv)を実行するときに、より明白になります。

  そして正しい(python opencvで実行されている):

  また、モジュロ補正の方法を使用します。

Mat multiply_mod(Mat im1、Mat im2)
{ 
    CV_Assert(im1.size()== im2.size()); 
    Mat uxx = Mat :: zeros(im1.size()、CV_8UC1); 
    for(int i = 0; i <uxx.rows; i ++)
    { 
        for(int j = 0; j <uxx.cols; j ++)
        { 
            uxx.at <uchar>(i、j)=(im1.at <uchar >(i、j)* im2.at <uchar>(i、j))%256; 
        } 
    } 
    return uxx; 
}

  演算結果:

  修正しました。

  同様に、減算も修復する必要があります。

Mat matr_sub(Mat im1、Mat im2)
{ 
    CV_Assert(im1.size()== im2.size()); 
    Mat uxx = Mat :: zeros(im1.size()、CV_8UC1); 
    for(int i = 0; i <uxx.rows; i ++)
    { 
        for(int j = 0; j <uxx.cols; j ++)
        { 
            uxx.ptr <uchar>(i)[j] =(im1.ptr < uchar>(i)[j]-im2.ptr <uchar>(i)[j])<0?(im1.ptr <uchar>(i)[j]-im2.ptr <uchar>(i)[j])%256:(im1.ptr <uchar>(i)[j]-im2.ptr <uchar> (i)[j]); 
        } 
    } 
    return uxx; 
}

  非常に美しく、すべての問題を解決しているようです。

  しかし、実際には、問題はそれほど単純ではありません。分割を修正する方法についての質問がまだあります。それは、場合によっては、画像に対していくつかの操作を実行した後、0を取得するためです(理由は、8UC1タイプのマットがピクセルの格納に使用されているためです。 0.xxxの値は直接0として扱われます。現時点では修正できませんが、正しい浮動小数点ピクセル値を取得または設定したいと思います。この問題は、私が書いた画像の類似性の検出に直接つながります。アルゴリズムが正しく動作しない...

  だから、落ち着いて考え直してください。

  まず、CV_32FC1を直接使用して画像を読み取ることはできませんが、予期せずNanまたはinfの値が多数取得されるため、正常に画像を表示できません。

  また、次のコードを使用してピクセル要素にアクセスすることはできません(以下では、C1シングルチャネル画像の使用を想定しています)。

  ケース1:imタイプがCV_8UC1であると想定します

im.at <int>(行、列); 
im.at <float>(row、col); 
// ...

  それ以外の場合、イメージは600 x 600ですが、小さな部分を読み取り、ループに入るとすぐにopencv_assertのアサーション割り込みエラーを報告します。参照:https : //github.com/kinchungwong/kinchungwong.github.io/blob/master/opencv_issues_11370/explain_opencv_non_issue_11370.md

  8Uシリーズの場合、この方法のみを使用できます。

im.at <uchar>(row、col)
im.ptr <T>(row)[col];

  他のケースでは、他のタイプのマットでは、次の方法でピクセル要素情報を取得または設定することをお勧めします。

im.ptr <T>(row)[col];

  <T>()を使用してアクセスしないでください。これは、メモリアドレスをタイプごとに計算するため、範囲を確実に超えるためです。プログラムはすぐに中断されます。

  トピックに戻ります。

  実際には、画像の正確で便利なマトリックス操作を確実にしたいのです。実際、実行する手順は1つだけです。最初に、CV_8UC1(例としてシングルチャネルの画像を使用)を使用して画像を読み取り、そのマトリックスタイプをCV_32FC1に変換します。さあ!とても簡単ですが、長い間私でした。

マットim1 = imread( "../ opencv / samples / data / lena.jpg"、CV_8UC1); 
マットim1f; 

im1.convertTo(im1f、CV_32FC1); 
// ...

  したがって、私が作成したSSIMアルゴリズムを使用できます。次の記事では、SSIMアルゴリズムを完全に紹介します〜

おすすめ

転載: www.cnblogs.com/darkchii/p/12677412.html