2013-11-20 64 views
4

我試圖使用OpenCV的索貝爾方法的結果來確定圖像的梯度方向。使用OpenCV的索貝爾操作計算圖像的梯度方向

我知道這應該是一個非常簡單的任務,我認爲我理解這個理論,但是實現這一點比我想象的更具挑戰性。

我期望梯度方向在0-360度之間,但是我的代碼顯示所有梯度落在180-270度之間。

我提交了包含整數除法問題的此代碼的以前版本。我已經解決了這個問題,但它並沒有解決方向角受限的問題。

我已經通過了所有的代碼,但我不明白我要去哪裏錯了?任何人都能發現我的錯誤嗎

謝謝。

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); 

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

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

uchar* pixelX = grad_x.data; 
uchar* pixelY = 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 = -1; 

for(int i = 0; i < grad_x.rows * grad_x.cols; i++) 
{ 
     double directionRAD = atan2(pixelY[i], pixelX[i]); 
     int directionDEG = (int)(180 + directionRAD/M_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."; 
     } 

} 

}

回答

7

grad_xgrad_y的類型CV_16SC1的席子,這是每一個像素在其中佔據了兩個字節。

但是,您聲明pixelXpixelY指向8位字節的指針。因此pixelX[1]是第一個漸變的第二個字節,而不是第二個漸變。

你需要

short* pixelX = grad_x.ptr<short>(0); 
short* pixelY = grad_y.ptr<short>(0); 
+0

非常感謝。感謝您的解釋,我終於明白了這個問題。我根本沒有想到這樣的問題,希望未來能夠更好地發現這樣的問題。再次感謝。 – CVirtuous

+2

你也習慣直接迭代.data,當你遇到一個非連續的Mat時會咬你 - 見http://docs.opencv.org/doc/tutorials/core/how_to_scan_images/how_to_scan_images.html#the-高效方式 – Bull

+0

謝謝。是的,我通常通過類似的方式來做這件事,但在這種情況下,我知道它是連續的,所以它只是快速和骯髒;) – CVirtuous

1

問題是在這裏

uchar* pixelX = grad_x.data; 
uchar* pixelY = grad_y.data; 

這裏

double directionRAD = atan2(pixelY[i], pixelX[i]); 

客人不願意採取ABS(),但使用unsigned指針。這就是爲什麼你不能讓x或y消極。

應該是:

short* pixelX = (short*) grad_x.data; 
short* pixelY = (short*) grad_y.data; 

double directionRAD = atan2((double)pixelY[i], (double)pixelX[i]); 
+0

非常感謝。似乎我的問題是缺乏對數據表示和正確使用指針的理解。看起來我需要刷新這個東西!再次感謝。 – CVirtuous