2014-09-04 6 views
5

Ich möchte den Radius der roten Kreise berechnen (Bild 2). Ich habe Probleme, diese Kreise mit HoughCircles von OpenCV zu finden. Wie Sie in Abb. 2 Ich kann nur die kleinen Kreise in der Mitte finden, die mit HoughCircles schwarz dargestellt sind.Finde überlappende/komplexe Kreise mit OpenCV

original pic1 Abb 2. red

Da ich in der Mitte der roten Kreise kennen (die die gleiche wie die roten sind), ist es eine Möglichkeit, einfach den Radius der roten Kreise zu berechnen?

Ist es auch möglich, eine generische Art und Weise der Berechnung Radius von Kreisen auf einem komplexeren Bild wie dieser zu haben:

example 2

Edit: Hier ist der interessante Teil meines Codes nach Abb Erhalt 2 :

threshold(maskedImage, maskedImage, thresh, 255, THRESH_BINARY_INV | THRESH_OTSU); 
    std::vector<Vec3f> circles; 
// Canny(maskedImage, maskedImage, thresh, thresh * 2, 3); 

HoughCircles(maskedImage, circles, CV_HOUGH_GRADIENT, 1, src_gray.rows/4, cannyThreshold, accumulatorThreshold, 0, 0); 

Mat display = src_display.clone(); 
for (size_t i = 0; i < circles.size(); i++) 
{ 
    Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); 
    int radius = cvRound(circles[i][2]); 
    // circle center 
    circle(display, center, 3, Scalar(0, 255, 0), -1, 8, 0); 
    // circle outline 
    circle(display, center, radius, Scalar(0, 0, 255), 3, 8, 0); 
} 

Ich habe versucht, spielen mit cannyThreshold und Akku ohne Ergebnisse. Echte Bilder sind 5x Biggers. Hier a link zum Beispiel 1 nach der Schwelle.

Dank

+0

können Sie Ihren HoughCircles-Code anzeigen? Überlappungen/Halbkreise usw. sind normalerweise kein Problem für HoughCircles afaik. – Micka

+0

Vielen Dank Micka Ich habe gerade einen Code hinzugefügt – coincoin

+1

Können Sie maskedImage in eine Datei speichern ('imwrite (" maskedImage.jpg ", maskedImage)') und einen Link posten? –

Antwort

5

Sie kennen bereits die kleineren Kreise im Bild (die Sie in schwarz gezeichnet haben).

  • Bereiten Sie ein Maskenbild mit diesen Kreisen vor, so dass die Bereiche mit kleineren Kreisen Pixel ungleich Null haben. Wir nennen werde es Maske:
  • enter image description here

    • In dem Originalbild, füllen Sie diese Kreisflächen in einer dunklen Farbe (sagen schwarz). Dies wird zu einem Bild wie Ihrer Abbildung 2 führen. Wir nennen es gefüllt
    • Schwellenwert der gefüllt Bild, um die dunklen Bereiche zu erhalten. Wir nennen es binär. Sie können dafür Otsu Thresholding verwenden. Ergebnis wird wie folgt aussehen:

    enter image description here

    • Nehmen Sie die Distanz-Transformation dieser binären Bild. Verwenden Sie hierfür eine genaue Distanzschätzmethode. Wir nennen das dist. Es sieht ungefähr so ​​aus. Die farbige ist nur eine Heatmap für mehr Klarheit:

    enter image description hereenter image description here

    • Verwenden Sie die Maske die Spitzenregionen von dist zu erhalten. Der Maximalwert jeder dieser Regionen sollte Ihnen den Radius des größeren Kreises geben. Sie können auch einige Bearbeitungen in diesen Regionen vornehmen, um einen vernünftigeren Wert für den Radius zu erhalten, als nur den maximalen Wert zu ermitteln.
    • Für die Regionen auswählen, können Sie entweder die Konturen der Maske finden und extrahieren diese Region aus dist Bild, oder, da Sie bereits die kleineren Kreise Anwendung Hough-Kreis verwandeln wissen, bereiten eine Maske aus jeder dieser Kreise und extrahieren diese Region von dist Bild. Ich bin mir nicht sicher, ob du maximale oder andere Werte berechnen kannst, indem du eine Maske gibst. Max wird definitiv funktionieren, weil der Rest der Pixel 0 ist. Sie könnten die Statistiken der Region berechnen, wenn Sie diese Pixel zu einem anderen Array extrahieren.
    • Die folgenden Abbildungen zeigen eine solche Maske und die extrahierte Region von dist. Dafür bekomme ich ein Maximum von 29, was mit dem Radius dieses Kreises übereinstimmt. Beachten Sie, dass die Bilder nicht maßstabsgetreu sind.

      Maske für einen Kreis, extrahiert Region von dist

      enter image description hereenter image description here

      Hier ist der Code (ich bin nicht Hough-Kreise-Transformation):

      Mat im = imread(INPUT_FOLDER_PATH + string("ex1.jpg")); 
      
          Mat gray; 
          cvtColor(im, gray, CV_BGR2GRAY); 
      
          Mat bw; 
          threshold(gray, bw, 0, 255, CV_THRESH_BINARY|CV_THRESH_OTSU); 
          // filtering smaller circles: not using hough-circles transform here. 
          // you can replace this part with you hough-circles code. 
          vector<int> circles; 
          vector<vector<Point>> contours; 
          vector<Vec4i> hierarchy; 
          findContours(bw, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); 
          for(int idx = 0; idx >= 0; idx = hierarchy[idx][0]) 
          { 
           Rect rect = boundingRect(contours[idx]); 
           if (abs(1.0 - ((double)rect.width/rect.height) < .1)) 
           { 
            Mat mask = Mat::zeros(im.rows, im.cols, CV_8U); 
            drawContours(mask, contours, idx, Scalar(255, 255, 255), -1); 
            double area = sum(mask).val[0]/255; 
            double rad = (rect.width + rect.height)/4.0; 
            double circArea = CV_PI*rad*rad; 
            double dif = abs(1.0 - area/circArea); 
            if (dif < .5 && rad < 50 && rad > 30) // restrict the radius 
            { 
             circles.push_back(idx); // store smaller circle contours 
             drawContours(gray, contours, idx, Scalar(0, 0, 0), -1); // fill circles 
            } 
           } 
          } 
      
          threshold(gray, bw, 0, 255, CV_THRESH_BINARY_INV|CV_THRESH_OTSU); 
      
          Mat dist, distColor, color; 
          distanceTransform(bw, dist, CV_DIST_L2, 5); 
          double max; 
          Point maxLoc; 
          minMaxLoc(dist, NULL, &max); 
          dist.convertTo(distColor, CV_8U, 255.0/max); 
          applyColorMap(distColor, color, COLORMAP_JET); 
          imshow("", color); 
          waitKey(); 
      
          // extract dist region corresponding to each smaller circle and find max 
          for(int idx = 0; idx < (int)circles.size(); idx++) 
          { 
           Mat masked; 
           Mat mask = Mat::zeros(im.rows, im.cols, CV_8U); 
           drawContours(mask, contours, circles[idx], Scalar(255, 255, 255), -1); 
           dist.copyTo(masked, mask); 
           minMaxLoc(masked, NULL, &max, NULL, &maxLoc); 
           circle(im, maxLoc, 4, Scalar(0, 255, 0), -1); 
           circle(im, maxLoc, (int)max, Scalar(0, 0, 255), 2); 
           cout << "rad: " << max << endl; 
          } 
          imshow("", im); 
          waitKey(); 
      

      Ergebnisse (skaliert):

      enter image description hereenter image description here

      Hoffe das hilft.

    +0

    Danke, es ist eine nette Idee. Ich habe die gleichen Ergebnisse erhalten, die Sie mit distanceTransform haben. (Übrigens, wie Sie die Entfernung Karte Farbe applyColorMap scheint nicht für mich arbeiten). Aber ich sehe nicht, wie ich Kreise Radius unterscheiden und effektiv diese Maximalwerte berechnen kann? – coincoin

    +1

    In OpenCV wird das Ergebnis der Entfernungstransformation vom Typ float sein. Versuchen Sie, es auf den Bereich 0-255 zu skalieren und konvertieren Sie es in den Typ uint8. Dann wird applyColorMap funktionieren. Wie Sie maximale Werte erhalten, finden Sie in meinem editierten Post, um zu sehen, ob ich Ihre Frage dort beantwortet habe. – dhanushka

    +0

    Vielen Dank für Ihre wertvolle Antwort. Ich habe die Kartenfarbe, aber ich habe Schwierigkeiten zu verstehen, wie ich die Region mit Maskenbildern und der Mitte kleiner Kreise extrahieren kann. Könnten Sie bitte diesen Teil genauer beschreiben? – coincoin