Bildregistrierung mit Python und Kreuzkorrelation

9

Ich habe zwei Bilder, die genau den gleichen Inhalt zeigen: 2D-Gaußsche Flecken. Ich rufe diese beiden 16-Bit Png-Dateien "left.png" und "right.png". Da sie jedoch durch eine etwas andere optische Anordnung erhalten werden, erscheinen die entsprechenden Punkte (physisch die gleichen) an leicht unterschiedlichen Positionen. Das heißt, das Recht ist leicht gestreckt, verzerrt oder nichtlinear. Deshalb möchte ich die Transformation von links nach rechts bekommen.

Also für jedes Pixel auf der linken Seite mit seiner x- und y-Koordinate möchte ich eine Funktion, die mir die Komponenten des Verschiebungsvektors gibt, die auf das entsprechende Pixel auf der rechten Seite zeigen.

In einem früheren Ansatz versuchte ich, die Positionen der entsprechenden Punkte zu erhalten, um die relativen Abstände deltaX und deltaY zu erhalten. Diese Abstände passte ich dann an die Taylor-Erweiterung bis zur zweiten Ordnung von T (x, y) und gab mir die x- und y-Komponente des Verschiebungsvektors für jedes Pixel (x, y) auf der linken Seite und zeigte auf das entsprechende Pixel (x ', y') rechts.

Um ein allgemeineres Ergebnis zu erhalten, möchte ich eine normalisierte Kreuzkorrelation verwenden. Dazu multipliziere ich jeden Pixelwert von links mit einem entsprechenden Pixelwert von rechts und summe über diese Produkte. Die Transformation, nach der ich suche, sollte die Pixel verbinden, die die Summe maximieren. Wenn die Summe maximiert ist, weiß ich, dass ich die entsprechenden Pixel multipliziert habe.

Ich habe wirklich viel damit versucht, aber es hat nicht geklappt. Meine Frage ist, ob jemand von Ihnen eine Idee hat oder etwas Ähnliches getan hat.

%Vor%

Bitte lassen Sie mich wissen, wenn ich diese Frage klarer machen kann. Ich muss immer noch überprüfen, wie man Fragen mit Latex stellt.

Vielen Dank für die Eingabe.

[left.png] Ссылка [right.png] Ссылка

Ich fürchte, in den meisten Fällen erscheinen 16-Bit-Bilder nur schwarz (zumindest auf Systemen, die ich benutze) :( aber natürlich sind da Daten drin.

AKTUALISIEREN 1

Ich versuche meine Frage zu klären. Ich suche nach einem Vektorfeld mit Verschiebungsvektoren, die von jedem Pixel in left.png auf das entsprechende Pixel in right.png zeigen. Mein Problem ist, dass ich mir über die Einschränkungen, die ich habe, nicht sicher bin.

%Vor%

wobei der Vektor r (Komponenten x und y) auf ein Pixel in left.png zeigt und der Vektor r-prime (Komponenten x-prime und y-prime) auf das entsprechende Pixel in right.png zeigt. für jedes r gibt es einen Verschiebungsvektor.

Was ich früher gemacht habe, war, dass ich manuell Komponenten des Vektorfelds d gefunden und auf ein Polynom zweiten Grades gebracht habe:

%Vor%

Also passte ich:

%Vor%

und

%Vor%

Macht das für Sie Sinn? Ist es möglich, alle Delta-x (x, y) und Delta-y (x, y) mit Kreuzkorrelation zu erhalten? Die Kreuzkorrelation sollte maximiert werden, wenn die entsprechenden Pixel durch die Verschiebungsvektoren miteinander verbunden sind, richtig?

AKTUALISIEREN 2

Also der Algorithmus, an den ich dachte, ist wie folgt:

  1. Deform right.png
  2. Erhalten Sie den Wert der Kreuzkorrelation
  3. Deform right.png weiter
  4. Ermitteln Sie den Wert der Kreuzkorrelation und vergleichen Sie ihn mit dem Wert vor
  5. Wenn es größer ist, gute Deformation, wenn nicht, Deformation wiederholen und etwas anderes tun
  6. Nachdem Sie den Kreuzkorrelationswert maximiert haben, wissen Sie, welche Verformung es gibt:)

Über Deformation: könnte man zuerst eine Verschiebung entlang der x- und y-Richtung machen, um die Kreuzkorrelation zu maximieren, dann in einem zweiten Schritt x- und y-abhängig dehnen oder komprimieren und in einem dritten Schritt quadratisch x- und y deformieren -abhängig und wiederholen Sie dieses Verfahren iterativ? Ich habe wirklich ein Problem, dies mit Integer-Koordinaten zu tun. Meinst du, ich müsste das Bild interpolieren, um eine kontinuierliche Verteilung zu erhalten? Ich muss nochmal darüber nachdenken :( Danke an alle für die Teilnahme:)

    
feinmann 10.02.2012, 09:21
quelle

3 Antworten

2

OpenCV (und damit die Python-Opencv-Bindung) hat eine StarDetector Klasse, die Dieser Algorithmus .

Als Alternative können Sie sich die OpenCV-Klasse SIFT ansehen, die steht für Scale Invariant Feature Transformation.

Aktualisieren

In Bezug auf Ihren Kommentar verstehe ich, dass die "richtige" Transformation die Kreuzkorrelation zwischen den Bildern maximiert, aber ich verstehe nicht, wie Sie die Menge der Transformationen auswählen, über die Sie maximieren möchten. Vielleicht, wenn Sie die Koordinaten von drei übereinstimmenden Punkten kennen (entweder durch einige Heuristiken oder indem Sie sie manuell auswählen), und wenn Sie Affinität erwarten, könnten Sie etwas wie cv2.getAffineTransform , um eine gute Anfangstransformation für Ihren Maximierungsprozess zu erhalten. Von dort können Sie kleine zusätzliche Transformationen verwenden, um eine Menge zu maximieren. Aber dieser Ansatz scheint mir etwas neu zu erfinden, auf das SIFT aufpassen könnte.

Um Ihr Testbild tatsächlich zu transformieren, können Sie auch cv2.warpAffine verwenden kann auf Randwerte achten (zB Pad mit 0). Um die Kreuzkorrelation zu berechnen, können Sie scipy.signal verwenden .correlate2d .

Aktualisieren

Ihr letztes Update hat in der Tat einige Punkte für mich geklärt. Aber ich denke, dass ein Vektorfeld von Verschiebungen nicht die natürlichste Sache ist, nach der zu suchen ist, und hier kam auch das Missverständnis. Ich dachte eher an die globale Transformation T, die für jeden beliebigen Punkt (x, y) des linken Bildes gilt (x ', y') = T (x, y) die rechte Seite, aber T hat für jedes Pixel die gleiche analytische Form. Zum Beispiel könnte dies eine Kombination aus Verschiebung, Rotation, Skalierung, vielleicht einer perspektivischen Transformation sein. Ich kann nicht sagen, ob es realistisch ist oder nicht, eine solche Transformation zu finden, das hängt von Ihrem Aufbau ab, aber wenn die Szene auf beiden Seiten physisch gleich ist, würde ich sagen, dass es vernünftig ist, eine affine Transformation zu erwarten. Aus diesem Grund habe ich cv2.getAffineTransform vorgeschlagen. Es ist natürlich trivial, Ihr Verschiebungsvektorfeld von einem solchen T zu berechnen, da dies nur T (x, y) - (x, y) ist.

Der große Vorteil wäre, dass Sie nur sehr wenige Freiheitsgrade für Ihre Transformation haben, anstatt, wie ich behaupten möchte, 2N Freiheitsgrade im Verschiebungsvektorfeld, wobei N die Anzahl der hellen Punkte ist.

>

Wenn es sich tatsächlich um eine affine Transformation handelt, würde ich einen Algorithmus wie diesen vorschlagen:

  • identifiziere drei helle und gut isolierte Flecken auf der linken Seite
  • Definieren Sie für jeden dieser drei Punkte einen Begrenzungsrahmen, damit Sie darauf hoffen können, den entsprechenden Punkt im rechten Bild zu identifizieren
  • finde die Koordinaten der entsprechenden Punkte, z. mit einer Korrelationsmethode, wie sie in cv2.matchTemplate oder von auch nur den hellsten Punkt innerhalb der Bounding Box zu finden.
  • Sobald Sie drei übereinstimmende Koordinatenpaare haben, berechnen Sie die affine Transformation, die einen Satz in den anderen transformiert, mit cv2.getAffineTransform .
  • Wenden Sie diese affine Transformation auf das linke Bild an, um zu überprüfen, ob Sie die richtige gefunden haben, die berechnet werden kann, wenn die gesamte normalisierte Kreuzkorrelation über einem Schwellenwert liegt oder signifikant abfällt, wenn Sie ein Bild in Bezug auf das andere verschieben / li>
  • Wenn Sie es wünschen und immer noch brauchen, berechnen Sie das Verschiebungsvektorfeld trivial aus Ihrer Transformation T.

Aktualisieren

Es scheint, cv2.getAffineTransform erwartet einen umständlichen Eingabedatentyp 'float32'. Nehmen wir an, die Quellkoordinaten sind (sxi,syi) und das Ziel (dxi,dyi) mit i=0,1,2 . Was Sie brauchen, ist

%Vor%     
PiQuer 13.02.2012 12:17
quelle
1

Ich glaube nicht, dass eine Kreuzkorrelation hier helfen wird, da es nur eine einzige beste Verschiebung für das gesamte Bild gibt. Es gibt drei Alternativen, die ich in Betracht ziehen würde:

  1. Machen Sie eine Kreuzkorrelation auf Sub-Cluster von Punkten. Nimm zum Beispiel die drei Punkte oben rechts und finde die optimale x-y-Verschiebung durch die Kreuzkorrelation. Dies gibt Ihnen die grobe Transformation für die obere linke Seite. Wiederholen Sie dies für so viele Cluster wie möglich, um eine sinnvolle Karte Ihrer Transformationen zu erhalten. Passen Sie dies mit Ihrer Taylor-Erweiterung an und Sie können sich einigermaßen nahe kommen. Damit Ihre Kreuzkorrelation funktioniert, muss der Unterschied in der Verschiebung zwischen den Punkten jedoch geringer sein als der Punkt, sonst können Sie nicht alle Punkte in einem Cluster gleichzeitig mit einer einzelnen Verschiebung überlappen. Unter diesen Umständen könnte Option 2 besser geeignet sein.

  2. Wenn die Verschiebungen relativ klein sind (was ich für eine Bedingung für Option 1 halte), könnten wir annehmen, dass für einen gegebenen Fleck im linken Bild der nächste Fleck im rechten Bild der entsprechende Fleck ist. Daher finden wir für jeden Punkt im linken Bild den nächsten Punkt im rechten Bild und verwenden diesen als Verschiebung an diesem Ort. Aus den 40 gut verteilten Verschiebungsvektoren können wir durch Anpassen Ihrer Taylor-Expansion eine vernünftige Annäherung an die tatsächliche Verschiebung erhalten.

  3. Dies ist wahrscheinlich die langsamste Methode, könnte aber am robustesten sein, wenn Sie große Verschiebungen haben (und Option 2 funktioniert also nicht): Verwenden Sie so etwas wie einen evolutionären Algorithmus, um die Verschiebung zu finden. Wenden Sie eine zufällige Transformation an, berechnen Sie den verbleibenden Fehler (Sie müssen dies möglicherweise als Summe der kleinsten Entfernung zwischen Punkten in Ihrem ursprünglichen und transformierten Bild definieren) und verbessern Sie die Transformation mit diesen Ergebnissen. Wenn Ihre Verschiebungen ziemlich groß sind, benötigen Sie möglicherweise eine sehr breite Suche, da Sie wahrscheinlich viele lokale Minima in Ihrer Landschaft erhalten werden.

Ich würde Option 2 versuchen, da es scheint, dass Ihre Verschiebungen klein genug sind, um einen Punkt im linken Bild leicht mit einem Fleck im rechten Bild zu assoziieren.

Aktualisieren

Ich nehme an, dass Ihre Optik nichtlineare Verzerrungen induziert und dass zwei getrennte Strahlengänge (unterschiedliche Filter in jedem?) die Beziehung zwischen den beiden Bildern noch mehr nichtlinear machen. Die affine Transformation, die PiQuer vorschlägt, könnte einen vernünftigen Ansatz ergeben, aber wahrscheinlich niemals die tatsächlichen Verzerrungen vollständig abdecken.

Ich denke, Ihre Annäherung an ein Taylor-Polynom niedriger Ordnung ist in Ordnung. Dies funktioniert für alle meine Anwendungen mit ähnlichen Bedingungen. Höchste Ordnungen sollten wahrscheinlich etwas wie xy ^ 2 und x ^ 2y sein; etwas Höheres als das wirst du nicht bemerken.

Alternativ können Sie die Verzerrungen für jedes Bild zuerst kalibrieren und dann Ihre Experimente durchführen. Auf diese Weise sind Sie nicht von der Verteilung Ihrer Punkte abhängig, sondern können ein Referenzbild mit hoher Auflösung verwenden, um die beste Beschreibung Ihrer Transformation zu erhalten.

Option 2 oben steht immer noch als Vorschlag für die Überlappung der beiden Bilder. Dies kann vollständig automatisiert werden und ich bin mir nicht sicher, was Sie meinen, wenn Sie ein allgemeineres Ergebnis wünschen.

Update 2

Sie kommentieren, dass die Punkte in den beiden Bildern nicht übereinstimmen. Wenn dies der Fall ist, denke ich, dass Ihr iterativer Kreuzkorrelationsansatz auch nicht sehr robust ist. Sie haben sehr kleine Punkte, so dass Überlappungen nur auftreten, wenn der Unterschied zwischen den beiden Bildern klein ist.

Im Prinzip ist Ihre vorgeschlagene Lösung nicht falsch, aber ob sie funktioniert oder nicht, hängt stark von der Größe Ihrer Deformationen und der Robustheit Ihres Optimierungsalgorithmus ab. Wenn Sie mit sehr wenig Überlappung beginnen, kann es schwierig sein, einen guten Ausgangspunkt für Ihre Optimierung zu finden. Wenn Sie zunächst genügend Überlappungen haben, hätten Sie die Verformung pro Punkt zuerst finden können, aber in einem Kommentar geben Sie an, dass dies nicht funktioniert.

Vielleicht können Sie sich für eine gemischte Lösung entscheiden: Suchen Sie die Kreuzkorrelation von Punktclustern, um einen Ausgangspunkt für Ihre Optimierung zu erhalten, und optimieren Sie dann die Verformung mithilfe der Prozedur, die Sie in Ihrem Update beschrieben haben. Also:

  1. Finden Sie für ein NxN-Pixelsegment die Verschiebung zwischen den linken und rechten Bildern
  2. Wiederholen Sie dies für beispielsweise 16 dieser Segmente
  3. Berechnen Sie eine Annäherung der Deformation mit diesen 16 Punkten
  4. Verwenden Sie dies als Ausgangspunkt für Ihren Optimierungsansatz
Daan 14.02.2012 08:46
quelle
0

Vielleicht möchten Sie sich bunwarpj ansehen, das bereits das tut, was Sie vorhaben . Es ist nicht Python, aber ich benutze es genau in diesem Zusammenhang. Sie können eine Nur-Text-Spline-Transformation exportieren und verwenden, wenn Sie dies wünschen.

    
max 16.05.2013 10:10
quelle

Tags und Links