2012-11-23 3 views
7

enter image description here 많은 홈이있는 표면 사진이 있습니다. 대부분의 경우 홈 가공의 가장자리가 평행선을 이루기 때문에 Canny 및 Hough 변형은 선을 감지하고 특성을 파악하는 데 매우 효과적입니다. 그러나 여러 위치에서 그루 빙 가공이 해제되고 모서리가 더 이상 평행하지 않습니다.OpenCV 홈 붙이기 감지

나는 어떤 모서리가 직선인지 또는 직선과의 엇갈림이나 편차가 있는지 쉽게 확인할 수있는 방법을 찾고있다. 선형 보간에서 R square 매개 변수와 같은 것을 생각하고 있습니다. 그러나 여기에는 더 많은 위치 종속적 인 매개 변수가 필요합니다. 가장자리를 특징 짓는 다른 방법이 있습니까?

나니 가장자리 감지 후 그루 빙 그림을 첨부했습니다. 여기서, 모서리는 직선이고 그루브 가공은 양호합니다. 불행히도 지금은 그루브가 손상된 그림을 볼 수 없습니다. 그러나 홈이 파손 된 그림에서는 선이 큰 간격 (그림 크기의 10 % 이상)을 갖거나 평행하지 않습니다.

+0

샘플 이미지를 포함 할 수 있습니까? –

+0

Stackoverflow에 오신 것을 환영합니다. 신중하게 내 대답을 검토 한 다음 도움이된다면 투표하십시오. 질문 옆에있는 확인란을 클릭하여 질문에 대한 공식 답변으로 선택할 수 있습니다. 이런 것들을함으로써 당신은이 스레드를 조직화하여 미래의 방문자들을 돕고 자신과 우리를 도울 것입니다. – karlphillip

답변

6

아래의 공유 기술 그레이 스케일 이미지에서 선분을 찾으려면 cv::HoughLinesP()을 사용하십시오.

입력 이미지를 그레이 스케일로로드하여 응용 프로그램을 시작합니다. 이 시점에서 시각화하는 파일에 기록 될 수있는 검출 된 모든 선분

#include <cv.h> 
#include <highgui.h> 

#include <algorithm> 

// Custom sort method adapted from: http://stackoverflow.com/a/328959/176769 
// This is used later by std::sort() 
struct sort_by_y_coord 
{ 
    bool operator()(cv::Vec4i const& a, cv::Vec4i const& b) const 
    { 
     if (a[1] < b[1]) return true; 

     if (a[1] > b[1]) return false; 

     return false; 
    } 
}; 


int main() 
{ 
    /* Load input image as grayscale */ 

    cv::Mat src = cv::imread("13531682.jpg", 0); 

    /* Pre-process the image to enhance the characteristics we are interested at */ 

    medianBlur(src, src, 5); 

    int erosion_size = 2; 
    cv::Mat element = cv::getStructuringElement(cv::MORPH_CROSS, 
             cv::Size(2 * erosion_size + 1, 2 * erosion_size + 1), 
             cv::Point(erosion_size, erosion_size)); 
    cv::erode(src, src, element); 
    cv::dilate(src, src, element); 

    /* Identify all the lines in the image */ 

    cv::Size size = src.size(); 
    std::vector<cv::Vec4i> total_lines; 
    cv::HoughLinesP(src, total_lines, 1, CV_PI/180, 100, size.width/2.f, 20); 

    int n_lines = total_lines.size(); 
    std::cout << "* Total lines: "<< n_lines << std::endl; 

    cv::Mat disp_lines(size, CV_8UC1, cv::Scalar(0, 0, 0)); 

    // For debugging purposes, the block below writes all the lines into disp_lines 
    // for (unsigned i = 0; i < n_lines; ++i) 
    // { 
    //  cv::line(disp_lines, 
    //    cv::Point(total_lines[i][0], total_lines[i][2]), 
    //    cv::Point(total_lines[i][3], total_lines[i][4]), 
    //    cv::Scalar(255, 0 ,0)); 
    // } 
    // cv::imwrite("total_lines.png", disp_lines); 

: 그럼 cv::HoughLinesP() 의한 검출을 개선하는 것을 목표로, 이미지의 특정 특성을 향상시키는 기본적인 전처리 동작을 수행 목적 :

우리가 cv::HoughLinesP()가 그렇게하지 않기 때문에 라인의 우리의 벡터를 분류하기 위해 필요한이 시점에서

, 우리는 벡터가 측정하고 비교함으로써, 라인 그룹을 식별 할 수 분류 필요 줄 사이의 거리 :

/* Sort lines according to their Y coordinate. 
     The line closest to Y == 0 is at the first position of the vector. 
    */ 

    sort(total_lines.begin(), total_lines.end(), sort_by_y_coord()); 

    /* Separate them according to their (visible) groups */ 

    // Figure out the number of groups by distance between lines 
    std::vector<int> idx_of_groups; // stores the index position where a new group starts 
    idx_of_groups.push_back(0); // the first line indicates the start of the first group 

    // The loop jumps over the first line, since it was already added as a group 
    int y_dist = 35; // the next groups are identified by a minimum of 35 pixels of distance 
    for (unsigned i = 1; i < n_lines; i++) 
    { 
     if ((total_lines[i][5] - total_lines[i-1][6]) >= y_dist) 
     { 
      // current index marks the position of a new group 
      idx_of_groups.push_back(i); 
      std::cout << "* New group located at line #"<< i << std::endl;   
     } 
    } 

    int n_groups = idx_of_groups.size(); 
    std::cout << "* Total groups identified: "<< n_groups << std::endl; 

단순히 새로운 vector<int>에서 라인의 벡터의 인덱스 위치를 저장하는 위의 코드의 마지막 부분은 그래서 우리는 새로운 그룹을 시작하는 줄 알고있다.

예를 들어, 새 벡터에 저장된 인덱스는 0 4 8 12이라고 가정합니다. 기억하십시오 : 그들은 각 그룹의 시작을 정의합니다. 즉, 그룹의 결말은 0, 4-1, 4, 8-1, 8, 12-1, 12입니다. 그것을 알고

, 우리는 다음과 같은 코드 쓰기 :

/* Mark the beginning and end of each group */ 

    for (unsigned i = 0; i < n_groups; i++) 
    { 
     // To do this, we discard the X coordinates of the 2 points from the line, 
     // so we can draw a line from X=0 to X=size.width 

     // beginning 
     cv::line(disp_lines, 
       cv::Point(0, total_lines[ idx_of_groups[i] ][7]), 
       cv::Point(size.width, total_lines[ idx_of_groups[i] ][8]), 
       cv::Scalar(255, 0 ,0)); 

     // end  
     if (i != n_groups-1) 
     { 
      cv::line(disp_lines, 
        cv::Point(0, total_lines[ idx_of_groups[i+1]-1 ][9]), 
        cv::Point(size.width, total_lines[ idx_of_groups[i+1]-1 ][10]), 
        cv::Scalar(255, 0 ,0)); 
     } 
    } 
    // mark the end position of the last group (not done by the loop above)  
    cv::line(disp_lines, 
      cv::Point(0, total_lines[n_lines-1][11]), 
      cv::Point(size.width, total_lines[n_lines-1][12]), 
      cv::Scalar(255, 0 ,0)); 

    /* Save the output image and display it on the screen */ 

    cv::imwrite("groups.png", disp_lines); 

    cv::imshow("groove", disp_lines); 
    cv::waitKey(0); 
    cv::destroyWindow("groove"); 

    return 0; 
} 

을 그리고 결과 이미지는 다음과 같습니다

그것은 완벽하게 일치은 아니지만, 가까이. 여기저기서 약간의 조정으로이 접근법이 훨씬 향상 될 수 있습니다.나는 sort_by_y_coord에 대한 더 똑똑한 논리를 작성함으로써 시작할 것인데, 이는 X 좌표 (즉, 작은 선분)와 X 축에 완벽하게 정렬되지 않은 선들 사이의 거리가 작은 선 (예 : 두 번째 그룹의 선 출력 이미지에서). 이 제안은 응용 프로그램에서 생성 된 첫 번째 이미지를 평가하는 데 시간을 할애하면 훨씬 더 의미가 있습니다.

행운을 빈다.

+1

감사! 우수 답변. – marc

4

즉시 떠오르는 것은 Hough Transform입니다. 이것은 가능한 행을 취하고 그것에 대한 점수를주는 행 공간의 투표 체계입니다. 위에서 링크 된 코드에서 나사 홈이있는 홈/선의 ~ 10 %에 가까운 임계 값을 간단히 설정할 수 있습니다.

+1

선이 평행하지 않거나 구부러진 경우 Marc은 이미지의 NxN 영역에서 Hough를 사용하여 조각 별 직선을 찾을 수 있습니다. 그런 다음 짧은 선 세그먼트를 결합하여 커브를 찾을 수 있습니다. – Rethunk