1

Ich begann mit dem Lesen Mat.Warum erzeugt DrawContour() in OpenCV diese seltsame Maske?

enter image description here

Dann konvertiert ich es Graustufen- und angewendet Imgproc.canny() es, die folgende Maske bekommen.

enter image description here

Dann habe ich Imgproc.findContours() die Konturen zu finden, Imgproc.drawContours() und Core.putText() die Konturen mit Zahlen zu beschriften:

enter image description here

Dann habe ich Rect boundingRect = Imgproc.boundingRect(contours.get(0)); Mat submatrix = new Mat(); submatrix = originalMat.submat(boundingRect); zu erhalten folgende submatrix:

enter image description here

So weit so gut. Das Problem beginnt hiernach:

JETZT BRAUCHT ICH EINE MASKE DER submatrix. Also beschloss ich, Imgproc.drawContours() zu verwenden, um die Maske zu bekommen:

Mat mask = new Mat(submatrix.rows(), submatrix.cols(), CvType.CV_8UC1); 
     List<MatOfPoint> contourList = new ArrayList<>(); 
     contourList.add(contours.get(0)); 
     Imgproc.drawContours(mask, contourList, 0, new Scalar(255), -1); 

Ich habe die folgende Maske:

enter image description here

, was ich auf einen gefüllten erwartete (in weißer Farbe) Rautenform schwarzer Hintergrund.

WARUM bekomme ich dieses unerwartete Ergebnis?


EDIT:

  1. Als ich Mat mask = new Mat(submatrix.rows(), submatrix.cols(), CvType.CV_8UC1); von Mat mask = Mat.zeros(submatrix.rows(), submatrix.cols(), CvType.CV_8UC1);, die letzten Maske mit weißen Farbe Müll wurde von einer leeren schwarzen Maske ohne jede weiße Farbe ersetzt ersetzt darauf. Ich habe die folgende submat und Maske:

    enter image description hereenter image description here

  2. Ich wurde in der Liste der Konturen (benannt contours) durch contours.get(0), und mit dieser ersten Kontur berechnen Imgproc.boundingRect() auch die erste Kontur bekommen wie in contourList.add(contours.get(0)); später (wo contourList ist die Liste von nur einer Kontur, die in der letzten drawContours() verwendet wird).

    Dann ging ich weiter contours.get(0) zu contours.get(1) in Imgproc.boundingRect() sowie in contourList.add(); (kurz vor Imgproc.drawContours()) zu ändern. Die führte in diesem submat und Maske:

    enter image description hereenter image description here

  3. Dann wechselte ich in Imgproc.boundingRect() zu contours.get(0) zurück; und lassen Sie contourList.add(contours.get(1)); da sein. Haben Sie den folgenden submat und Maske:

    enter image description hereenter image description here

jetzt bin ich völlig unfähig, zu verstehen, was hier geschieht.

Antwort

2

Ich bin nicht sicher, wie dies in JAVA behandeln ist (ich benutze in der Regel OpenCV in C++ oder Python), aber es ist ein Fehler im Code ...

Die contours Liste eine Liste der Liste haben von Punkten. Diese Punkte beziehen sich auf das Originalbild. Also, das heißt, wenn die Zahl eins ist in, sagen wir mal, x=300, y= 300, width= 100, height=100, dann, wenn Sie Ihre Submatrix bekommen, wird es versuchen, diese Punkte in einem kleineren Bild zu zeichnen ... so, wenn es versucht, Punkt (300,300) in einem 100 x 100 Bild zu zeichnen, es wird einfach fehlschlagen ... wahrscheinlich einen Fehler wirft oder einfach nichts zeichnet ...

Eine Lösung dafür ist, machen Sie eine for-Schleife und subtrahieren Sie zu jedem Punkt der Kontur den Anfangspunkt des begrenzenden rect (in meinem Beispiel (300,300)).

Wie, warum gibt es Müll gezeichnet ... naja, Sie initialisieren nie die Matrix. Nicht sicher in JAVA, aber in C++ müssen Sie sie auf 0 gesetzt denke ich, es so etwas wie dies sein sollte:

Mat mask = new Mat(submatrix.rows(), submatrix.cols(), CvType.CV_8UC1, new Scalar(0)); 

Ich hoffe, das hilft :)

EDIT

Ich glaube, ich habe mich vorher nicht klar genug erklärt.

Ihre Konturen sind eine Anordnung von Punkten (x, y). Dies sind die Koordinaten der Punkte, die jede Kontur im Originalbild darstellen. Dieses Bild hat eine Größe und Ihre Submatrix hat eine kleinere Größe. Die Punkte sind außerhalb dieses kleinen Bildgrenzen ....

Sie so etwas tun sollte, es zu beheben:

for (int j = 0; j < contours[0].length; j++) { 
    contours[0][j].x -= boundingrect.x; 
    contours[0][j].y -= boundingrect.y; 
} 

und dann können Sie die Konturen zeichnen, da sie in Grenzen der sein wird, Untermat.

ich in Java denke, es ist auch möglich, die opencv Punkte direkt zu subtrahieren:

for (int j = 0; j < contours[0].length; j++) { 
    contours[0][j] -= boundingrect.tl(); 
} 

aber in diesem Fall bin ich nicht sicher, da ich es in c versucht haben ++ nur

boundingrect.tl() -> gibt Ihnen den oberen linken Punkt der Rect

+0

Ich hatte versucht, 'neue Mat (submatrix.rows(), submatrix.cols(), CvType.CV_8UC1, neue Skalar (0));', aber das hatte nicht funktioniert. Aber 'Mat.zeros()' funktioniert. Ich habe ein paar andere Sachen ausprobiert, die mich mehr verwirrt haben. Können Sie die Änderung am Ende meiner Frage sehen? – Solace

+1

@Solace Ich aktualisierte die Antwort – api55

+0

Vielen Dank für die Lösung meines Problems. Ich konnte die anfängliche Antwort nicht vollständig verstehen, aber danke für die Klärung in der Bearbeitung. In Java musste ich die Kontur (deren Typ ist "MatOfPoint") in ein Array von "Points" umwandeln und dann manipulierte ich die 'x' und' y' Koordinaten von jedem 'Point':' Point [] pointsArray = contours. get (0) .toArray(); \t \t \t für (int pointIndex = 0; pointIndex Solace