2013-11-15 11 views
5

Tôi đang cố gắng xác định hướng hình ảnh bằng cách sử dụng các kết quả từ phương pháp Sobel của openCV.Xác định hướng chuyển ảnh từ sobel?

Tôi hiểu đây phải là một nhiệm vụ rất đơn giản. Tôi đã sao chép các phương pháp từ một số tài nguyên và câu trả lời từ đây, nhưng bất cứ điều gì tôi làm các hướng kết quả luôn ở giữa 0 - 57 độ (tôi mong đợi phạm vi được từ 0-360).

Tôi tin rằng tất cả các độ sâu đều chính xác. Tôi đã thử tính toán hướng sử dụng dữ liệu 16S cũng như dữ liệu 8U.

Tôi không thể thấy mình đang đi sai ở đâu? Ai có thể phát hiện sai lầm của tôi?

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."; 
      }    
    } 
} 

Trả lời

6

Bạn đang sử dụng số học số nguyên để tính toán cho radian và độ của bạn đang bị cắt xén.

Cũng atan2 đưa ra một kết quả trong khoảng -PI-+PI, vì vậy nếu bạn muốn có một giá trị trong độ trong khoảng 0..360 bạn sẽ cần phải thêm một sự điều chỉnh 180 độ:

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

Note việc sử dụng double thay vì int cho directionRAD.

Mẹo chuyên nghiệp: tìm hiểu cách sử dụng trình gỡ lỗi để bước qua mã, kiểm tra biến khi bạn thực hiện - điều này sẽ giúp sửa các lỗi đơn giản như thế này dễ dàng hơn nhiều so với chờ phản hồi trên StackOverflow.

+0

Cám ơn những lời khuyên Paul. Tôi đã sửa vấn đề cắt ngắn như bạn đã đề xuất, tuy nhiên nó không tạo ra nhiều khác biệt. Tôi vẫn nhận được một số giới hạn hướng gradient 0 - 90 (hoặc 180 - 270 với hiệu chỉnh 180 độ được áp dụng). Tôi không còn mở rộng các giá trị và do đó tôi đang sử dụng các giá trị 16S thô do hoạt động Sobel đưa ra. Tôi đã thực hiện quá trình này cho toàn bộ hình ảnh nhưng không thể nhìn thấy nó ở đâu sai. Bạn có bất cứ ý tưởng? Cảm ơn. – CVirtuous

+0

Bạn đã xóa hoạt động abs chưa? Nếu có, thì tôi khuyên bạn nên đăng mã mới nhất của mình làm câu hỏi mới. –

+0

Vâng tôi đã làm. Tôi sẽ đăng câu hỏi mới ngay bây giờ. Cảm ơn bạn. – CVirtuous

2

Bạn lấy và giá trị tuyệt đối của các gradient, ánh xạ tất cả các góc từ [-180; 180] đến [0; 90]. Ngoài ra bạn sử dụng phân chia số nguyên.

+0

Cảm ơn cũ-ufo. Tôi đã sửa vấn đề phân chia số nguyên theo lời khuyên của Paul và tôi chỉ sử dụng dữ liệu 16S trực tiếp từ thao tác Sobel.Tuy nhiên, tôi vẫn nhận được một phạm vi giới hạn chỉ đường từ 0 - 90. Bạn có thấy điều gì khác sai với mã của tôi không? – CVirtuous

+0

Vui lòng cập nhật mã trong bài đăng của bạn để chúng tôi có thể tìm thấy lỗi trong phiên bản _current_. –

4

Bạn có thể nhận x-phái sinh dx và phái sinh phái sinh dy bằng toán tử Sobel. Sau đó, bạn có thể sử dụng công thức để tính toán độ lớn và hướng của gradient. G=sqrt(dx^2+dy^2), theta=arctan(dy/dx). Bạn có thể tìm thấy điều này chỉ là chuyển đổi hệ thống tọa độ descartes (x, y) thành các tọa độ cực (rho, theta)!

Có điều gì đó sai trong mã của bạn mà bạn đặt giá trị tuyệt đối là dxdy, làm cho hướng luôn nằm trong góc phần tư đầu tiên của hệ tọa độ Descartes. Và hàm bạn đã sử dụng convertScaleAbs sẽ chuyển đổi kết quả thành 8 bit, dẫn đến lỗi cắt ngắn.

Tôi có bản trình diễn để tính toán độ lớn một phần dựa trên mã của bạn.

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

Các vấn đề liên quan