2013-11-15 6 views
5

openCVのSobelメソッドの結果を使用して画像の勾配方向を決定しようとしています。sobelから画像の勾配方向を決定していますか?

これは非常に簡単な作業であるはずです。私はここからいくつかのリソースと回答からメソッドをコピーしましたが、結果の方向をいつでも0〜57度(私は範囲が0〜360になると予想します)の間にあります。

私はすべての深さが正しいと信じています。私は16Uデータと8Uデータを使って方向を計算しようとしました。

どこが間違っているのか分かりません。誰も私の間違いを見つけられますか?

void getGradients(IplImage* original, cv::Mat* gradArray) 
{ 
    cv::Mat original_Mat(original, true); 

    // Convert it to gray 
    cv::cvtColor(original_Mat, original_Mat, CV_RGB2GRAY); 
    //cv::blur(original_Mat, original_Mat, cv::Size(7,7)); 

    /// Generate grad_x and grad_y 
    cv::Mat grad_x = cv::Mat::zeros(original->height, original->width, CV_16S); 
    cv::Mat grad_y = cv::Mat::zeros(original->height, original->width, CV_16S); 

    cv::Mat abs_grad_x = cv::Mat::zeros(original->height, original->width, CV_8U); 
    cv::Mat abs_grad_y = cv::Mat::zeros(original->height, original->width, CV_8U);; 

    /// Gradient X 
    cv::Sobel(original_Mat, grad_x, CV_16S, 1, 0, 3); 
    cv::convertScaleAbs(grad_x, abs_grad_x); 

    /// Gradient Y 
    cv::Sobel(original_Mat, grad_y, CV_16S, 0, 1, 3); 
    cv::convertScaleAbs(grad_y, abs_grad_y); 

    uchar* pixelX = abs_grad_x.data; 
    uchar* pixelY = abs_grad_y.data; 
    uchar* grad1 = gradArray[0].data; 
    uchar* grad2 = gradArray[1].data; 
    uchar* grad3 = gradArray[2].data; 
    uchar* grad4 = gradArray[3].data; 
    uchar* grad5 = gradArray[4].data; 
    uchar* grad6 = gradArray[5].data; 
    uchar* grad7 = gradArray[6].data; 
    uchar* grad8 = gradArray[7].data; 
    int count = 0; 
    int min = 999999; 
    int max = 0; 

    for(int i = 0; i < grad_x.rows * grad_x.cols; i++) 
    { 
      int directionRAD = atan2(pixelY[i], pixelX[i]); 
      int directionDEG = directionRAD/PI * 180; 

      if(directionDEG < min){min = directionDEG;} 
      if(directionDEG > max){max = directionDEG;} 

      if(directionDEG >= 0 && directionDEG <= 45)   { grad1[i] = 255; count++;}   
      if(directionDEG >= 45 && directionDEG <= 90)  { grad2[i] = 255; count++;}   
      if(directionDEG >= 90 && directionDEG <= 135)  { grad3[i] = 255; count++;}   
      if(directionDEG >= 135 && directionDEG <= 190)  { grad4[i] = 255; count++;}   
      if(directionDEG >= 190 && directionDEG <= 225)  { grad5[i] = 255; count++;}   
      if(directionDEG >= 225 && directionDEG <= 270)  { grad6[i] = 255; count++;}  
      if(directionDEG >= 270 && directionDEG <= 315)  { grad7[i] = 255; count++;} 
      if(directionDEG >= 315 && directionDEG <= 360)  { grad8[i] = 255; count++;} 

      if(directionDEG < 0 || directionDEG > 360) 
      { 
       cout<<"Weird gradient direction given in method: getGradients."; 
      }    
    } 
} 

答えて

6

整数演算を使用しているため、ラジアンと度の計算は切り捨てに苦しんでいます。あなたは範囲内の度に値をしたい場合は、180度の補正を追加する必要があります0..360ので

またatan2は、+PIの範囲-PIで結果を与える:

 double directionRAD = atan2(pixelY[i], pixelX[i]); 
     int directionDEG = (int)(180.0 + directionRAD/M_PI * 180.0); 

注意をに対してintではなくdoubleの使用。

Proのヒント:デバッガを使用してコードをステップ実行し、変数を検査する方法を学びます。これは、StackOverflowでの応答を待っているよりもずっと簡単なバグを簡単に修正します。

+0

感謝。私はあなたが示唆したように切り捨ての問題を修正しましたが、大きな違いはありませんでした。私はまだ勾配方向0〜90(180度補正を適用して180〜270)の制限数を取得します。私はもはや値をスケーリングせず、したがって、Sobel操作によって与えられた生の16S値を使用しています。 画像全体の処理を進めてきましたが、どこが間違っているのか分かりません。あなたはなにか考えはありますか?ありがとう。 – CVirtuous

+0

abs操作も削除しましたか?もしそうなら、最新のコードを新しい質問として投稿することをお勧めします。 –

+0

はい、私はしました。今私は新しい質問を投稿します。ありがとうございました。 – CVirtuous

2

グラデーションの絶対値をとると、[-180; 180]を[0; 90]に設定する。また、整数除算を使用します。

+0

ありがとうold-ufo。私はポールのアドバイスに従って整数除算の問題を修正し、私はソーベルの操作から直接16Sデータを使用します。しかし、私はまだ0 - 90の範囲の制限された範囲を取得します。あなたは私のコードに間違って何かを見ることができますか? – CVirtuous

+0

あなたの投稿のコードを更新してください。_current_バージョンのバグを見つけることができます。 –

4

Sobel演算子を使用して、x派生dxとy派生dyを得ることができます。次に、数式を使用してグラデーションの大きさと方向を計算できます。 G=sqrt(dx^2+dy^2), theta=arctan(dy/dx)。これは座標系(x、y)を極座標(rho、theta)に変換するだけです!

絶対値がdxおよびdyになるようにコードに問題があります。方向は常にデカルト座標系の最初の象限になります。そして、convertScaleAbsを使用した関数は、結果を8ビットに変換します。その結果、切り捨てエラーが発生します。

コードに基づいて部分的に大きさを計算するデモがあります。アドバイスポール用

const string imgname = "F:/OpenCV/square.jpg"; 
    Mat img = imread(imgname, CV_LOAD_IMAGE_COLOR); 

    // 1. convert it to gray value 
    Mat gray; 
    cvtColor(img, gray, CV_BGR2GRAY); 
    // 2. blur the image 
    blur(gray, gray, Size(7, 7)); 
    // 3. sobel 
    Mat grad_x, grad_y; 
    Scharr(gray, grad_x, CV_32FC1, 1, 0); 
    Scharr(gray, grad_y, CV_32FC1, 0, 1); 
    // 4. calculate gradient magnitude and direction 
    Mat magnitude, direction; 
    bool useDegree = true; // use degree or rad 
    // the range of the direction is [0,2pi) or [0, 360) 
    cartToPolar(grad_x, grad_y, magnitude, direction, useDegree); 

    // test, the histogram of the directions 
    vector<int> cnt(8, 0); // 0-45, 45-90, ..., 315-360 

    for(auto iter = direction.begin<float>(); iter != direction.end<float>(); ++iter) 
    { 
     int idx = static_cast<int>(*iter)/45; 
     ++cnt[idx]; 
    } 

    Mat scaled; 
    convertScaleAbs(magnitude, scaled); 
    imshow("magnitude", scaled); 
    for(auto v : cnt) 
     cout << v << " "; 

A test picture magnitude visulization result

関連する問題