Grundlagen

Bevor wir jedoch zur praktischen Umsetzung kommen können, werde ich hier erst einmal auf ein paar grundlegende Techniken und Funktionen der Computer Vision, die für das Verständnis der nächsten Abschnitte erforderlich sind, eingehen, für weiterführende Informationen sei auf das Literaturverzeichniss verwiesen.

Was ist Computer Vision

Computer Vision oder auch maschinelles Sehen ist ein Gebiet der Computer Grafik und Robotik, dass sich im Allgemeinen mit der “computergestützte[n] Lösung von Aufgabenstellungen, die sich an den Fähigkeiten des menschlichen visuellen Systems orientieren” [WMS], beschäftigt.

Dabei wird die visuelle Welt über Sensorik aufgenommen, die erlangten visuellen Daten werden verarbeitet, aufbereitet und anschließend zur Informationsgewinnung analysiert und interpretiert (vgl. [CVM], Kap. 1).

Wie funktioniert Computer Vision

Der Ablauf bei der Computer Vision gliedert sich grob in die vier Schritte Aufnahme, Verarbeitung, Analyse und Interpretation. Ein kurzes Beispiel, bei dem alle diese Schritte umgesetzt wurden, befindet sich unter Finden geometrischer Formen im Bild.

Aufnahme

Heutzutage stehen eine Vielzahl von Sensoren zur Bildgewinnung zur Verfügung, angefangen von handelsüblichen Digitalkameras über 3D-Kameras und Laser-Scanner bis hin zu bildgebenden Geräten der Medizintechnik wie Röntgengeräte und Computertomographen.

Verarbeitung

Zur Erleichterung der späteren Analyse können vorher ein paar grundlegende Operationen zur Verbesserung des Bildmaterials vorgenommen werden, wie zum Beispiel die Anpassung der Helligkeit, eine Erhöhung des Kontrastes, Weichzeichnen um Bildrauschen zu entfernen oder die Konvertierung in einen anderen Farbbereich.

Analyse

In der Bildanalyse kann dann eine Segmentierung erfolgen, d.h. eine Abgrenzung einzelner Bildbereiche aufgrund bestimmter Kriterien, wie zum Beispiel die Erzeugung größerer Konturen aufgrund der Farbgebung, die Unterteilung des Bildes in Vordergrund und Hintergrund oder das Finden von Kanten und Linien.

Interpretation

Der komplizierteste Teil ist dann die Interpretation der Daten. Aus mehrdimensionalen Matrizen, die die Farbwerte eines jeden Pixels im Bild enthalten, wird die reale Welt rekonstruiert, um Objekte zu lokalisieren oder Messungen durchzuführen. Dabei erschweren Faktoren wie unterschiedliche Lichtverhältnisse und die Vielfalt der realen Welt die Interpretation ungemein.

Grundlegende Funktionen und Algorithmen

Um die gewünschten Informationen aus den Kamerabildern zu extrahieren, sind in OpenCV verschiedene Funktionen implementiert. Die Funktionsweise von ein paar wichtigen und häufig verwendeten, werde ich in den nächsten Abschnitten erklären.

Entzerren des Kamerabildes

Wenn eine Kamera mit einem Weitwinkelobjektiv mit großem Öffnungswinkel, ein sogenanntes Fischaugenobjektiv, eingesetzt wird, kommt es zu starken Verzerrungen des Bildes, wie in Abbildung 1 dargestellt. Die Verzerrung ist dabei von der Entfernung zum Bildmittelpunkt abhängig, weshalb sie besonders stark in den Randbereichen auftritt.

alternate text

Abbildung 1: Radiale Verzerrung (Quelle: Learning OpenCV [LOCV])

Nachdem eine Kalibrierung der Kamera vorgenommen wurde und die Verzerrung sowie die Intrinsischen Parameter (Zusammenhang zwischen Kamera- und Bildkoordinatensystem) ermittelt wurden, kann das Kamerabild mit Hilfe der OpenCV Funktion remap() zumindest teilweise wieder entzerrt werden.

Hinweise zur Ermittlung der Verzerrung, ein verzerrtes Kamerabild sowie das Ergebnis nach dem Entzerren, sind unter Kalibrierung der Kamera zu finden.

Funktionsweise:

Da die Verzerrung vom Abstand zum Bildmittelpunkt abhängt kann man, nach dem die Verzerrung anhand bekannter Objektpunkte und Bildpunkte bestimmt wurde, eine Funktion in Abhängigkeit vom Radius zur Umrechnung der Koordinaten der verzerrten Bildpunkte in unverzerrte Bildpunkte aufstellen.

alternate text

Abbildung 2: Radiale Verzerrung Radius (Quelle: CarreraCV [CCV])

So wird dann zum Beispiel der verzerrte Bildpunkt Pv in Abbildung 2 in den unverzerrten Bildpunkt Pu überführt.

Perspektivische Transformation

Wenn sich im Bild ein Objekt mit bekannten Abmaßen bzw. festen Seitenverhältnissen, wie zum Beispiel ein Quadrat oder ein Schachbrettmuster befindet, der Blickwinkel auf das Objekt jedoch nicht senkrecht ist, lässt sich die Perspektive so transformieren, als ob man senkrecht auf das Objekt blicken würde.

Im OpenCV SVN existiert dazu unter learning_opencv_v2/ch12_ex12_1.cpp ein Beispielprogramm, besser bekannt als “Birds eye view”, eine angepasste Version mit Beispielbildern befindet sich im Laustracker Repository unter playground/basics/Birds_Eye/.

Beispiel:

Das oben genannte Beispielprogramm wird mit folgendem Befehl compiliert:

Birds_Eye]$ g++ ch12_ex12_1.cpp -o ch12_ex12_1 \
              `pkg-config --cflags opencv --libs opencv`

Danach kann es genutzt werden, um ein Schachbrett-Bild zu transformieren:

Birds_Eye]$ ./ch12_ex12_1 10 6 schachbrett.jpg

Dabei wird beim Aufruf des Programms neben dem Ausgangsbild noch die Größe des Schachbretts als Anzahl der Quadrate in horizontaler und vertikaler Richtung (jeweils minus eins) mit angegeben. Das Ausgangsbild mit Markierungen an den vom Programm gefundenen Eckpunkten sieht man dann in Abbildung 3 und das transformierte Bild ist in Abbildung 4 dargestellt.

alternate text

Abbildung 3: Perspektivische Transformation: Ausgangsbild mit Markierungen

alternate text

Abbildung 4: Perspektivische Transformation: Birds eye view

Funktionsweise:

Zum Transformieren der Perspektive in der Laustracker Software werden später die vier Eckpunkte des Labyrinthes (Objektpunkte) genutzt. Da die realen Abstände bzw. Seitenverhältnisse des Labyrinthes bekannt sind, können die im Kamerabild gefundenen Eckpunkte des Labyrinthes (Bildpunkte) genutzt werden, um eine Transformationsmatrix zu berechnen, die die Bildpunkte in die Objektpunkte (ein ideales Quadrat) überführt. Wird diese Matrix dann auf das Kamerabild angewendet, wird auch dieses transformiert.

Im obigen Schachbrett-Beispiel werden als Objektpunkte die Eckpunkte eines Rechtecks mit den gleichen Seitenverhältnissen wie das abgebildete Schachbrett genutzt.

Die Erode Operation

Zur Nutzung der Erode-Operation existiert in OpenCV die erode() Funktion, zum Testen der Erode-, Dilate- und Morphology-Operation nutze ich das opencv/samples/cpp/morphology2.cpp Programm, als Ausgangsbild dient ein Schwarz-Weiß-Bild der linken unteren Labyrinthecke.

Die Erode-Funktion hat den gleichen Effekt wie die Erosion in der Natur, je nach dem wie groß das Erode-Element, der Kernel ist, werden in Abbildung 5 erst nur vereinzelte weiße Pixel entfernt und später immer größere weiße Bereiche abgetragen.

alternate text

Abbildung 5: Labyrinth Ecke: Links: Original, Mitte: Erode (Kernel Größe: 3), Rechts: Erode (Kernel Größe: 7)

Die Dilate Operation

Die Dilate-Operation macht genau das Gegenteil, sie vergrößert alle Konturen gleichmäßig.

alternate text

Abbildung 6: Labyrinth Ecke: Links: Original, Mitte: Dilate (Kernel Größe: 3), Rechts: Dilate (Kernel Größe: 7)

Die Morphology Operation

Die Morphology-Operation kann entweder genutzt werden, um Konturen zu schließen, d.h. einzelne Flächen, die noch nicht zusammenhängen, sich aber nah beieinander befinden, zu verbinden wie in Abbildung 7 dargestellt, oder dünne Verbindungen zwischen Flächen zu trennen wie in Abbildung 8 dargestellt. Dabei macht die Operation nicht generell alle Flächen breiter oder dünner wie die Erode- oder Dilate-Operation, sondern greift selektiv die Stellen zwischen größeren Konturen an.

alternate text

Abbildung 7: Labyrinth Ecke: Links: Original, Mitte: Morph Close (Kernel Größe: 5), Rechts: Morph Close (Kernel Größe: 17)

alternate text

Abbildung 8: Labyrinth Ecke: Links: Original, Mitte: Morph Open (Kernel Größe: 3), Rechts: Morph Open (Kernel Größe: 11)

Zum Generieren eines Schwarz-Weiß-Bildes zum Lokalisieren der Wände im Labyrinth, wie im Abschnitt Herausfinden wo sich Wände befinden beschrieben, werden diese Operationen (Erode, Dilate, Morphology) dann in der Funktion edm() kombiniert. Dabei gilt es zu beachten, dass diese Operationen je nach Bildgröße und je größer der Kernel ist, sehr viel Rechenzeit beanspruchen. Deshalb müssen sie bei Aufgaben, die regelmäßig durchgeführt werden, wie zum Beispiel das Lokalisieren der Roboter, sparsam eingesetzt werden.

Kantenerkennung – Canny Filter

Zur Demonstration kommt das Canny Detector Demo Programm von opencv/samples/cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp zum Einsatz.

In dem resultierenden Bild (Abbildung 9) sind die Labyrinthfelder gut erkennbar. Später kann das Bild noch weiter verarbeitet werden, um auf die Labyrinthposition oder das Vorhandensein von Wänden zu schließen.

alternate text

Abbildung 9: Canny Detector Demo

Die Hough Lines Transformation

Zur Demonstration kommt das Standard Hough Lines Demo Programm von opencv/samples/cpp/tutorial_code/ImgTrans/HoughLines_Demo.cpp zum Einsatz.

Je nach dem, wie klein man den Schwellwert der Hough Transformation wählt, desto mehr Linien werden im Labyrinthbild (Abbildung 10), in dem zuvor die Kanten mit einem Canny-Filter ermittelt wurden, gefunden.

alternate text

Abbildung 10: Standard Hough Lines Demo

Wie man in Abbildung 10 sehen kann, eignet sich die Hough Lines Transformation zum Beispiel zum Finden das Labyrinthes im Raum, wenn man die Schnittpunkte der äußersten Linien berechnet.

Finden geometrischer Formen im Bild

OpenCV kann auch zum Finden beliebiger geometrischer Formen genutzt werden.

Hier möchte ich kurz, unter Anwendung der oben vorgestellten Funktionen, eine Möglichkeit zum Auffinden von Quadraten vorstellen. Dieser Algorithmus wird auch später zum automatischen Finden des Labyrinthes verwendet, siehe hierzu Variante 2: Automatisch. Der Sourcecode dazu ist in der findSquares() Funktion in laustracker/src/liblaustracker/labyrinth.cpp zu finden.

Zuerst wird das Ausgangsbild (Abbildung 11, Links) in ein Graustufen-Bild umgewandelt (Abbildung 11, Mitte), dann kann der oben schon vorgestellte Canny Algorithmus zum Finden von Kanten genutzt werden. Dabei kommen die Labyrintheinteilungen in Abbildung 11 (Rechts) deutlich zum Vorschein.

alternate text

Abbildung 11: Square Detection: Links: Ausgangsbild, Mitte: Graustufen, Rechts: Canny

Um nicht im Zwischenraum innerhalb der Kanten, die über den Canny Algorithmus ermittelt wurden, ebenfalls Konturen zu finden, wird die Dilate Funktion genutzt, um diese in Abbildung 12 (Links) aufzufüllen. Anschließend wird OpenCV’s findContours() Funktion genutzt, um alle zusammenhängen Flächen, die in Abbildung 12 (Mitte) eingerahmt sind, zu finden. Diese werden dann in Abbildung 12 (Rechts) als Polygone approximiert.

alternate text

Abbildung 12: Square Detection: Links: Dilate, Mitte: Alle Konturen, Rechts: Alle Konturen als Polygon approximiert

Jetzt müssen nur noch die Quadrate ausfindig gemacht werden. Dazu werden in Abbildung 13 (Links) erst alle Polygone aussortiert die keine 4 Ecken haben, danach wird in Abbildung 13 (Mitte) überprüft, ob der Betrag des Kosinus eines jeden Innenwinkels jedes Polygons kleiner als 0,3 ist, denn das entspricht einem Winkel von etwa 90° (degrees(arccos(0.3)) = 72.54, degrees(arccos(-0.3)) = 107.46).

Wenn dies geschehen ist, werden nur noch die Seitenlängen von 2 nicht gegenüberliegenden Seiten des Polygons verglichen. Wenn diese annähernd gleich lang sind, haben wir nur noch Quadrate, wie in Abbildung 13 (Rechts) zu sehen ist.

alternate text

Abbildung 13: Square Detection: Links: Konturen mit 4 Ecken, Mitte: Konturen mit 90° Winkeln, Rechts: Approximierte Quadrate mit ähnlichen Seitenlängen

Der HSV-Farbraum

Zur mathematischen Darstellung der Farbwerte der einzelnen Pixel eines Digitalbildes existieren verschiedene Modelle, sogenannte Farbräume.

Einer der verbreitetsten ist der RGB-Farbraum mit den Kanälen Rot, Grün und Blau. Der RGB-Farbraum wird häufig als Würfel, wie in Abbildung 14 dargestellt, visualisiert. In Grafikanwendungen wird dann jeder der 3 Kanäle durch eine Zahl zwischen zwischen 0 und 255 repräsentiert (Maximalwerte können sich je nach Anwendung unterscheiden).

Digitale Fotografien und Videodaten werden meist im RGB-Farbraum gespeichert. Das liegt vor allem an der technischen Umsetzung der Darstellung am Monitor, denn hier werden die Farben Rot, Grün und Blau additiv gemischt. Läge das Bildmaterial in einem anderen Farbraum vor, müsste erst jedes Bild konvertiert werden, dass in den Anfängen der Computertechnik unnötig viel Rechenleistung verbraucht hätte.

alternate text

Abbildung 14: Der RGB-Farbraum (Quelle: Wikipedia [WHSV])

Diese Darstellung der Farbwerte ist allerdings nicht sehr intuitiv. In Abbildung 14 fällt es zum Beispiel schwer, anhand der RGB-Farbverläufe ein Kriterium aufzustellen, für welche drei Bereiche von R, G und B ein Pixel als Rot einzustufen ist.

Einer der ersten Verarbeitungsschritte, die später mit den Kamerabildern durchgeführt werden, ist daher die Konvertierung vom RGB-Farbraum in den HSV-Farbraum mit den Kanälen H (Hue, Farbton), S (Saturation, Sättigung) und V (Value, Hellwert).

Als Modell für den HSV-Farbraum kommt, wie in Abbildung 14 dargestellt, ein Zylinder zum Einsatz.

alternate text

Abbildung 15: Der HSV-Farbraum (Quelle: Wikipedia [WHSV])

Noch schöner, als im obigen Modell, sieht man die Nützlichkeit des HSV-Farbraums an den Farbreglern in Gimp (Abbildung 18). Über den Regler für H lässt sich sofort ein Farbbereich für die grüne Farbe finden, während es nahezu unmöglich ist, ohne zu probieren, auf die Position der Regler für R, G und B zu schließen, um die Farbe Grün zu erhalten.

Bestimmen der Grenzwerte zum Finden der LEDs

Zur Bestimmung der HSV-Grenzwerte zum Finden einer LED macht man als erstes mit dem ueyedemo-Programm bei kurzer Belichtungszeit ein Bild von dem Labyrinth, bei dem nur noch die LEDs auf den Robotern gut erkennbar sind.

alternate text

Abbildung 16: Kamerabild mit 8 mm LEDs bei kurzer Belichtungszeit

Jetzt wird das Bild in Gimp geöffnet und mit dem “Color Picker Tool” auf eine der LEDs geklickt (hier die Blaue), so dass die Farbe der LED ausgewählt ist.

alternate text

Abbildung 17: Kamerabild geöffnet in Gimp

Dann wird auf das “Foreground Color” Feld in der Palette geklickt, damit sich der Dialog “Change Foreground Color” öffnet, wo mit den einzelnen Reglern experimentiert werden kann, um die Grenzwerte für die Farbbereiche zum Finden der LEDs zu bestimmen.

alternate text

Abbildung 18: Dialog zum Ändern der Vordergrundfarbe in Gimp

In dem Dialog sind gleich die HSV-Werte sichtbar, der Regler für H seht in Abbildung 18 auf 235 für Blau, durch Verschieben nach links und rechts lässt sich der Bereich für Blau von ungefähr 200 bis 265 eingrenzen.

In der Konfigurationsdatei laustracker/share/laustracker/robots.conf werden die Grenzwerte für die einzelnen Farben dann definiert:

[gimp_colors]
hsv_bluemin = 200 85 70
hsv_bluemax = 265 100 100
hsv_redmin_1 = 325 50 40
hsv_redmax_1 = 360 100 100
hsv_redmin_2 = 0 40 40
hsv_redmax_2 = 80 100 100
hsv_whitemin = 0 0 50
hsv_whitemax = 360 80 100

Bei den Werten für hsv_bluemin und hsv_bluemax sind die beiden Werte von oben, 200 und 265 ersichtlich. Da bei Gimp der Maximalwert für H bei 360 liegt, bei OpenCV aber nur bei 179, werden die Werte von Gimp nach dem Einlesen noch in den Wertebereich von OpenCV umgerechnet.

Der Wert für Blau lässt sich beispielsweise durch Multiplikation mit (179.0 / 360) in den Wertebereich für OpenCV übertragen, die restlichen Umrechnungen erfolgen in der Datei robots.cpp in der Funktion load_robots_conf().

Die anderen zwei Werte entsprechen noch der Sättigung sowie dem Hellwert.

Da sich der Farbbereich für Rot über das Ende des Reglers hinaus erstreckt, wurden entsprechend 2 Bereiche für Rot definiert (hsv_redmin_1 und hsv_redmin_2), die dann intern addiert werden.

alternate text

Abbildung 19: Das Programm laustracker-cli wurde zu Finden der LEDs benutzt.

Später gehe ich noch weiter auf die einzelnen Programme ein, für das obige Bild wurde das Programm laustracker-cli benutzt um mit Hilfe der neuen Grenzwerte in dem oben schon verwendeten Kamerabild nach Robotern zu suchen.