Dies ist ein Artikel, um die affine Matrix in Feature Point Matching zu finden. In diesem Artikel werden die Feature-Punkte manuell festgelegt. Der Zweck besteht darin, die affine Matrix A zu finden, die Bild1 in Bild2 mit den Merkmalspunkten der beiden so bekannten Bilder konvertiert.
Wenn Sie die Affin-Matrix in den Feature-Punkten finden, können Sie die Bilder wie folgt überlagern.
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 -
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.
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()
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