2012-11-23 20 views
7

enter image description here मेरे पास कई ग्रूव के साथ सतह की तस्वीरें हैं। ज्यादातर मामलों में ग्रोइंग फॉर्म के समानांतर समानांतर रेखाएं होती हैं ताकि कैनी और हफ़ ट्रांसफॉर्मेशन लाइनों का पता लगाने और कुछ विशेषता करने के लिए बहुत अच्छा काम कर सकें। हालांकि, कई जगहों पर गड़बड़ी खराब हो जाती है और किनारें समानांतर नहीं होती हैं।ओपनसीवी ग्रूविंग डिटेक्शन

मैं यह जांचने का एक आसान तरीका ढूंढ रहा हूं कि कोई निश्चित किनारा सीधी रेखा है या यदि सीधी रेखा से कोई अंतराल या विचलन हो। मैं रैखिक इंटरपोलेशन में आर वर्ग पैरामीटर की तरह कुछ सोच रहा हूं, लेकिन यहां मुझे एक पैरामीटर चाहिए जो अधिक स्थान-निर्भर है। क्या आपके पास किनारों को चित्रित करने के लिए कोई और तरीका है?

मैंने कैनी एज डिटेक्शन के बाद ग्रोइंग की तस्वीर संलग्न की। यहां, किनारों की सीधी रेखाएं हैं और ग्रोइंग ठीक है। दुर्भाग्य से मुझे इस समय क्षतिग्रस्त ग्रोइंग के साथ चित्रों तक पहुंच नहीं है। हालांकि, क्षतिग्रस्त grooving के साथ चित्रों में, लाइनों में प्रमुख अंतराल (तस्वीर के आकार का कम से कम 10%) होगा या समानांतर नहीं होगा।

+0

शायद आप एक नमूना छवि शामिल कर सकते हैं? –

+0

स्टैक ओवरफ्लो में आपका स्वागत है। कृपया मेरे उत्तर की सावधानीपूर्वक समीक्षा करें, फिर अगर यह आपकी मदद करता है तो इसे वोट दें। आप इसे अपने प्रश्न के आधिकारिक उत्तर के रूप में चुनने के लिए इसके पास स्थित चेकबॉक्स पर क्लिक कर सकते हैं। इस सामान को करके आप इस थ्रेड को व्यवस्थित करके अपने और हमारे जैसे भविष्य के आगंतुकों की सहायता करेंगे। – karlphillip

उत्तर

6

तकनीक का मूल मैं नीचे साझा कर रहा हूं cv::HoughLinesP() का उपयोग ग्रेस्केल छवि में रेखा खंडों को खोजने के लिए करता है।

एप्लिकेशन इनपुट छवि को ग्रेस्केल के रूप में लोड करके शुरू होता है। तो यह एक बुनियादी पूर्व प्रसंस्करण कार्रवाई निष्पादित छवि की कुछ विशेषताओं को बढ़ाने के लिए, पता लगाने 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() कि ऐसा नहीं करता है की जरूरत है, और हम वेक्टर लाइनों के समूहों की पहचान करने के लिए, को मापने और तुलना द्वारा सक्षम होने के लिए हल कर की जरूरत है रेखाओं के बीच दूरी:

/* 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 के लिए एक स्मार्ट तर्क लिखकर शुरू करूंगा, जो एक्स कोऑर्डिनेट्स (यानी छोटे रेखा सेगमेंट) के बीच छोटी दूरी वाली रेखाओं को त्यागना चाहिए, और ऐसी रेखाएं जो एक्स अक्ष पर पूरी तरह से गठबंधन नहीं हैं (जैसे दूसरे समूह में से एक आउटपुट छवि में)। एप्लिकेशन द्वारा उत्पन्न पहली छवि का मूल्यांकन करने के लिए समय निकालने के बाद यह सुझाव अधिक समझ में आता है।

शुभकामनाएं।

+1

धन्यवाद! उत्कृष्ट जवाब – marc

4

दिमाग में तुरंत क्या आता है Hough Transform होगा। यह लाइन स्पेस में एक मतदान योजना है, जो प्रत्येक संभावित रेखा लेती है और आपको इसके लिए स्कोर देती है। कोड से ऊपर जो मैंने लिंक किया है, आप बस एक थ्रेसहोल्ड सेट कर सकते हैं जो ~ 10% खराब ग्रेन/लाइनों का अनुमान लगाता है।

+1

यदि रेखाएं समानांतर नहीं हैं, या यदि वे घुमाए गए हैं, तो मार्क छवि के एनएक्सएन क्षेत्रों में टुकड़े की सीधी रेखाओं को खोजने के लिए हौ का उपयोग कर सकता है। वक्र लाइनों को वक्र खोजने के लिए जोड़ा जा सकता है। – Rethunk

संबंधित मुद्दे