2017-02-10 5 views
9

Ich versuche, Lineal auf dem Bild zu erkennen, und ich werde den nächsten Prozess folgen.OpenCV Linien/Lineal Erkennung

1) bereites Bild (Blur, Canny, ect)

2) erkennen von Linien

3) bereiten Satz paralleler Linien

so, ich habe ein Bild: enter image description here

dass app dazu umwandelt: enter image description here

nächste habe ich versuche HoughLinesP Methode und schaue ich es in meinem Fall nicht anwenden kann, weil ich den Winkel der Linien weiß es nicht, so ist es nicht Lineal vertikale Linien gefunden, aber horizontal gefunden (zum Beispiel) und jeder Herrscher Linie besteht aus vielen dünnen Linien, das wird ein Problem Prozess: enter image description here

der Code:

std::vector<cv::Vec4i> lines_std; 
cv::HoughLinesP(grayMat, lines_std, 1, CV_PI/90, 50, 10, 0); 

// drawing lines (with random color) 
for(size_t i = 0; i < lines_std.size(); i++) 
{ 
    cv::line(originalMat, cv::Point(lines_std[i][0], lines_std[i][1]), 
      cv::Point(lines_std[i][2], lines_std[i][3]), cv::Scalar(arc4random_uniform(155)+100, 
                  arc4random_uniform(155)+100, 
                  arc4random_uniform(155)+100), 1); 
} 

auch habe ich LineSegmentDetector versucht, und bekam mehr näher Ergebnis, das ich erwartete: enter image description here

Code:

vector<Vec4f> lines_std; 
Ptr<LineSegmentDetector> ls = createLineSegmentDetector(LSD_REFINE_NONE); 
ls->detect(grayMat, lines_std); 

aber hier stand ich mit einigen Problemen (und sieht es keine Möglichkeit createLineSegmentDetector anzupassen ist): nicht alle Linien erfasst wurden, Linien erkennt in der Mitte nicht aber auf die Seiten und manchmal nur auf der linken oder rechten Seite, aber ich muss die Mitte der fetten Linie bekommen, weil dies in den Berechnungen als nächstes verwendet wird.

Also, was ist der richtige Weg, um alle Linien (und jede Linie nur einmal in der Mitte der fetten Linie) zu finden?

aktualisieren

versucht HoughLines auch:

Vektorlinien;

cv::HoughLines(grayMat, lines, 1, CV_PI/90, 100 , 100, 0); 

for(size_t i = 0; i < lines.size(); i++) 
{ 
    float rho = lines[i][0], theta = lines[i][1]; 
    cv::Point pt1, pt2; 
    double a = cos(theta), b = sin(theta); 
    double x0 = a*rho, y0 = b*rho; 

    pt1.x = cvRound(x0 + 1000*(-b)); 
    pt1.y = cvRound(y0 + 1000*(a)); 
    pt2.x = cvRound(x0 - 1000*(-b)); 
    pt2.y = cvRound(y0 - 1000*(a)); 

    cv::line(originalMat, pt1, pt2, cv::Scalar(0,255,0), 3, CV_AA); 
} 

aber das Ergebnis sieht auch seltsam (und Berechnungen braucht viel Zeit): enter image description here

Antwort

4

Ich glaube, ich die Art und Weise fand ich für folgen sollte:

1) machen Linien dünn wie möglich (nach Canny-Transformation):

cv::Mat skel(grayMat.size(), CV_8UC1, cv::Scalar(0)); 
cv::Mat temp(grayMat.size(), CV_8UC1); 
cv::Mat elementSkel = cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(3, 3)); 

bool done; 
do 
{ 
    cv::morphologyEx(grayMat, temp, cv::MORPH_OPEN, elementSkel); 
    cv::bitwise_not(temp, temp); 
    cv::bitwise_and(grayMat, temp, temp); 
    cv::bitwise_or(skel, temp, skel); 
    cv::erode(grayMat, grayMat, elementSkel); 

    double max; 
    cv::minMaxLoc(grayMat, 0, &max); 
    done = (max == 0); 
} while (!done); 

es sieht wie folgt aus:

enter image description here

2) erfassen Linien mit LineSigmentDetector:

vector<Vec4f> lines_std; 
Ptr<LineSegmentDetector> ls = createLineSegmentDetector(LSD_REFINE_NONE); 
ls->detect(skel, lines_std); 

3) Linienwinkel und Gruppen-IDs durch den Winkel berechnen:

NSMutableDictionary *testHashMap = [[NSMutableDictionary alloc]init]; 

for(size_t i = 0; i < lines_std.size(); i++) 
{ 
    cv::Point p1 = cv::Point(lines_std[i][0], lines_std[i][1]); 
    cv::Point p2 = cv::Point(lines_std[i][2], lines_std[i][3]); 
    int angle = abs(atan2(p1.y - p2.y, p1.x - p2.x)); // int for rounding (for test only) 

    NSMutableArray *idArray=testHashMap[[NSString stringWithFormat:@"%i", angle]]; 
    if(idArray == nil) { 
     idArray = [[NSMutableArray alloc] init]; 
    } 

    [idArray addObject:[NSNumber numberWithInt:i]]; 
    [testHashMap setObject:idArray forKey:[NSString stringWithFormat:@"%i", angle] ]; 
} 

4) gefunden die Lineallinie einstellen und zeichnen:

for(NSInteger i = 0; i < [rulerIds count]; i++) 
{ 
    int itemId = [[rulerIds objectAtIndex:i] integerValue]; 
    cv::Point p1 = cv::Point(lines_std[itemId][0], lines_std[itemId][1]); 
    cv::Point p2 = cv::Point(lines_std[itemId][2], lines_std[itemId][3]); 
    cv::line(originalMat, p1 , p2, cv::Scalar(0,255,0), 1); 
} 

Ergebnis bekam ich:

enter image description here

aktualisieren

aber wenn wir dieses Bild auch noch vergrößern duplizierte Linien sehen Doppelungen zu entfernen habe ich einfache Logik aus, die durch die Gründung Linien fusioniert Durchschnittswert für jeden Punkt, zum Beispiel im Fall von 3 Zeilen (grün) haben wir 3 Punkte am Ende:

enter image description here