5.31. Verschiebungsabgleich

Template-Matching beantwortet die Frage wo befindet sich dieser Ausschnitt im Einzelbild; das Ähnlichkeits-Scoring beantwortet wie ähnlich sind sich diese beiden Bilder insgesamt. Eine andere Frage liegt dazwischen: Die beiden Einzelbilder zeigen dieselbe Szene, aber die Kamera (oder die Szene) hat sich zwischen ihnen bewegt – um wie viel? Das ist das Verschiebungsproblem, und das image-Modul löst es mit einer einzigen Phasenkorrelationsmethode.

5.31.1. Verschiebung per Phasenkorrelation

find_displacement() schätzt die starre Ausrichtung zwischen zwei gleich großen Bildern mittels Phasenkorrelation – einer Methode im Frequenzbereich, die auf jedem Bild eine schnelle Fourier-Transformation (FFT) ausführt, ihre Phasen kreuzkorreliert und die Spitze im Ergebnis lokalisiert. Die Position der Spitze ist die Verschiebung, die die beiden Bilder zur Deckung bringt:

d = img.find_displacement(template)

print("shift:", d.x_translation, d.y_translation,
      " response:", d.response)

Das zurückgegebene Displacement trägt x_translation und y_translation – die Pixelverschiebung in jeder Achse – plus response, einen Vertrauenswert von 0.0 bis 1.0, wobei 1.0 eine perfekte Spitze bedeutet. Das Herausfiltern von Erkennungen unterhalb von response > 0.3 verwirft fehlerhafte Ergebnisse, bei denen die Phasenkorrelation nie eine saubere Spitze gefunden hat.

Sowohl rotation als auch scale sind im Standardmodus 0.0 bzw. 1.0; sie nehmen nur dann echte Werte an, wenn logpolar=True (siehe unten).

Die Methode bringt zwei praktische Einschränkungen mit sich. Die erste sind Zweierpotenz-Abmessungen: Die FFT im Kern der Phasenkorrelation ist am schnellsten – und auf der Kamera nur vollständig unterstützt – bei Größen wie 32 mal 32, 64 mal 64 und 128 mal 128. Das sauberste Setup besteht darin, direkt mit einer dieser Größen aufzunehmen, indem die Auflösung als Tupel an framesize() übergeben wird:

csi0.framesize((64, 64))

Eine Anwendung, die die Verschiebung aus einem größeren Einzelbild benötigt, schneidet stattdessen einen Zweierpotenz-Ausschnitt aus dem interessierenden Bereich heraus und führt den Matcher darauf aus.

Die zweite sind gleich große Eingaben: roi und template_roi müssen identische Breiten und Höhen auswählen, sonst verweigert der Matcher den Aufruf. Zwei Aufnahmen derselben Kamera bei derselben Konfiguration erfüllen dies automatisch; ein aufgenommenes Einzelbild, das mit einer geladenen Referenz verglichen wird, muss zuerst auf zueinander passende Zweierpotenz-Ausschnitte zugeschnitten werden.

5.31.2. Rotation und Skalierung per Log-Polar

Der Standardmodus findet nur Verschiebung. Wenn sich die beiden Einzelbilder zusätzlich in der Rotation um ein gewähltes Zentrum oder in der Skalierung um dasselbe Zentrum unterscheiden, verwandelt das Ausführen der Phasenkorrelation auf der Log-Polar-Reprojektion jedes Bildes diese Parameter in eine Verschiebung im Log-Polar-Koordinatensystem – die derselbe Phasenkorrelations-Matcher wiedergewinnen kann:

d = img.find_displacement(template, logpolar=True)

print("rotation rad:", d.rotation,
      " scale:", d.scale,
      " response:", d.response)

Mit logpolar=True führt die Methode dieselbe Matching-Pipeline gegen die log-polar-projizierten Bilder statt gegen die Originale aus. Die Felder rotation und scale des Ergebnisses kommen ausgefüllt zurück: rotation ist der Winkel im Bogenmaß zwischen den beiden Einzelbildern, scale ist der Skalierungsfaktor zwischen ihnen. x_translation und y_translation werden in diesem Modus bedeutungslos (die Verschiebung entlang der Log-Polar-Achsen entspricht keiner linearen Verschiebung in der Quelle).

Das Schlüsselwort fix_rotation_scale=True deckt den Zwischenfall ab: Die beiden Bilder unterscheiden sich in sowohl Verschiebung als auch Rotation/Skalierung, und die Anwendung benötigt nur die Verschiebung nach der Korrektur von Rotation und Skalierung. Der Matcher führt zuerst den Log-Polar-Durchlauf aus, um Rotation und Skalierung wiederzugewinnen, wendet die Umkehrung auf eines der Bilder an und führt dann den Verschiebungs-Durchlauf aus, um die verbleibende Verschiebung wiederzugewinnen. Das Flag ist nur dann von Bedeutung, wenn logpolar=False – es weist den Matcher im Verschiebungsmodus an, zuerst die Rotation/Skalierung zu entfernen.

Das Muster aus den Polartransformationen – kartesisch → polar → abgleichen – ist das, was find_displacement() mit logpolar=True in einem einzigen Aufruf tut. Die Anwendung speichert beim Start einen Log-Polar-Referenzausschnitt, nimmt jedes Live-Einzelbild auf und log-polar-transformiert es, und die Methode gewinnt den Unterschied in Rotation und Skalierung zwischen ihnen wieder. Für Anwendungen, die einen rotations- und skalierungsinvarianten Tracker benötigen – ein Andock-Roboter, dessen Kamera bei der Annäherung an ein Ziel kippt und zoomt, ein stabilisierter Gimbal, der wissen muss, wie sich das Bild relativ zu einer Referenz dreht – ist dies die Standardkonstruktion.

5.31.3. Die klassische Anwendung

Die häufigste Anwendung von find_displacement() ist die Bewegungsschätzung von Einzelbild zu Einzelbild in einer Pipeline, die eine sich bewegende Kamera verarbeitet. Die Kamera nimmt einen kleinen Zweierpotenz-Ausschnitt bei Einzelbild N auf, nimmt den gleich großen Ausschnitt bei Einzelbild N+1 auf, führt find_displacement() auf den beiden aus und liest die Pixelverschiebung zwischen ihnen ab. Die Verschiebung ist die geschätzte Bewegung der Kamera (oder der Szene, je nachdem, wessen Bezugssystem von Bedeutung ist) zwischen den beiden Aufnahmen, nützlich für:

  • Sensorik im Stil des optischen Flusses – eine schwebende Drohne mit nach unten gerichteter Kamera nutzt die Verschiebung pro Einzelbild, um ihre seitliche Bewegung zu schätzen und sie an den Flugregler zurückzuführen.

  • Bildstabilisierung – die Verschiebung zwischen aufeinanderfolgenden Einzelbildern wird aus dem aufgenommenen Bild herausgerechnet, bevor es aufgezeichnet oder übertragen wird, was einen flüssigeren Videostream erzeugt.

  • Inspektionsausrichtung – eine scannende Kamera, die sich entlang eines Förderbands bewegt, nutzt die Verschiebung pro Einzelbild, um jedes Einzelbild gegen das nächste zu registrieren und eine zusammengesetzte Ansicht des gesamten Teils aufzubauen.

Jede dieser Anwendungen nimmt dieselbe Form an: aufnehmen, verschieben, in eine laufende Schätzung akkumulieren, erneut aufnehmen.