2014-10-27 33 views
5

http://oi60.tinypic.com/51lkp.jpgOpenCV C++ - Rechteck Erkennung, die unregelmäßige Seite

hat Hallo .. Ich habe Problem mit Rechteck Erkennung, die unregelmäßige Seite (nicht gerade) wie Abbildung oben. tatsächlich mit Methode Houghline kann Zeilen auf dem Rechteck mit einigen Parameterkonfiguration erkennen. Nach der Berechnung schneiden und 4 Ecke, kann ich es in die normale Position drehen.

Aber wenn ich das Bild mit einem anderen Rechteck (andere Größe und immer noch unregelmäßige Seite) ändern, muss ich die Parameter erneut konfigurieren. Dies liegt daran, dass die Linie nicht an vier Seiten erkannt wird, daneben kann die Linie mehr als 4 sein.

Gibt es neben der Houghline noch eine andere Methode, die einfacher ist (erfordert keine Rekonfiguration/schwierige Konfiguration)?

+0

vielleicht können Sie Dilatation und Erosion Sequenzen zu Crea betrachten Um die Eckkoordinaten mit der Konturmethode zu erhalten, müssen Sie ein "normales" Rechteck verwenden. Sie können dann das ursprüngliche Rechteck nachher drehen. –

+0

Das Beispiel "quadrats.cpp" in OpenCV-Beispielen könnte Ihnen helfen. Verwenden Sie eine einfache Schwellenwertfunktion, extrahieren Sie die äußeren Konturen und führen Sie dann eine Polygon-Approximation dieser Konturen durch, wie im Beispiel gezeigt. – dhanushka

+0

Versuchen Sie dies: http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=minarearect#minarearect – Micka

Antwort

5

Auf diese Weise wird das gedrehte Rechteck berechnet, das alle rechteckigen Pixel enthält.

Vielleicht kann man das kombinieren mit Vasanth Antwort, so dass Sie zuerst das Polynom annähern eine regelmäßige Grenze zu kommen und danach das gedrehte Rechteck extrahieren mit cv::minAreaRect

Hier ist mein Code:

int main() 
{ 
    cv::Mat input = cv::imread("../inputData/RotatedRect.png"); 

    // convert to grayscale (you could load as grayscale instead) 
    cv::Mat gray; 
    cv::cvtColor(input,gray, CV_BGR2GRAY); 

    // compute mask (you could use a simple threshold if the image is always as good as the one you provided) 
    cv::Mat mask; 
    cv::threshold(gray, mask, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU); 

    // find contours (if always so easy to segment as your image, you could just add the black/rect pixels to a vector) 
    std::vector<std::vector<cv::Point>> contours; 
    std::vector<cv::Vec4i> hierarchy; 
    cv::findContours(mask,contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); 

    /// Draw contours and find biggest contour (if there are other contours in the image, we assume the biggest one is the desired rect) 
    // drawing here is only for demonstration! 
    int biggestContourIdx = -1; 
    float biggestContourArea = 0; 
    cv::Mat drawing = cv::Mat::zeros(mask.size(), CV_8UC3); 
    for(int i = 0; i< contours.size(); i++) 
    { 
     cv::Scalar color = cv::Scalar(0, 100, 0); 
     drawContours(drawing, contours, i, color, 1, 8, hierarchy, 0, cv::Point()); 

     float ctArea= cv::contourArea(contours[i]); 
     if(ctArea > biggestContourArea) 
     { 
      biggestContourArea = ctArea; 
      biggestContourIdx = i; 
     } 
    } 

    // if no contour found 
    if(biggestContourIdx < 0) 
    { 
     std::cout << "no contour found" << std::endl; 
     return 1; 
    } 

    // compute the rotated bounding rect of the biggest contour! (this is the part that does what you want/need) 
    cv::RotatedRect boundingBox = cv::minAreaRect(contours[biggestContourIdx]); 
    // one thing to remark: this will compute the OUTER boundary box, so maybe you have to erode/dilate if you want something between the ragged lines 



    // draw the rotated rect 
    cv::Point2f corners[4]; 
    boundingBox.points(corners); 
    cv::line(drawing, corners[0], corners[1], cv::Scalar(255,255,255)); 
    cv::line(drawing, corners[1], corners[2], cv::Scalar(255,255,255)); 
    cv::line(drawing, corners[2], corners[3], cv::Scalar(255,255,255)); 
    cv::line(drawing, corners[3], corners[0], cv::Scalar(255,255,255)); 

    // display 
    cv::imshow("input", input); 
    cv::imshow("drawing", drawing); 
    cv::waitKey(0); 

    cv::imwrite("rotatedRect.png",drawing); 

    return 0; 
} 

gibt diese Ergebnis:

enter image description here

+1

danke Micka .. diese Methode funktioniert für mich .. danke auch für die Erklärung in dieser Code – stranger

4

Elementargeometrie, Sie die Koordinaten wo

  • Schwarz Pixelposition mit kleinsten x-Koordinate
  • Schwarz Pixelposition mit dem größten x-Koordinate
  • Schwarz-Pixel finden müssen Lage mit kleinstem y-Koordinate
  • Schwarz Pixelposition mit dem größten y-Koordinaten

Diese 4 Punkte sind die Kanten Ihres Rechtecks.

+0

Danke bikz05, ich schätze deine Antwort, +1 zu Einfachheit – stranger

3

Versuchen Sie folgendes:

1.Run findCountours auf das Bild.

2.Apply approxPolyDP, um die Kontur an ein Rechteck anzunähern. Die Konturseiten werden viel regelmäßiger sein.

3.Segmentieren Sie die rechteckigen Konturen mit moments und/oder Geometrie.

+0

Danke Vasanth, ich schätze deine Antwort, jetzt kenne ich andere Methode neben houghline – stranger