Raspberry Pi Roboter Vision: Tiefenkarte
Heute wird die gesamte Technologie des "Drohnenbaus" aktiv billiger. Bis auf eine: eine Karte des umgebenden Raums bekommen. Es gibt zwei Extreme: entweder teure Lidars (Tausende von Dollar) und optische Lösungen zum Erstellen einer Tiefenkarte (viele Hundert Dollar) oder ganz normale Lösungen wie Ultraschall-Entfernungsmesser.Aus diesem Grund entstand auf der Grundlage eines kostengünstigen Raspberry Pi mit einer Kamera die Idee, eine Lösung zu finden, die sich in einer leeren Nische befindet und es Ihnen ermöglicht, eine Tiefenkarte „kostengünstig“ zu erhalten. Und dies in einer einfachen Programmiersprache wie Python, damit Anfänger experimentieren können. Eigentlich wollte ich über meine Ergebnisse erzählen. Die resultierenden Skripte mit Beispielfotos können auch auf dem Desktop ausgeführt werden.Tiefenkarte von einer Kamera.
Zunächst ein paar Worte zum optischen Teil. Um eine Tiefenkarte zu erstellen, werden immer zwei Bilder verwendet - von der linken und rechten Kamera. Und wir haben Himbeeren mit einer Kamera. Daher wurde ein optischer Splitter entwickelt, der der Kamera ein Stereopaar verleiht.In einfachen Worten - wenn Sie sich das Foto ansehen, sehen Sie aus der Blackbox zwei Augen der Kamera an. Aber eigentlich ist die Kamera eine. Nur ein bisschen optische Magie.
Das Foto zeigt die zwölfte Iteration des Geräts. Es hat lange gedauert, ein zuverlässiges stabiles Design zu erhalten, das gleichzeitig kostengünstig wäre. Der schwierigste Teil sind die Innenspiegel, die durch Vakuumabscheidung von Aluminium auf Bestellung gefertigt wurden. Wenn Sie Standardspiegel verwenden, bei denen sich die reflektierende Schicht unter dem Glas und nicht darüber befindet, bilden sie an der Verbindungsstelle eine Lücke, die das gesamte Bild radikal beeinträchtigt.Woran werden wir arbeiten?
Das Himbeer-Image von Raspbian Wheezy wurde als Basis verwendet, Python 2.7 und OpenCV 2.4 wurden installiert, also die erforderlichen Pakete für die kleinen Dinge - Matplotlib, Numpy und andere. Alle Arten und ein Link zum fertigen Bild der Karte finden Sie am Ende des Artikels. Eine Beschreibung der Skripte in Form von Lektionen finden Sie auf der ProjektwebsiteVorbereiten eines Bildes zum Erstellen einer Tiefenkarte
Da unsere Lösung nicht aus Metall und ohne hochpräzise Optik besteht, sind durch die Montage kleine Abweichungen von der idealen Geometrie möglich. Außerdem wird die Kamera mit Schrauben am Gerät befestigt, sodass ihre Position möglicherweise nicht ideal ist. Das Problem mit der Position der Kamera wird manuell gelöst, und die Kompensation der "Krümmung" der Baugruppe der Struktur erfolgt in der Software.Skript Eins - Kameraausrichtung
Die Verbindung der Spiegel im Bild sollte idealerweise vertikal und zentriert sein. Es ist schwer, es mit den Augen zu tun, daher wurde das erste Skript erstellt. Es nimmt nur das Bild von der Kamera im Live-Vorschaumodus auf, zeigt es auf dem Bildschirm an und zeichnet in der Mitte der Überlagerung einen weißen Streifen, entlang dessen die Ausrichtung stattfindet. Nachdem die Kamera richtig ausgerichtet ist, ziehen wir die Schrauben fester an und die Montage ist abgeschlossen.Was ist interessant im Code des ersten Skripts- –
- – , cv.imshow() , . , . , , .
- – , .. . «» , camera.hflip = True
Das zweite Skript - wir bekommen ein "sauberes" Stereopaar
Unsere linken und rechten Bilder werden in der Bildmitte zusammengefügt. Die Fuge auf dem Foto hat eine Breite ungleich Null - Sie können sie nur entfernen, indem Sie die Spiegel vom Gerät entfernen, wodurch die Struktur vergrößert wird. Bei der Kamera der Himbeere ist der Fokus auf unendlich eingestellt, und nahe gelegene Objekte (in unserem Fall ist dies eine Kreuzung) verschwimmen einfach. Daher müssen Sie nur dem Skript mitteilen, das unserer Meinung nach eine „schlechte“ Zone ist, damit das Stereopaar sauber in Bilder geschnitten wird. Es wurde ein zweites Skript erstellt, das ein Bild anzeigt und es Ihnen ermöglicht, mit den Tasten die zu schneidende Zone anzugeben.So sieht der Prozess aus:Was ist interessant im Code des zweiten Skripts- , , cv2.rectangle(). , , . , , Enter .
- , . , .
- JSON. , , .
- . , , , . , ./src . . pf_1280_720.txt – , .
- , . . :
loadImagePath = ""
Das dritte Skript - eine Reihe von Fotos zur Kalibrierung
Die Grundlagenforschung sagt, dass das Stereopaar kalibriert werden muss, um eine Tiefenkarte erfolgreich zu erstellen. Alle wichtigen Punkte des linken Bildes sollten sich nämlich auf derselben Höhe und im rechten Bild befinden. In dieser Situation kann die StereoBM-Funktion, die unsere einzige Echtzeitfunktion ist, ihre Aufgabe erfolgreich erfüllen.Für die Kalibrierung müssen wir ein Referenzbild drucken, eine Reihe von Fotos erstellen und es dem Kalibrierungsalgorithmus übergeben, der alle Verzerrungen berechnet und die Parameter speichert, um die Bilder wieder normal zu machen.Drucken Sie also das „ Schachbrett “ aus und kleben Sie es auf eine harte, flache Oberfläche. Der Einfachheit halber wurde für das Serienfoto ein Skript mit einem Countdown-Timer erstellt, das über dem Video angezeigt wird.So sieht das Skript für Serienfotografie bei der Arbeit aus:Was ist interessant im 3. Skriptcode- . , . , , «» . , – , . camera.capture () , use_video_port=True.
- – camera.annotate_text() . 5 – .
- -, , ./src
Es ist zu beachten, dass die „Richtigkeit“ der erstellten Serie für die Kalibrierungsergebnisse entscheidend ist. Wenig später werden wir uns das Ergebnis ansehen, das mit falsch aufgenommenen Fotos erzielt wird.Skript 4 - Schneiden von Fotos auf Stereopaaren
Nachdem eine Reihe von Fotos aufgenommen wurde, erstellen wir ein weiteres Service-Skript, das die gesamte aufgenommene Fotoserie in Bildpaare schneidet - links und rechts - und die Paare in einem Ordner speichert. Zonen in der Bildmitte. Das Skript ist ziemlich gewöhnlich, deshalb habe ich das Video unter einem Spoiler versteckt.Ein Arbeitsbeispiel und ein Link zu den Quellen des 4. Skripts Das Interessanteste ist die Kalibrierung, das fünfte Skript
Das Kalibrierungsskript führt alle Stereopaare aus dem Ordner ./src in die Kalibrierungsfunktion ein und taucht in Gedanken ein. Nach seiner schwierigen Arbeit (für 15 Bilder 1280x720 auf der ersten Himbeere dauert es ungefähr 5 Minuten) nimmt er das letzte Stereopaar, „korrigiert“ die Bilder (korrigiert) und zeigt bereits korrigierte Versionen, mit denen Sie eine Tiefenkarte erstellen können.So sieht das Skript in der Arbeit aus:Was ist interessant im Code des 5. Skripts "Etwas ist schief gelaufen."
Es gibt Zeiten, in denen Kalibrierungsergebnisse unerwartet sind.Hier einige bemerkenswerte Beispiele:
Tatsächlich ist die Kalibrierung ein entscheidender Moment. Was wir bei der Erstellung einer Tiefenkarte erhalten, hängt direkt von ihrer Qualität ab. Nach einer großen Anzahl von Experimenten zeichnete sich die folgende Liste der Schießanforderungen ab:- Das Schachbild sollte nicht parallel zur Ebene des Fotos sein - immer in unterschiedlichen Winkeln. Aber auch ohne Fanatismus - wenn Sie das Brett fast senkrecht zur Ebene des Fotos halten, findet das Skript das Schach einfach nicht auf dem Bild.
- Licht, gutes Licht. Bei schwacher Raumbeleuchtung und selbst beim Herausziehen von Bildern aus dem Video nimmt die Bildqualität ab. In meinem Fall korrigierte Licht in 90% der Fälle sofort die Situation.
- Schreiben Sie im Internet, dass die Karte nach Möglichkeit den maximalen Platz im Bild einnehmen soll. Hilft wirklich.
So sieht ein „festes“ Stereopaar mit guten Kalibrierungsergebnissen aus:
Skript 6 - der erste Versuch, eine Tiefenkarte zu erstellen
Als ob alles fertig wäre - Sie können bereits eine Tiefenkarte erstellen.Wir laden die Kalibrierungsergebnisse, machen ein Foto und erstellen mutig eine Tiefenkarte mit cv2.StereoBM. Wir erhalten ungefähr Folgendes :
Das Ergebnis ist nicht sehr beeindruckend, offensichtlich müssen wir etwas verdrehen. Nun, lassen Sie uns im nächsten, siebten Skript mit der Feinabstimmung fortfahren. Dort werden wir für die Konstruktion nicht 2 Parameter verwenden, wie in StereoBM (), sondern fast 10, was viel interessanter ist.Hier sind die Quellen des 6. SkriptsSkript 7 - Tiefenkarte mit erweiterten Einstellungen
Wenn die Parameter nicht 2, sondern 10 sind, ist das Sortieren ihrer Optionen mit einem ständigen Neustart der Skripte falsch. Daher wurde ein Skript zur bequemen interaktiven Abstimmung der Tiefenkarte erstellt. Die Aufgabe bestand nicht darin, den Code mit der Schnittstelle zu komplizieren, daher wurde alles auf matplotlib erledigt. Das Zeichnen der Oberfläche in matplotlib auf Himbeeren ist ziemlich langsam, daher übertrage ich normalerweise den Arbeitsordner von Himbeeren auf den Laptop und wähle dort die Parameter aus. So funktioniert das Skript:Nachdem Sie die Parameter ausgewählt haben, speichert das Skript über die Schaltfläche Speichern das Ergebnis in der Datei 3dmap_set.txt im JSON-Format.Was ist interessant im Code des 7. Skripts- 7-
- . , - , .
- , . , numOfDisparities 16, . update(val), . numOfDisparities 65.57 64. , .
- matplotlib , .
Die praktische Arbeit mit der Tiefenkarte hat gezeigt, dass Sie zunächst den Parameter minDisparity und in Verbindung damit numOfDisparities auswählen müssen. Denken Sie daran, dass sich numOfDisparities mit Schritt 16 tatsächlich diskret ändert.Nachdem Sie dieses Paar eingerichtet haben, können Sie mit anderen Parametern herumspielen .Die Funktionen der Karteneinstellungen sind bereits eine Frage des Geschmacks des Benutzers und hängen von der zu lösenden Aufgabe ab. Sie können die Karte auf eine große Anzahl kleiner Teile bringen oder vergrößerte Bereiche anzeigen. Für eine einfache Vermeidung von Hindernissen durch Roboter ist die zweite besser geeignet. Für eine Punktwolke treten hier die ersten, aber Leistungsprobleme auf (wir werden darauf zurückkommen).Was wollen wir sehen?
Nun, vielleicht ist einer der wichtigsten Punkte die Einstellung der "Weitsichtigkeit" unseres Geräts. Beim Einrichten der Tiefenkarte platziere ich normalerweise ein Objekt in einem Abstand von etwa 30 cm, das zweite in einem Meter und den Rest zwei Meter weiter. Und wenn ich die ersten beiden Parameter (minDisparity und numOfDisparities) im 7. Skript einrichte, erreiche ich Folgendes:- Nächstes Objekt (30 cm) - rot
- Objekt in einem halben Meter - gelb oder grün
- Objekte 2-3 Meter - grün oder hellblau
Als Ergebnis erhalten wir ein System, das so konfiguriert ist, dass es die "nahe" Zone von Hindernissen in einem Radius von 5 bis 10 Metern erkennt.Arbeiten mit Video on the fly - Skript 8., endgültig
Nun haben wir ein vorgefertigtes kundenspezifisches System, und wir müssten ein praktisches Ergebnis erzielen. Wir versuchen, mithilfe von Videos von unserer Kamera eine Tiefenkarte in Echtzeit zu erstellen und diese beim Aktualisieren in Echtzeit anzuzeigen.Was ist interessant im Code des 8. Skripts Im Rennen um die Geschwindigkeit
Die erste Messung wurde also an der ersten Himbeere mit einem Single-Core-Prozessor durchgeführt.- 4 Sekunden - Erstellen einer Karte auf dem Bild von 1280x720 Das ist viel.- 2,5 Sekunden - auf dem Raspberry Pi 2 schon besser.Die Analyse ergab, dass in diesem Fall nur ein Kern für die zweite Himbeere verwendet wird. Durcheinander! Ich habe OpenCV mithilfe der TBB-Parallelisierungsbibliothek neu erstellt.- 1,5 Sekunden - Starten Sie die zweite Himbeere mit Multi-Core. Tatsächlich stellte sich heraus, dass nur 2 Kerne verwendet werden - daran muss noch gebastelt werden. Es stellte sich heraus, dass nicht nur ich auf dieses Problem gestoßen bin , sondern auch noch Bewegungsspielraum besteht.Nach dem Algorithmus sollte die Betriebsgeschwindigkeit linear von der Größe der verarbeiteten Daten abhängen. Wenn Sie also die Auflösung um das Zweifache reduzieren, sollte theoretisch alles viermal schneller funktionieren.- 0,3 Sekunden oder etwa 3-4 FPS - mit einer halb reduzierten Auflösung von 640 x 360. Die Theorie wurde bestätigt.Weitere Pläne
Zunächst wollte ich das Beste aus dem Multicore der zweiten Himbeere herausholen. Ich werde mir die Quellen der StereoBM-Funktion genauer ansehen und versuchen zu verstehen, warum die Arbeit nicht vollständig verläuft.Die nächste Stufe verspricht viel mehr Abenteuer - dies ist die Verwendung einer Himbeer-GPU, um die Berechnungen zu beschleunigen.Hier werden drei mögliche Wege gezeichnet:Wenn Sie Erfahrung mit TBB für Raspberry OpenCV hatten oder sich mit der Codierung für Himbeer-GPUs befassten, bin ich Ihnen für weitere Hinweise dankbar . Ich habe es aus einem einfachen Grund geschafft, einige vorgefertigte Entwicklungen zu finden - Himbeeren mit zwei Kameras sind selten. Wenn Sie zwei Webcams über USB anschließen, treten große Bremsen auf, und nur Raspberry Pi Compute kann mit zwei nativen Kameras arbeiten, für die auch ein kräftiges Devboard mit Schnürsenkeln und Adaptern erforderlich ist.Nützliche Links:
Arbeitsskripte:OpenCV und Python auf Himbeeren einrichten:StereoVision-Bibliothek:GPU-ArbeitNun, ein interessanter Artikel über den Habr über " Um Bilder zu erkennen, müssen Sie keine Bilder erkennen "Source: https://habr.com/ru/post/de388259/
All Articles