Erkundung von OpenCV auf StereoPi: Tiefenkarte aus Video



Heute möchten wir eine Reihe von Beispielen in Python für OpenCV-Lernende auf dem Raspberry Pi veröffentlichen, und zwar für das Zweikammer-StereoPi-Board. Der fertige Code (plus das Raspbian-Bild) hilft Ihnen bei allen Schritten, beginnend mit der Aufnahme eines Bildes und endend mit dem Abrufen einer Tiefenkarte aus dem aufgenommenen Video.

Einführung


Ich muss sofort betonen, dass diese Beispiele für ein bequemes Eintauchen in das Thema und nicht für eine Produktionslösung gedacht sind. Wenn Sie ein fortgeschrittener OpenCV-Benutzer sind und sich mit Himbeeren beschäftigt haben, wissen Sie, dass es für vollwertige Arbeiten ratsam ist, einen Biss zu codieren und sogar eine Himbeer-GPU zu verwenden. Am Ende des Artikels werde ich näher auf die „Engpässe“ der Python-Lösung und die Gesamtleistung eingehen.

Womit arbeiten wir?


Wir haben so ein Setup wie Eisen:



StereoPi-Karte an Bord des Raspberry Pi Compute Module 3+. Die beiden einfachsten Kameras sind für die Raspberry Pi Version V1 (am ov5647-Sensor) angeschlossen.

Was ist installiert:

  • Raspbian Stretch (Kernel 4.14.98-v7 +)
  • Python 3.5.3
  • OpenCV 3.4.4 (vorkompiliert, 'pip' von Python Wheels)
  • Picamera 1.13
  • StereoVision lib 1.0.3 (https://github.com/erget/StereoVision)

Die Installation der gesamten Software geht über den Rahmen dieses Artikels hinaus. Wir empfehlen lediglich, das fertige Raspbian-Image herunterzuladen (Links zum Github am Ende des Artikels).

Schritt eins: Nehmen Sie ein Bild auf


Verwenden Sie dazu das Skript 1_test.py

Öffnen Sie die Konsole und wechseln Sie vom Basisordner zum Ordner mit Beispielen:

cd stereopi-tutorial 

Führen Sie das Skript aus:

 python 1_test.py 

Nach dem Start wird eine Vorschau unseres Stereobildes auf dem Bildschirm angezeigt. Der Vorgang kann durch Drücken der Q-Taste unterbrochen werden. Dadurch wird das zuletzt aufgenommene Bild gespeichert, das in einem der folgenden Skripte zum Konfigurieren der Tiefenkarte verwendet wird.

Mit diesem Skript können Sie sicherstellen, dass die gesamte Hardware ordnungsgemäß funktioniert, und das erste Bild für die zukünftige Verwendung abrufen.

So sieht das erste Skript aus:


Schritt zwei: Sammeln Sie Bilder zur Kalibrierung


Wenn wir über ein kugelförmiges Pferd im Vakuum sprechen, benötigen wir zwei absolut identische Kameras, deren vertikale und optische Achse perfekt parallel sind und deren horizontale Achsen zusammenfallen, um eine Tiefenkarte von guter Qualität zu erhalten. In der realen Welt unterscheiden sich jedoch alle Kameras geringfügig, und es ist nicht möglich, sie perfekt anzuordnen. Daher wurde ein Software-Kalibrierungstrick erfunden. Mit zwei Kameras aus der realen Welt wird eine große Anzahl von Bildern eines zuvor bekannten Objekts aufgenommen (wir haben ein Bild mit einem Schachbrett), und dann berechnet ein spezieller Algorithmus alle „Unvollkommenheiten“ und versucht, die Bilder so zu korrigieren, dass sie nahezu ideal sind.

Dieses Skript erledigt die erste Phase der Arbeit, nämlich das Erstellen einer Reihe von Fotos zur Kalibrierung.

Vor jedem Foto startet das Skript einen Countdown von 5 Sekunden. Diese Zeit reicht in der Regel aus, um das Board an eine neue Position zu bringen, um sicherzustellen, dass es bei beiden Kameras nicht über die Kanten kriecht, und um seine Position zu fixieren (damit das Foto keine Unschärfe aufweist). Standardmäßig ist die Seriengröße auf 30 Fotos eingestellt.

Start:

 python 2_chess_cycle.py 

Prozess:


Als Ergebnis haben wir eine Reihe von Fotos im Ordner / scene.

Wir schneiden Bilder in Paare


Das dritte Skript 3_pairs_cut.py schneidet die aufgenommenen Fotos in "linke" und "rechte" Bilder und speichert sie im Ordner / pair. Tatsächlich könnten wir dieses Skript ausschließen und das Schneiden im laufenden Betrieb durchführen, aber es ist in weiteren Experimenten sehr nützlich. Sie können beispielsweise Slices aus verschiedenen Serien speichern, Ihre Skripte verwenden, um mit diesen Paaren zu arbeiten, oder sogar Bilder, die mit anderen Stereokameras aufgenommen wurden, paarweise entfernen.

Außerdem zeigt das Skript vor dem Ausschneiden jedes Bilds das Bild an, sodass Sie häufig fehlgeschlagene Fotos vor dem nächsten Kalibrierungsschritt anzeigen und einfach löschen können.

Führen Sie das Skript aus:

 python 3_pairs_cut.py 

Kurzes Video:


Im fertigen Bild gibt es eine Reihe von Fotos und Schnittpaaren, die wir für unsere Experimente verwendet haben.

Kalibrierung


Das Skript 4_calibration.py zeichnet alle Paare mit den Schachbrettern und berechnet die notwendigen Korrekturen, um die Bilder zu korrigieren. Das Skript lehnte Fotos, auf denen kein Schachbrett gefunden wurde, automatisch ab, sodass bei erfolglosen Fotos die Arbeit nicht unterbrochen wird. Nachdem alle 30 Bildpaare hochgeladen wurden, beginnt die Berechnung. Bei uns dauert es ungefähr anderthalb Minuten. Nach Abschluss nimmt das Skript eines der Stereopaare auf und „korrigiert“ diese auf der Grundlage der berechneten Kalibrierungsparameter, wobei ein korrigiertes Bild auf dem Bildschirm angezeigt wird. An dieser Stelle können Sie die Qualität der Kalibrierung bewerten.

Mit Befehl ausführen:

 python 4_calibration.py 

Kalibrierungsskript in Arbeit:


Tiefenkarten-Setup


Das Skript 5_dm_tune.py lädt das vom ersten Skript aufgenommene Bild und die Kalibrierungsergebnisse. Als nächstes wird eine Oberfläche angezeigt, über die Sie die Einstellungen der Tiefenkarte ändern und sehen können, welche Änderungen vorgenommen wurden. Tipp: Bevor Sie die Parameter einstellen, nehmen Sie einen Rahmen, in dem Sie gleichzeitig Objekte in unterschiedlichen Entfernungen haben: in der Nähe (30-40 Zentimeter), in einer durchschnittlichen Entfernung (Meter oder zwei) und in der Entfernung. Auf diese Weise können Sie die Parameter auswählen, bei denen nahe Objekte rot und entfernte Objekte dunkelblau sind.

Das Bild enthält eine Datei mit unseren Tiefenkarteneinstellungen. Sie können unsere Einstellungen in ein Skript laden, indem Sie einfach auf die Schaltfläche „Einstellungen laden“ klicken

Wir starten:

 python 5_dm_tune.py 

So sieht der Einrichtungsprozess aus:


Echtzeit-Tiefenkarte


Das letzte Skript 6_dm_video.py erstellt aus dem Video eine Tiefenkarte unter Verwendung der Ergebnisse vorheriger Skripte (Kalibrierung und Einstellung der Tiefenkarte).

Start:

 python 6_dm_video.py 

Eigentlich das Ergebnis:


Wir hoffen, dass unsere Skripte für Ihre Experimente nützlich sind!

Nur für den Fall, ich möchte hinzufügen, dass alle Skripte über eine Tastenanschlagverarbeitung verfügen und Sie die Arbeit unterbrechen können, indem Sie die Q-Taste drücken. Wenn Sie "grob" stoppen, z. B. Strg + C, kann der Prozess der Python-Interaktion mit der Kamera unterbrochen werden und ein Himbeer-Neustart ist erforderlich.

Für Fortgeschrittene


  • Das erste Skript im Prozess zeigt die durchschnittliche Zeit zwischen den Frame-Erfassungen und nach Abschluss die durchschnittliche FPS an. Dies ist ein einfaches und bequemes Werkzeug zum Auswählen solcher Bildparameter, bei denen die Python immer noch nicht "erstickt". Damit haben wir 1280x480 mit 20 FPS aufgenommen, in denen das Video ohne Verzögerung gerendert wird.
  • Möglicherweise stellen wir fest, dass wir ein Stereopaar in einer Auflösung von 1280 x 480 erfassen und dann auf 640 x 240 skalieren.

    Eine vernünftige Frage: Warum all das und warum nicht sofort das Miniaturbild greifen und unsere Python nicht durch Reduzieren laden?

    Antwort: Bei der direkten Aufnahme mit sehr niedrigen Auflösungen treten immer noch Probleme im Himbeerkern auf (das Bild bricht ab). Daher nehmen wir eine größere Auflösung und reduzieren dann das Bild. Hier verwenden wir einen kleinen Trick: Das Bild wird nicht mit Python skaliert, sondern mit Hilfe der GPU, sodass der Armkern nicht belastet wird.
  • Warum Videos im BGRA-Format aufnehmen, nicht im BGR?
    Wir verwenden GPU-Ressourcen, um die Größe des Bildes zu reduzieren, und das native Format für die Größenänderung ist das BGRA-Format. Wenn wir BGR anstelle von BGRA verwenden, haben wir zwei Nachteile. Der erste ist etwas niedriger als der endgültige FPS (in unseren Tests - 20 Prozent). Das zweite ist die ständige Sorge in der Konsole "PiCameraAlfaStripping: Verwenden von Alpha-Stripping zum Konvertieren in ein Nicht-Alpha-Format; Möglicherweise finden Sie das entsprechende Alpha-Format schneller. “ Das Googeln führte zum Abschnitt mit der Picamera-Dokumentation, in dem dieser Trick beschrieben wird.
  • Wo ist das PiRGBArray?

    Dies ist wie die native Picamera-Klasse für die Arbeit mit der Kamera, wird hier jedoch nicht verwendet. Es hat sich bereits herausgestellt, dass in unseren Tests die Arbeit mit einem „handgemachten“ Numpy-Array viel schneller ist (ungefähr eineinhalb Mal) als die Verwendung von PiRGBArray. Dies bedeutet nicht, dass PiRGBArray schlecht ist, höchstwahrscheinlich sind dies unsere krummen Hände.
  • Wie hoch ist der Prozentsatz bei der Berechnung der Tiefenkarte?
    Antworten wir mit einem Bild:



    Wir sehen, dass von den 4 Kernen des Prozessors tatsächlich nur einer geladen ist, und das sind 70%. Und das trotz der Tatsache, dass wir mit einer GUI arbeiten und Bilder und Tiefenkarten an den Benutzer ausgeben. Dies bedeutet, dass es eine gute Leistungsspanne gibt und eine dünne OpenCV-Abstimmung mit OpenMP und anderen Extras in C sowie ein „Kampf“ -Modus ohne GUI sehr interessante Ergebnisse liefern können.
  • Was ist die maximale FPS-Tiefenkarte, die mit diesen Einstellungen erhalten wird?

    Das von uns erreichte Maximum betrug 17 FPS, wenn 20 Bilder pro Sekunde von der Kamera aufgenommen wurden. Die in Bezug auf Geschwindigkeitsparameter in den Tiefenkarteneinstellungen am schnellsten reagierenden sind MinDisparity und NumOfDisparities. Dies ist logisch, da sie die Anzahl der "Schritte" bestimmen, die innerhalb des Algorithmus vom Suchfenster zum Vergleichen von Frames ausgeführt werden. Am zweitempfindlichsten ist preFilterCap, das sich insbesondere auf die „Glätte“ der Tiefenkarte auswirkt.
  • Was ist mit der Temperatur des Prozessors?

    Auf Compute Module 3+ Lite (eine neue Serie mit einer eisernen „Kappe“ auf dem Prozess) werden ungefähr die folgenden Ergebnisse angezeigt:

  • Wie benutzt man eine GPU?

    Zumindest kann es zur Andistorisierung und Korrektur von Bildern in Echtzeit verwendet werden, da es Beispiele ( hier auf WebGL ), Python Pi3d sowie das Verarbeitungsprojekt ( Beispiele für Himbeeren ) gibt.

    Es gibt eine weitere interessante Entwicklung von Koichi Nakamura, genannt Py-Videocore . In unserer Korrespondenz mit ihm drückte er die Idee aus, dass Sie zur Beschleunigung von StereoBM dessen Kern- und OpenCV-Sortierungen mit Cuda-Unterstützung verwenden können . Im Allgemeinen zur Optimierung - eine unberührte Kante, wie sie sagen.

Vielen Dank für Ihre Aufmerksamkeit, und hier ist der versprochene Link zur Quelle .

Source: https://habr.com/ru/post/de446872/


All Articles