OpenCV – Probleme mit „cvFindContours()“
Nahezu täglich habe ich mit OpenCV zu tun. In der Regel ist es nicht viel, hin und wieder rufe ich einzelne Funktionen auf und nutze regelmäßig das Format „IplImage“, um Bilder bequem zu verwalten. Und ich muss gestehen, dass ich bisher nur die OpenCV 1.0 verwende, was sich aber bald ändern wird. Aber hin und wieder muss ich sehr tief in die Materie eintauchen, da a) die verwendete Funktion unseren Bedürfnissen angepasst werden muss oder b) die Funktion komischerweise nicht das tut, was ich erwarte. Speziell im zweiten Fall wird einem die Arbeit oftmals erschwert. Das liegt unter anderem am wenig kommentierten Quellcode, ein Thema, welches ich sicherlich auch nochmal ansprechen werde. Außerdem werden in der Dokumentation nur Dinge wie grobe Funktion, Parameter und Rückgabewerte angesprochen. Zwar gibt es weiterführende Literatur – ich nutze regelmäßig „O’Reilly – Learning OpenCV“ – jedoch sind die Funktionen in meinen Augen nicht immer ausreichend beschrieben, auch wenn mancher vielleicht anderes denkt.
Aber kommen wir zum eigentlichen Problem: die Funktion „cvFindContours()“. Sinn dieser Funktion ist es, aus einem Bild die Konturen von Objekten herauszufinden (der Name sagt es ja bereits) und in einem Format zu speichern, welches einen einfachen Zugriff auf die gefundenen Konturen ermöglicht. Dabei hat man verschiedene Möglichkeiten die Daten zu speichern, beispielsweise können von Geraden nur Anfangs- und Endpunkt gespeichert werden, was zu einer geringeren Datenmenge führt (weiterführende Informationen und Optionen unter http://opencv.willowgarage.com/documentation/…). Und man kann eigentlich nicht meckern, denn genau das tut diese Funktion auch: sie findet die Konturen.
Das Problem ist jedoch, dass die Funktion im Ausgangsbild einen Rahmen zeichnet. Bei größeren Objekten ist der Rahmen auch nicht weiter wild, jedoch habe ich viel mit sehr dünnen Objekten zu tun. Wenn diese dann am Rand entlanglaufen, werden sie durch den gezeichneten Rahmen überschrieben. Dickere Objekte werden einfach etwas dünner, aber bei einer Breite von einem Pixel wird das Objekt gelöscht oder geteilt. Wie das dann aussieht, seht ihr hier:
Dass das Bild verändert wird, ist zwar angegeben, genauso wie der Hinweis, dass man ggf. eine Kopie anlegen sollte, aber dass relevante Bildteile gleich zu Beginn überschrieben werden können, der Hinweis fehlt. Und was kann man dagegen tun? Nun ja, im Prinzip sollte es reichen, wenn man das Ausgangsbild um zwei Pixel in der Höhe und Breite erweitert (statt 640×480 also 642×482). Somit wird der Rahmen nicht auf das Objekt gelegt und auch dicke Objekte werden nicht verfälscht. Sollte man im Anschluss die Funktion „cvDrawContour()“ verwenden, so kann dort mit dem Parameter „Offset“ diese Vergrößerung des Bildes wieder korrigiert werden.