Möchte man ein Kamerabild verwenden um einer Linie zu folgen, so kann man im Gegensatz zur Verwendung von Reflexionssensoren, die nur Werte an der aktuellen Position liefern, damit ergänzend "weiter nach vorne blicken" um umfassendere Informationen für Navigations-Berechnungen zu erhalten. Dazu lassen sich bei der Auswertung von Bilddaten mit einer OpenMV Cam unterschiedliche Bereiche - sogenannte ROIs (Regions Of Interest) festlegen - in denen man blobs (Farbbereiche mit speziellen Eigenschaften) sucht.
Für die Berechnung entsprechender Richtungskorrekturen beim Folgen einer Linie kann man z. B. drei ROIs (in der Abbildung grün dargestellt) festlegen, in denen man den Mittelpunkt eines schwarzen Farbbereichs sucht - einmal ganz am unteren Rand des Bildes (also nahe am Roboter), einmal in der Mitte und einmal am oberen Rand des Bildes, was dann dem am weitesten vom Roboter entfernten Bereich entspricht.
In der folgenden Abbildung erkennt man die drei blobs mit ihren Mittelpunkten, die in den drei ROIs gefunden wurden und sehr gute Informationen für die Steuerung eines Roboters entlang einer Linie liefern.
Das Python-Skript zum Finden von blobs und deren Mittelpunkten in drei ROIs
import sensor, image, time, math
GRAYSCALE_THRESHOLD = [(0, 64)]
ROIS = [
(0, 100, 160, 20),
(0, 50, 160, 20),
(0, 0, 160, 20)
]
sensor.reset()
sensor.set_pixformat(sensor.GRAYSCALE)
sensor.set_framesize(sensor.QQVGA)
sensor.set_vflip(True)
sensor.set_hmirror(True)
sensor.skip_frames(time = 2000)
sensor.set_auto_gain(False)
sensor.set_auto_whitebal(False)
while(True):
img = sensor.snapshot()
i = 1
ausgabe = ""
for r in ROIS:
blobs = img.find_blobs(GRAYSCALE_THRESHOLD, roi=r[0:4], merge=True)
if blobs:
largest_blob = max(blobs, key=lambda b: b.pixels())
img.draw_rectangle(largest_blob.rect())
img.draw_cross(largest_blob.cx(), largest_blob.cy())
ausgabe = ausgabe + "R" + str(i) + " x:" + str(largest_blob.cx()) + " y:" + str(largest_blob.cy()) + " "
i=i+1
print(ausgabe)
Erklärungen zu diesem Programmbeispiel
Zeile 3: GRAYSCALE_THRESHOLD = [(0, 64)]
Hier wird ein Bereich festgelegt, in dem Grauwerte in einem Bild als "schwarz" interpretiert werden.
Zeile 5-9: ROIS =[ ... ]
Mit diesen Angaben werden die, in der oberen Abbildung grün dargestellten Rechtecke für die drei ROIs festgelegt. Es sind dies jeweils die x,y-Koordinaten des linken oberen Eckpunkts, sowie die Breite und die Höhes des jeweiligen Rechtecks.
Zeile 11: sensor.reset()
Mit dieser Funktion wird der Kamerasensor initialisiert.
Zeile 12: sensor.set_pixformat(sensor.GRAYSCALE)
Hiermit wird festgelegt, dass die Farbwerte eines Kamerabbildes als Graustufen aufgenommen werden. Die Informationen über den Grauwert eines Pixesl werden mit Zahlen von 0 (schwarz) bis 255 (weiß) beschrieben.
Zeile 13: sensor.set_framesize(sensor.QQVGA)
In dieser Zeile wird die Größe eines aufgenommenen Bildes auf 160x120 Pixel festgelegt.
Zeile 14, 15: sensor.set_vflip(True) sensor.set_hmirror(True)
Das Setzen dieser beiden Einstellungen bezieht sich speziell auf die Montage einer OpenMV Cam auf einem Roboter, bei dem das Kameraboard so angebracht ist, dass die USB-Buchse nach oben zeigt. In diesem Fall muss das aufgenommene Bild für die weitere Verarbeitung vertikal und horizontal gespiegelt werden.
Zeile 16: sensor.skip_frames(t = 2000)
Die Funktion sensor.skip_frames(t = 2000) sollte immer aufgerufen werden, um das Kamerabild nach Änderung der Kameraeinstellungen (z. B. Farbformat oder Bildgröße) zu stabilisieren. In diesem Fall wird 2000 ms gewartet, bis mit der Auswertung der Bilddaten begonnen wird.
Zeile 17: sensor.set_auto_gain(False)
Damit wird die automatische Helligkeitsverstärkung des Sensors deaktiviert. Der Sensor startet grundsätzlich mit aktivierter automatischer Helligkeitsverstärkung, was bei der Auswertung von Graustufen-Bildern zu Problemen führen kann, bei der fixe Grauwerte bei der Analyse von Bilddaten benötigt werden.
Zeile 18: sensor.set_auto_whitebal(False)
Bei einem automatischen Weißabgleich werden die Farben eines Bildes laufend so angepasst, dass neutrale Farben (wie Weiß) unter verschiedenen Lichtbedingungen korrekt wiedergegeben werden. Möchte man bei der Auswertung von Bilddaten Farben erkennen, so wird eine konstante Verstärkung der Rot-, Grün- und Blauwerte benötigt. Dieser automatische Weißabgleich wird mit der Funktion sensor.set_auto_whitebal(False) ausgeschaltet.
Zeile 21: img = sensor.snapshot()
In dieser Zeile wird ein Bild des Kamerasensors aufgenommen und im Objekt img abgeleget.
Zeile 22,23: i = 1 ausgabe = ""
Die beiden Variablen i und ausgabe werden für die Anzeige der Mittelpunkte von gefundenen blobs im Serial Terminal benötigt.
Zeile 24: for r in ROIS:
Innerhalb dieser Schleife wird ein Suchbereich (ROI) nach dem anderen analysiert.
Zeile 25: blobs = img.find_blobs(GRAYSCALE_THRESHOLD, roi=r[0:4], merge=True)
Mit der Funktion img.find_blobs() werden im aufgenommenen Bild alle Farbbereiche gesucht, welche den Grauwerten in GRAYSCALE_THRESHOLD entsprechen. Ergänzend wird hier mit roi=r[0:4] ein Auschnitt des Bildes angegeben, der untersucht werden soll, wie auch mit merge=True, dass mehrere gefundene blobs, die sich überschneiden, zu einem großen blob zusammengefasst werden sollen.
Zeile 26: if blobs:
Diese Abfrage überprüft, ob zuvor mit img.find_blobs() ein Bereich mit den gewünschten Vorgaben gefunden wurde.
Zeile 27: largest_blob = max(blobs, key=lambda b: b.pixels()):
Aus den gefundenen blobs im untersuchten Bereich wird der größte gefundene Farbbereich ausgewählt, da dieser mit großer Wahrscheinlichkeit einen Bereich der schwarzen Linie beinhaltet, auch wenn zusätzlich mehrere kleinere blobs gefunden wurden, die in den vorgegebenen Graustufenbereich fallen.
Zeile 28: img.draw_rectangle(largest_blob.rect())
Mit der Funktion img.draw_rectangle(largest_blob.rect()) wird im LIVE-Bild der OpenMV IDE ein Rechteck eingezeichnet, das den größten gefundenen Farbbereich umfasst.
Zeile 29: img.draw_cross(largest_blob.cx(), largest_blob.cy())
In der Mitte der jeweiligen Rechtecke wird mit der Funktion img.draw_cross(largest_blob.cx(), largest_blob.cy()) ein Kreuz gezeichnet. Mit den beiden Funktionen largest_blob.cx() und largest_blob.cy() können die Koordinaten des Mittelpunkts eines blobs ermittelt werden.
Zeile 30: ausgabe = ausgabe + "R" + str(i) + " x:" + str(largest_blob.cx()) + " y:" + str(largest_blob.cy()) + " "
Hier wird ein String zur Ausgabe im Serial Terminal zusammengestellt. Dabei werden die für die drei gefundenen blobs in den drei ROIs die Koordinaten der Mittelpunkte angezeigt.