2012-11-23 31 views
7

enter image description here Birçok oluklu bir yüzeyin resimlerine sahibim. Çoğu durumda olukların kenarları paralel çizgiler oluşturur ve böylece Canny ve Hough dönüşümü çizgileri tespit etmek ve bazı karakterizasyonları yapmak için çok iyi çalışır. Bununla birlikte, çeşitli yerlerde kanal açma hasar görür ve kenarlar artık paralel değildir.OpenCV kanal açma algılaması

Belirli bir kenarın düz bir çizgi olup olmadığını veya düz bir çizgiden herhangi bir boşluk veya sapma olup olmadığını kontrol etmenin kolay bir yolunu arıyorum. Doğrusal enterpolasyonda R kare parametresi gibi bir şey düşünmekteyim, fakat burada daha fazla lokasyona bağlı bir parametreye ihtiyacım var. Kenarları nasıl karakterize edeceğiniz konusunda başka bir kehanette var mı?

Canny kenar algılamasından sonra oluğun resmini iliştirdim. Burada kenarlar düz çizgilerdir ve oluklar iyidir. Maalesef şu anda hasarlı kanal açma ile resimlere erişemiyorum. Bununla birlikte, hasarlı oluklu resimlerde, hatların büyük boşlukları olacaktır (resmin boyutunun en az% 10'u) veya paralel olmayacaktır.

+0

Örnek bir resim ekleyebilir misiniz? –

+0

Stackoverflow'a Hoş Geldiniz. Lütfen cevabımı dikkatle gözden geçirin, sonra size yardımcı olursa oy verin. Sorunuzun resmî cevabı olarak seçmek için yakınındaki onay kutusunu tıklayabilirsiniz. Bu işi yaparak, bu iş parçacığını organize ederek kendiniz ve bizim gibi gelecekteki ziyaretçilere yardımcı olacaksınız. – karlphillip

cevap

6

Tekniğin temeli Aşağıdaki paylaşımda bulunmaktayım, gri tonlamalı bir görüntüdeki çizgi parçalarını bulmak için cv::HoughLinesP() kullanır.

Uygulama giriş görüntüsünü gri tonlamalı olarak yükleyerek başlar. Bu noktada, görüntüleme için bir dosyaya yazılır algılanan tüm çizgi parçaları

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

: Sonra cv::HoughLinesP() tarafından gerçekleştirilen algılama geliştirmek amacıyla, görüntünün belli özelliklerini geliştirmek için temel bir ön-işleme işlemi gerçekleştirir amaçları:

biz cv::HoughLinesP() bunu yapmaz çünkü çizgilerin bizim vektör sıralamak gerekir Bu noktada

ve biz vektör ölçerek ve kıyaslayarak, çizgilerin gruplarını tanımlamak edebilmek için tasnif gerek satırlar arasındaki mesafe:

/* 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; 

sadece yeni vector<int> satır vektörü endeks pozisyonlarını saklar Yukarıdaki kod son kısmı bu yüzden yeni bir grup başladığı çizgiler biliyorum. Örneğin, yeni vektörte saklanan dizinlerin: 0 4 8 12 olduğunu varsayalım. Unutmayın: Her bir grubun başlangıç ​​ numarasını tanımlarlar. Yani, grupların bitiş çizgileri: 0, 4-1, 4, 8-1, 8, 12-1, 12. bilerek

, aşağıdaki kodu yazmak:

/* 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; 
} 

Ve çıkan resimdir:

Mükemmel bir maç değil, ama yakın. Burada biraz tweaks ile bu yaklaşım çok daha iyi olabilir.Ben sort_by_y_coord için daha akıllı bir mantık yazarak başlayacağım, bu X koordinatları (yani küçük çizgi parçaları) arasında küçük mesafeler olan satırları ve aynı zamanda X ekseninde mükemmel hizalanmayan satırları (ikinci gruptaki gibi) içermeyen satırları atmalıdır çıktı görüntüsünde). Bu öneri, uygulama tarafından oluşturulan ilk resmi değerlendirmek için zaman ayırdıktan sonra çok daha anlamlı hale gelir.

İyi şanslar.

+1

Teşekkürler! Mükemmel cevap. – marc

4

Akla hemen ne gelirse bir Hough Transform olur. Bu, her olası çizgiyi alan ve size bir puan veren, line-line bir oylama şemasıdır. Yukarıda bağladığım kodda, sadece vidalanmış olukların/çizgilerin yaklaşık% 10'una yaklaşan bir eşik ayarlayabilirsiniz.

+1

Çizgiler tam olarak paralel değilse veya kavisliyse, Marc parçayı düz çizgiler bulmak için görüntünün NxN bölgelerinde Hough kullanabilir. Kısa çizgi parçaları daha sonra eğrileri bulmak için birleştirilebilir. – Rethunk