[PYTHON] Ich habe versucht, die affine Matrix in der Bildausrichtung (Feature-Point-Matching) mithilfe der affinen Transformation zu finden

Einführung

Dies ist ein Artikel, um die affine Matrix in Feature Point Matching zu finden. In diesem Artikel werden die Feature-Punkte manuell festgelegt. image1.png Der Zweck besteht darin, die affine Matrix A zu finden, die Bild1 in Bild2 mit den Merkmalspunkten der beiden so bekannten Bilder konvertiert.

affine.gif Wenn Sie die Affin-Matrix in den Feature-Punkten finden, können Sie die Bilder wie folgt überlagern.

Feature Point Matching

Affinmatrix

Matrixberechnung zum Transformieren jeder Koordinate des Bildes

\left(
\begin{array}{c}
x^{'}\\
y^{'}\\
1
\end{array}
\right)
=
\left(
\begin{array}{ccc}
a & b & t_{x}\\
c & d & t_{y}\\
0 & 0 & 1
\end{array}
\right)
\left(
\begin{array}{c}
x\\
y\\
1
\end{array}
\right)

von

A=
\left(
\begin{array}{ccc}
a & b & t_{x}\\
c & d & t_{y}\\
0 & 0 & 1
\end{array}
\right)

Der Teil von ist die affine Matrix. Ein ausgezeichnetes Bild, das allein mit dieser Matrix Rotation, Vergrößerung, Verkleinerung, Bewegung, Inversion und Scherung eines Bildes darstellen kann! !!

Für die affine Umwandlung habe ich auf den folgenden Artikel verwiesen. Affin-Konvertierung vollständig verstehen Affin-Konvertierung durch Matrix (Vergrößerung / Verkleinerung / Drehung / Scherung / Bewegung) - Erfinder der Python-Bildverarbeitung -

Berechnung der affinen Matrix

Wenn in zwei Bildern $ N (N \ geqq3) $ Merkmalspunkte vorhanden sind, werden die Koordinaten der Merkmalspunkte im Bild vor der Konvertierung berechnet.

\left(
\begin{array}{c}
x_{n}\\
y_{n}
\end{array}
\right)

Koordinaten nach der Rückkehr

\left(
\begin{array}{c}
x^{'}_{n}\\
y^{'}_{n}
\end{array}
\right)

Als Matrixausdruck, der eine affine Transformation für alle $ N $ -Koordinaten durchführt

\left(
\begin{array}{c}
x^{'}_{1}&x^{'}_{2}&\cdots&x^{'}_{N}\\
y^{'}_{1}&x^{'}_{2}&\cdots&x^{'}_{N}\\
1&1&\cdots&1
\end{array}
\right)
=
\left(
\begin{array}{ccc}
a & b & t_{x}\\
c & d & t_{y}\\
0 & 0 & 1
\end{array}
\right)
\left(
\begin{array}{c}
x_{1}&x_{2}&\cdots&x_{N}\\
y_{1}&x_{2}&\cdots&x_{N}\\
1&1&\cdots&1
\end{array}
\right)

Es kann dargestellt werden durch. Der Zweck besteht darin, diese $ a, b, c, d, t_ {x}, t_ {y} $ zu finden. Hier finden Sie eine Reihe von Koordinaten vor und nach der Konvertierung

\left(
\begin{array}{c}
x_{n}\\
y_{n}
\end{array}
\right)
,
\left(
\begin{array}{c}
x^{'}_{n}\\
y^{'}_{n}
\end{array}
\right)

Affin Konvertierung zu

\left(
\begin{array}{c}
x^{'}_{n}\\
y^{'}_{n}\\
1
\end{array}
\right)
=
\left(
\begin{array}{ccc}
a & b & t_{x}\\
c & d & t_{y}\\
0 & 0 & 1
\end{array}
\right)
\left(
\begin{array}{c}
x_{n}\\
y_{n}\\
1
\end{array}
\right)

Wenn Sie erweitern

\begin{align}
x^{'}_{n}&=ax_{n} + by_{n} + t_{x}\\
y^{'}_{n}&=cx_{n} + dy_{n} + t_{y}
\end{align}

Wird sein.

w_1=
\left(
\begin{array}{c}
a\\
b\\
t_{x}
\end{array}
\right)
,
w_2=
\left(
\begin{array}{c}
c\\
d\\
t_{y}
\end{array}
\right)
,
p_{n}=
\left(
\begin{array}{c}
x_{n} & y_{n} & 1
\end{array}
\right)
,
p^{'}_{n}=
\left(
\begin{array}{c}
x^{'}_{n} & y^{'}_{n} & 1
\end{array}
\right)

Wenn Sie einen Vektor wie vorbereiten

\begin{align}
x^{'}_{n}&=p_{n}w_1\\
y^{'}_{n}&=p_{n}w_2
\end{align}

Kann geschrieben werden. Der Abstand zwischen den Konvertierungszielkoordinaten und den Koordinaten nach der Rückkehr durch Affin-Konvertierung wird als Fehlerfunktion verwendet, um $ w_1 $ und $ w_2 $ zu erhalten, wenn die Fehlerfunktion am kleinsten ist. Fehlerfunktion $ E $

E=\sum_{n=1}^{N} 
\Bigl(
(x^{'}_{n} - p_{n}w_1)^{2} + (y^{'}_{n} - p_{n}w_2)^{2}
\Bigr)

Um dies so einzustellen, dass es im Matrixformat dargestellt wird

X^{'}=
\left(
\begin{array}{c}
x^{'}_{1}\\
\vdots\\
x^{'}_{N}
\end{array}
\right)
,
Y^{'}=
\left(
\begin{array}{c}
y^{'}_{1}\\
\vdots\\
y^{'}_{N}
\end{array}
\right)
,
P=
\left(
\begin{array}{c}
p_{1}\\
\vdots\\
p_{N}
\end{array}
\right)
=
\left(
\begin{array}{c}
x_{1} & y_{2} & 1\\
&\vdots&\\
x_{N} & y_{N} & 1
\end{array}
\right)

angesichts dessen

E=
(X^{'} - Pw_1)^{T}(X^{'} - Pw_1) + (Y^{'} - Pw_2)^T(Y^{'} - Pw_2) 

Kann geschrieben werden. Wenn entfaltet

\begin{align}
E&=({X^{'}}^{T} - (Pw_1)^{T})(X^{'} - Pw_1) + ({Y^{'}}^{T} - (Pw_2)^{T})(Y^{'}-Pw_2)\\
&={X^{'}}^{T}X^{'} - {X^{'}}^{T}Pw_1 - (Pw_1)^{T}X^{'} + (Pw_1)^{T}(Pw_1) + {Y^{'}}^{T}Y^{'} - {Y^{'}}^{T}Pw_2 - (Pw_2)^{T}Y^{'} + (Pw_2)^{T}(Pw_2)\\
&={X^{'}}^{T}X^{'} - w^{T}_{1}P^{T}{X^{'}}^{T} - w^{T}_{1}P^{T}{X^{'}}^{T} + w^{T}_{1}P^{T}Pw_{1} + {Y^{'}}^{T}Y^{'} - w^{T}_{2}P^{T}{Y^{'}}^{T} - w^{T}_{2}P^{T}{Y^{'}}^{T} + w^{T}_{2}P^{T}Pw_{2}\\
&={X^{'}}^{T}X^{'} - 2w^{T}_{1}P^{T}{X^{'}}^{T} + w^{T}_{1}P^{T}Pw_{1} + {Y^{'}}^{T}Y^{'} - 2w^{T}_{2}P^{T}{Y^{'}}^{T} + w^{T}_{2}P^{T}Pw_{2}\\
\end{align}

Es wird sein. Wenn Sie die Zeit finden, in der $ E $ durch teilweise Differenzierung mit $ w_1 $ und $ w_2 $ kleiner wird

\begin{align}
\frac{\partial E}{\partial w_{1}}=-2P^{T}X^{'} + 2P^{T}Pw_{1}&=0\\
2P^{T}w_{1}&=2P^{T}X^{'}\\
w_{1}&=(P^{T}P)^{-1}P^{T}X^{'}\\
\frac{\partial E}{\partial w_{2}}=-2P^{T}Y^{'} + 2P^{T}Pw_{2}&=0\\
2P^{T}w_{2}&=2P^{T}Y^{'}\\
w_{2}&=(P^{T}P)^{-1}P^{T}Y^{'}
\end{align}

Als Ergebnis wurden $ w_1 $ und $ w_2 $ erhalten, so dass die affine Matrix erhalten wurde.

Implementierung

Lassen Sie es uns in Python nur mit numpy implementieren.

import numpy as np
import math
from PIL import Image
from matplotlib import pyplot as plt


#Eine Funktion, die sich auf das Ende des Arrays bezieht, wenn Sie den Bereich des Referenzbilds überschreiten
def clip_xy(ref_xy, img_shape):
    #Ersetzen Sie für x-Koordinate
    ref_x = np.where((0 <= ref_xy[:, 0]) & (ref_xy[:, 0] < img_shape[1]), ref_xy[:, 0], -1)
    #Ersetzen Sie etwa die y-Koordinate
    ref_y = np.where((0 <= ref_xy[:, 1]) & (ref_xy[:, 1] < img_shape[0]), ref_xy[:, 1], -1)

    #Kombinieren und zurückkehren
    return np.vstack([ref_x, ref_y]).T


#Affin-Konvertierung
def affine(data, affine, draw_area_size):
    # data:Bilddaten, die in affine konvertiert werden sollen
    # affine:Affinmatrix
    #:draw_area_size:Es kann mit der Form der Daten identisch oder besser sein

    #Inverse Matrix der Affin-Matrix
    inv_affine = np.linalg.inv(affine)

    x = np.arange(0, draw_area_size[1], 1)
    y = np.arange(0, draw_area_size[0], 1)
    X, Y = np.meshgrid(x, y)

    XY = np.dstack([X, Y, np.ones_like(X)])
    xy = XY.reshape(-1, 3).T

    #Berechnung von Referenzkoordinaten
    ref_xy = inv_affine @ xy
    ref_xy = ref_xy.T

    #Koordinaten um die Referenzkoordinaten
    liner_xy = {}
    liner_xy['downleft'] = ref_xy[:, :2].astype(int)
    liner_xy['upleft'] = liner_xy['downleft'] + [1, 0]
    liner_xy['downright'] = liner_xy['downleft'] + [0, 1]
    liner_xy['upright'] = liner_xy['downleft'] + [1, 1]

    #Gewichtsberechnung mit linearer Interpolation
    liner_diff = ref_xy[:, :2] - liner_xy['downleft']

    liner_weight = {}
    liner_weight['downleft'] = (1 - liner_diff[:, 0]) * (1 - liner_diff[:, 1])
    liner_weight['upleft'] = (1 - liner_diff[:, 0]) * liner_diff[:, 1]
    liner_weight['downright'] = liner_diff[:, 0] * (1 - liner_diff[:, 1])
    liner_weight['upright'] = liner_diff[:, 0] * liner_diff[:, 1]

    #Gewicht und hinzufügen
    liner_with_weight = {}
    for direction in liner_weight.keys():
        l_xy = liner_xy[direction]
        l_xy = clip_xy(l_xy, data.shape)
        l_xy = np.dstack([l_xy[:, 0].reshape(draw_area_size), l_xy[:, 1].reshape(draw_area_size)])
        l_weight = liner_weight[direction].reshape(draw_area_size)
        liner_with_weight[direction] = data[l_xy[:, :, 1], l_xy[:, :, 0]] * l_weight

    data_linear = sum(liner_with_weight.values())
    return data_linear


#Funktion zum Finden der affinen Matrix aus den Merkmalspunkten
def registration(P, x_dash, y_dash):
    w1 = np.linalg.inv(P.T @ P) @ P.T @ x_dash
    w2 = np.linalg.inv(P.T @ P) @ P.T @ y_dash
    affine_matrix = np.array([[1.0, 0.0, 0.0],
                              [0.0, 1.0, 0.0],
                              [0.0, 0.0, 1.0]])
    affine_matrix[0, :] = w1
    affine_matrix[1, :] = w2
    print(affine_matrix)
    return affine_matrix


#Klicken Sie auf den Feature-Punkt Array speichern
future_points1 = np.array([[1, 1]])
future_points2 = np.array([[1, 1]])
count_fp1 = 0
count_fp2 = 0


#Klicken Sie hier, um Feature-Punkte zu bestimmen
def onclick(event):
    global future_points1
    global future_points2
    global count_fp1
    global count_fp2

    click_axes = event.inaxes
    x = math.floor(event.xdata)
    y = math.floor(event.ydata)
    if click_axes == ax1:
        if count_fp1 == 0:
            future_points1[0, :] = (x, y)
            count_fp1 = 1
        else:
            future_points1 = np.vstack([future_points1, np.array([x, y])])
            count_fp1 += count_fp1
        print(future_points1)
    if click_axes == ax2:
        if count_fp2 == 0:
            future_points2[0, :] = (x, y)
            count_fp2 = 1
        else:
            future_points2 = np.vstack([future_points2, np.array([x, y])])
            count_fp2 += count_fp2
        print(future_points2)
    click_axes.scatter(x, y)
    fig.canvas.draw_idle()


#Geben Sie männlich und Bildüberlagerung ein
def onEnter(event):
    if event.key == 'enter' and future_points1.size == future_points2.size and future_points1.size >= 3:
        # P:Koordinatenmatrix der Konvertierungsquelle([[x,y,1],[x,y,1],...]
        # x_dash:Ziel x Koordinatenvektor
        # y_dash:Y-Koordinatenvektor des Konvertierungsziels
        vec_one = np.ones((future_points2.shape[0], 1))
        P = np.hstack([future_points2, vec_one])
        x_dash = future_points1[:, 0]
        y_dash = future_points1[:, 1]
        affine_matrix = registration(P, x_dash, y_dash)
        #Finden Sie das Bild nach der affinen Konvertierung
        affined_image = affine(image2, affine_matrix, image1.shape)
        x = np.arange(0, affined_image.shape[1], 1)
        y = np.arange(0, affined_image.shape[0], 1)
        X_affined, Y_affined = np.meshgrid(x, y)
        ax3.pcolormesh(X_affined, Y_affined, affined_image, cmap='gray', shading='auto', alpha=0.2)
        fig.canvas.draw_idle()


#Bild wird geladen
image1 = np.array(Image.open('./source/test1.jpg').convert('L'))
image2 = np.array(Image.open('./source/t_test1.jpg').convert('L'))
#Bg am Ende des Bildes_Farbzugabe von Farbe
bg_color = 256
image2 = np.hstack([image2, bg_color * np.ones((image2.shape[0], 1), int)])
image2 = np.vstack([image2, bg_color * np.ones((1, image2.shape[1]), int)])

x_image1 = np.arange(0, image1.shape[1], 1)
y_image1 = np.arange(0, image1.shape[0], 1)

X1, Y1 = np.meshgrid(x_image1, y_image1)

x_image2 = np.arange(0, image2.shape[1], 1)
y_image2 = np.arange(0, image2.shape[0], 1)

X2, Y2 = np.meshgrid(x_image2, y_image2)

fig = plt.figure(figsize=(8, 8))
ax1 = fig.add_subplot(221)
mesh1 = ax1.pcolormesh(X1, Y1, image1, shading='auto', cmap='gray')
ax1.invert_yaxis()
ax2 = fig.add_subplot(223)
mesh2 = ax2.pcolormesh(X2, Y2, image2, shading='auto', cmap='gray')
ax2.invert_yaxis()
ax3 = fig.add_subplot(222)
mesh3 = ax3.pcolormesh(X1, Y1, image1, shading='auto', cmap='gray', alpha=0.2)
ax3.invert_yaxis()

cid = fig.canvas.mpl_connect('button_press_event', onclick)
cid = fig.canvas.mpl_connect('key_press_event', onEnter)
plt.show()

Am Ende

Wenn man die Formel betrachtet, ähnelt sie der Formel zum Ermitteln des linearen Regressionskoeffizienten! !! Oder besser gesagt, es ist fast dasselbe wie eine lineare Regression. .. .. Es wäre interessant, wenn wir Merkmalsvektoren wie die lineare Regression erstellen oder mit Bildverzerrungen umgehen könnten, indem wir die Gaußsche Prozessmethode gut anwenden.

Bitte weisen Sie auf Fehler oder verwirrende Punkte hin.

Recommended Posts

Ich habe versucht, die affine Matrix in der Bildausrichtung (Feature-Point-Matching) mithilfe der affinen Transformation zu finden
Ich habe versucht, das Bild mithilfe von maschinellem Lernen zu komprimieren
Ich habe versucht, den Text in der Bilddatei mit Tesseract der OCR-Engine zu extrahieren
Ich habe versucht, die Entropie des Bildes mit Python zu finden
Ich habe versucht, das Bild mit OpenCV im "Skizzenstil" zu verarbeiten
Ich habe versucht, das Bild mit OpenCV im "Bleistift-Zeichenstil" zu verarbeiten
Ich habe versucht, das Gesichtsbild mit sparse_image_warp von TensorFlow Addons zu transformieren
Ich habe versucht, die Objekte aus dem Bild des Steak-Sets zu sortieren. ⑤ Ähnliche Erkennung von Bildmerkmalen
Ich habe versucht, die Trapezform des Bildes zu korrigieren
Ich habe versucht, den Bildfilter von OpenCV zu verwenden
Suchen Sie die Position im Originalbild anhand der Koordinaten nach der affinen Konvertierung (Python + OpenCV).
So speichern Sie die Feature-Point-Informationen des Bildes in einer Datei und verwenden sie zum Abgleichen
Ich habe versucht, die in Python installierten Pakete grafisch darzustellen
Ich habe versucht, Iris aus dem Kamerabild zu erkennen
Ich habe versucht, die Sündenfunktion mit Chainer zu approximieren
Finden Sie Kartenillustrationen aus Bildern mithilfe der Feature-Point-Anpassung
Ich habe versucht, die nicht negative Matrixfaktorisierung (NMF) zu wiederholen.
Ich habe versucht, die Sprache mit CNN + Melspectogram zu identifizieren
Ich habe versucht, das Wissensdiagramm mit OpenKE zu ergänzen
Python Open CV hat versucht, das Bild im Text anzuzeigen.
Ich habe versucht, die Umrisse von Big Gorilla herauszufinden
Ich habe versucht, mit TensorFlow den Durchschnitt mehrerer Spalten zu ermitteln
Ich habe versucht, die Anzeigenoptimierung mithilfe des Banditenalgorithmus zu simulieren
Ich habe versucht, die Zeit und die Zeit der C-Sprache zu veranschaulichen
Ich habe versucht, die im Geschäftsleben häufig verwendeten Befehle zusammenzufassen
Ich habe versucht, die Mail-Sendefunktion in Python zu implementieren
[TF] Ich habe versucht, das Lernergebnis mit Tensorboard zu visualisieren
Ich habe eine Stoppuhr mit tkinter mit Python gemacht
Ich habe versucht, die Sündenfunktion mit Chainer zu approximieren (Re-Challenge)
Ich habe versucht, den Trend der Anzahl der Schiffe in der Bucht von Tokio anhand von Satellitenbildern zu ermitteln.
Ich habe versucht, das Zugriffsprotokoll mit Node.js auf dem Server auszugeben
Ich habe versucht, den Unterschied zwischen A + = B und A = A + B in Python herauszufinden
Ich habe versucht, den Datenverkehr mit WebSocket in Echtzeit zu beschreiben
Ich habe versucht, den Index der Liste mithilfe der Aufzählungsfunktion abzurufen
Ich habe versucht, den auf Papier gestempelten Stempel mit OpenCV zu digitalisieren
Ich habe versucht, ein Standbild aus dem Video auszuschneiden
Ich habe versucht, den Ball zu bewegen
Ich habe versucht, die checkio-API zu verwenden
Ich habe versucht, den Abschnitt zu schätzen.
Ich habe versucht, die Lernfunktion im neuronalen Netzwerk sorgfältig zu verstehen, ohne die Bibliothek für maschinelles Lernen zu verwenden (zweite Hälfte).
Python-Programmierung: Ich habe versucht, mithilfe von BeautifulSoup4 Unternehmensinformationen (Crawlen) von Yahoo Finance in den USA abzurufen
Ich möchte die Farbe ändern, indem ich auf den Streupunkt in matplotlib klicke
[Python] Ich habe versucht, den kollektiven Typ (Satz) auf leicht verständliche Weise zusammenzufassen.
Ich habe versucht, den besten Weg zu finden, um einen guten Ehepartner zu finden
Ich habe versucht, das Bild durch Klicken mit der rechten und linken Maustaste in den angegebenen Ordner zu verschieben
Ich habe versucht, die Ähnlichkeit der Frageabsicht mit Doc2Vec von gensim abzuschätzen
Ich habe versucht, mehrere Servomotoren MG996R mit dem Servotreiber PCA9685 zu steuern.
Ich habe versucht, Gitarrenakkorde in Echtzeit mithilfe von maschinellem Lernen zu klassifizieren
Passende Karaoke-Tasten ~ Ich habe versucht, es auf Laravel zu setzen ~ <auf dem Weg>
Ich habe versucht, verschiedene Sätze mit der automatischen Zusammenfassungs-API "summpy" zusammenzufassen.
Ich habe versucht, die optimale Route des Traumlandes durch (Quanten-) Tempern zu finden
Ich habe versucht, die Phase der Geschichte mit COTOHA zu extrahieren und zu veranschaulichen
Ich habe versucht, den Höhenwert von DTM in einem Diagramm anzuzeigen
Ich habe die übliche Geschichte ausprobiert, Deep Learning zu verwenden, um den Nikkei-Durchschnitt vorherzusagen
Mit COTOHA habe ich versucht, den emotionalen Verlauf des Laufens von Meros zu verfolgen.
Ich habe das VGG16-Modell mit Keras implementiert und versucht, CIFAR10 zu identifizieren
Ich habe versucht, die Neujahrskarte selbst mit Python zu analysieren
Ich habe versucht, das RWA-Modell (Recurrent Weighted Average) in Keras zu trainieren