Dies ist ein Artikel, der versucht, die Vorverarbeitung durch Verwendung der affinen Umwandlung durch Tensor zu vereinfachen. Affin-Transformationen können auf Bilder angewendet werden, aber dieselben Transformationen können auch auf Anmerkungen wie Bounding Box angewendet werden. Sie können es auch auf einen Tensor erweitern, um gleichzeitig verschiedene Transformationen auf ein Objekt anzuwenden.
Die Affintransformation drückt die Bewegung von Punkten mit der folgenden Formel aus.
Wenn Sie ein vages Verständnis der affinen Konvertierung sehen möchten, lesen Sie bitte auch diesen Artikel.
Es wird das Produkt einer 3x3-Matrix und einer 3x1-Matrix verwendet, wobei die 3x3-Matrix die Transformation definiert und die 3x1-Matrix der Punkt vor dem Verschieben ist.
Wenn der Punkt (10, 20) 100 in Richtung $ x $ und 50 in Richtung $ y $ bewegt wird, sind die Koordinaten nach der Bewegung (110, 70), die wie folgt ausgedrückt werden.
Sie denken vielleicht, dass es nicht notwendig ist, eine solche Matrix zu verwenden, aber der Punkt ist, dass sie durch eine Matrix dargestellt werden kann. Wenn Sie es in Code schreiben, ist es wie folgt.
affine = np.array([[1, 0, 100], [0, 1, 50], [0, 0, 1]])
source = np.array([10, 20, 1])[:, None]
dest = np.dot(affine, source)
print(dest)
#[[110]
# [ 70]
# [ 1]]
Unter der Annahme, dass die Bewegung in der $ x $ -Richtung $ t_x $ und die Bewegung in der $ y $ -Richtung $ t_y $ ist, lautet die Umrechnungsmatrix für die parallele Bewegung wie folgt.
Die dritte Zeile jeder Matrix ist eine bedeutungslose Zahl. 1 ist zur Vereinfachung der Berechnung des Matrixprodukts enthalten.
Wenn der Punkt (50, 100) in Richtung $ x $ und 0,8 mal in Richtung $ y $ verdoppelt wird, sind die Koordinaten nach der Bewegung (100, 80), die wie folgt ausgedrückt werden.
affine = np.array([[2, 0, 0], [0, 0.8, 0], [0, 0, 1]])
source = np.array([50, 100, 1])[:, None]
dest = np.dot(affine, source)
print(dest)
# [[100.]
# [ 80.]
# [ 1.]]
Unter der Annahme, dass die Erweiterung in Richtung $ x $ $ s_x $ und die Erweiterung in Richtung $ y $ $ s_y $ ist, lautet die Skalierungsumwandlungsmatrix wie folgt.
Da es sich bei der affinen Transformation um eine Matrixberechnung handelt, kann die Anzahl der Punkte beliebig erweitert werden. Wenn Sie die affine Transformation für $ N $ -Punkte finden, nehmen Sie das Produkt aus der 3x3-Matrix und der 3xN-Matrix. Das Ergebnis ist eine 3xN-Matrix.
Eine Affin-Konvertierung von $ N = 4 $ Punkten führt zu einer quadratischen Affin-Konvertierung. Das Anwenden der affinen Transformation, die $ (2, 3) $ in der $ (x, y) $ -Richtung verdoppelt und $ (5, -1) $ parallel bewegt, auf die Eckpunkte des Vierecks ist wie folgt.
w, h = 2, 1
points = np.array([[0, w, w, 0], [0, 0, h, h], [1, 1, 1, 1]], np.float32) # (3, 4)
affine = np.array([[2, 0, 5], [0, 3, -1], [0, 0, 1]]) # (3, 3)
dest = np.dot(affine, points)
plt.scatter(points[0,:], points[1,:], color="cyan")
plt.scatter(dest[0,:], dest[1,:], color="magenta")
plt.show()
Dies ist ein Beispiel, das bei der Vorverarbeitung zur Objekterkennung verwendet werden kann. Wenn Sie das Bild in der Objekterkennungsdatenerweiterung drehen, müssen Sie auch den Begrenzungsrahmen drehen. Der Begrenzungsrahmen kann durch zwei Punkte definiert werden, den oberen linken und den unteren rechten. Wenn Sie jedoch die vier Punkte oben nehmen, können Sie den Begrenzungsrahmen nach der Drehung leicht berechnen. Durch Nehmen der Minimal- und Maximalwerte für x und y nach der Drehung können die oberen linken und unteren rechten Koordinaten des Begrenzungsrahmens nach der Drehung erhalten werden.
Die Drehung ist auch eine der affinen Transformationen, und die Transformationsmatrix beim Drehen von $ \ theta $ gegen den Uhrzeigersinn um den Ursprung ist
Und wenn sich die Eckpunkte der Begrenzungsbox (Quadrat) vor der Drehung nach der Drehung zu $ (x_1 ', y_1'), \ cdots, (x_4 ', y_4') $ bewegen, umschreibt eine neue Begrenzung das geneigte Quadrat. Boxkoordinaten sind
Sie finden es unter. Der Grund, warum diese Berechnung durchgeführt werden muss, ist, dass die ursprünglichen Scheitelpunkte nach der Drehung nicht als Begrenzungsrahmen geeignet sind (da sie keine Rechtecke parallel zur $ xy $ -Achse sind) und angepasst werden müssen. Bitte sehen Sie das Video unten für Details.
Die Handlung sieht folgendermaßen aus: Aufgrund des Diagramms werden 5 Punkte verschoben (überlappen den Ursprung), aber nur zur Berechnung ist das Verschieben von 4 Punkten in Ordnung.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
def rotate_box():
w, h = 2, 1
max_wh = max(w, h)
points = np.array([[0, w, w, 0, 0], [0, 0, h, h, 0], [1, 1, 1, 1, 0]], np.float32) #Original Bounding Box
for theta in range(0, 360, 10):
rad = np.radians(theta)
rotate_matrix = np.array([
[np.cos(rad), -np.sin(rad), 0],
[np.sin(rad), np.cos(rad), 0],
[0, 0, 1]], np.float32)
dest_points = np.dot(rotate_matrix, points)[:2, :] #Quadrat nach Drehung
rectangle = np.concatenate([np.min(dest_points, axis=-1),
np.max(dest_points, axis=-1)]) #Neue Begrenzungsbox
plt.clf()
plt.plot(dest_points[0,:], dest_points[1,:], linewidth=2, marker="o")
ax = plt.gca()
rect = patches.Rectangle(rectangle[:2], *(rectangle[2:] - rectangle[:2]),
linewidth=1, edgecolor="magenta", fill=False)
ax.add_patch(rect)
plt.ylim(-max_wh*2, max_wh*2)
plt.xlim(-max_wh * 2, max_wh * 2)
plt.title("degree = " + str(theta))
plt.show()
Affintransformationen können durch Einnahme eines Matrixprodukts kombiniert werden. Bei der Konvertierung von $ A_1-> A_2 $ nehmen wir das Produkt von $ A_2A_1P $ ($ P $ ist eine Punktematrix). Beachten Sie, dass die Reihenfolge umgekehrt ist. Außerdem gilt ** das Umtauschgesetz nicht **, und wenn Sie die Reihenfolge ändern, ist das Ergebnis anders.
Angenommen, $ A_1 $ verdoppelt $ x, y $, $ A_2 $ bewegt sich 50 in Richtung $ x $ und 100 bewegt sich in Richtung $ y $. Zu diesem Zeitpunkt ist $ A_2A_1 (A_1 \ bis A_2) $
$ A_1A_2 (A_2 \ bis A_1) $ ist jedoch
Und die Größe der Parallelbewegung ändert sich. Dies stellt den Unterschied zwischen "parallel bewegen und dann expandieren oder expandieren und dann parallel bewegen" dar. Wenn Sie die Reihenfolge nicht kennen, ist es eine gute Idee, ein einfaches Beispiel wie dieses zu versuchen.
Da die Affin-Transformation früher auf eine beliebige Anzahl von Punkten angewendet werden kann, ist es in Ordnung, Tausende von Punkten zu haben. Hier "kluge Person" (aus freiem Material)
Wird in Punktgruppendaten konvertiert und das Plotten wird durchgeführt, während die affinen Expansions- und Rotationstransformationen synthetisiert werden. Fast das gleiche wie in Beispiel 4.
from PIL import Image
def atamanowaruihito():
with Image.open("atamanowaruihito.png ") as img:
img = img.resize((img.width // 2, img.height // 2))
img = img.convert("L").point(lambda x: 255 if x >= 128 else 0) #Vergrauung, Binarisierung
points = np.stack(np.where(np.array(img) == 0)[::-1], axis=0) # yx ->xy, um die Punkte zu matrixisieren
points[1,:] = img.height - points[1,:] #Korrigieren Sie die y-Achse von positiv nach unten nach positiv nach oben(2, 5912)
points = np.concatenate([points, np.ones_like(points[0:1, :])], axis=0) #Fügen Sie 1 in die 3. Zeile ein(3, 5912)
for theta in range(0, 360, 1):
rad = np.radians(theta)
rotate_matrix = np.array([
[np.cos(rad), -np.sin(rad), 0],
[np.sin(rad), np.cos(rad), 0],
[0, 0, 1]], np.float32) #Rotationsmatrix
scale_matrix = np.eye(3, dtype=np.float32) * (1 + theta / 180)
#Die Affintransformationssynthese ist das Matrixprodukt der Transformationsmatrix
# A1->Nehmen Sie für A2 das Produkt in der Reihenfolge A2A1 (beachten Sie die Reihenfolge).
affine = np.dot(scale_matrix, rotate_matrix) #Drehen und erweitern
dest_points = np.dot(affine, points)[:2, :] #Punktgruppe nach Drehung
rectangle = np.concatenate([np.min(dest_points, axis=-1),
np.max(dest_points, axis=-1)]) #Begrenzungsrahmen für Punkte
plt.clf()
plt.scatter(dest_points[0,:], dest_points[1,:], s=1)
ax = plt.gca()
rect = patches.Rectangle(rectangle[:2], *(rectangle[2:] - rectangle[:2]),
linewidth=1, edgecolor="magenta", fill=False)
ax.add_patch(rect)
plt.ylim(-750, 750)
plt.xlim(-750, 750)
plt.show()
Der Begrenzungsrahmen kann auf die gleiche Weise wie das quadratische Beispiel berechnet werden.
Ab hier ist die Tensorberechnung. Betrachten Sie eine Methode zum gleichzeitigen Anwenden mehrerer Affin-Transformationen auf denselben Punkt, anstatt Affin-Transformationen zu synthetisieren. Es ist schwer, sich in einem Ausdruck auszudrücken, also denken Sie in Code.
Wenn es nur eine affine Transformation gäbe, hätte die Transformationsmatrix die Form "(3, 3)". Aber was ist, wenn es zwei Transformationen gibt, nämlich die Form `(2, 3, 3)`
? Mit anderen Worten,
# points(4 Punkte): (3, 4), affines: (2, 3, 3)
output = np.zeros((2, 3, 4)
for i in range(affines.shape[0]):
output[i] = np.dot(affines[i], points)
Ich möchte berechnen. Tatsächlich ist dies ein Einzeiler ohne for-Schleife.
output = np.matmul(affines, points)
Es kann mit berechnet werden.
Versuchen wir drei affine Transformationen in Beispiel 3.
from matplotlib import cm
def rectangle_multi():
w, h = 2, 1
points = np.array([[0, w, w, 0], [0, 0, h, h], [1, 1, 1, 1]], np.float32) # (3, 4)
a1 = np.eye(3) #Gleiche Umwandlung
a2 = np.array([[2, 0, 5], [0, 3, -1], [0, 0, 1]]) # (3, 3)
a3 = np.array([[3, 0, 10], [0, 1, 2], [0, 0, 1]]) # (3, 3)
affine = np.stack([a1, a2, a3], axis=0) # (3, 3, 3)
dest = np.matmul(affine, points) # (3, 3, 4)
cmap = cm.get_cmap("tab10")
for i in range(3):
plt.scatter(dest[i,0,:], dest[i, 1,:], color=cmap(i))
plt.show()
Ich konnte drei verschiedene Transformationen in nur einer Berechnung durchführen. Auf diese Weise kann eine Eins-zu-Viele-Umwandlung auch unter Verwendung einer affinen Umwandlung unter Verwendung eines Tensors durchgeführt werden.
Bei der Objekterkennung wird die Begrenzungsbox von jedem Punkt (Anker) der Ausgabe des neuronalen Netzwerks vorhergesagt. Der Begrenzungsrahmen entspricht den (Koordinaten) des Rohbilds, bei der Objekterkennung werden jedoch viele Koordinaten angezeigt. Zum Beispiel
Mit anderen Worten ist eine flexible Punktkonvertierung "von Koordinate zu Koordinate" erforderlich. Diese Koordinatentransformation kann durch die affine Transformation durch Tensor vereinheitlicht werden.
Betrachten Sie nun Folgendes:
Berücksichtigen Sie als Richtlinie zwei affine Conversions.
`(3, 3)`
.`(i, j,:, :)`
$ (0 \ leq i, j \ leq 3) Die affine Umwandlung an der Position von $ ist wie folgt. Da es sich um eine parallele Bewegung handelt, die von der Ankerbox aus gesehen wird, ist das Vorzeichen negativ.Alles was Sie tun müssen, ist die beiden, 1 und 2 zu kombinieren. Dies ist köstlich, wenn Sie die inverse Konvertierung (Anker → Originalbild) durchführen möchten, dh die inverse Matrix des zusammengesetzten Tensors von 1 und 2 nehmen möchten
inv_transform = np.linalg.inv(combined_affine)
Sie können den inversen Umwandlungstensor einfach erhalten, indem Sie dies tun. Wenn die Eingabe von `` `np.linalg.inv``` ein Tensor ist, stapeln Sie die inverse Matrix für die letzten beiden Achsen.
Für die Objekterkennung ist die Notation von $ (y, x) $ bequemer als die Notation von $ (x, y) $ (da der Tensor des Bildes $ (B, H, W, C) $ ist), also parallele Bewegung Affin-Konvertierung von $ t_x, t_y $, Skalierung von $ s_x, s_y $
Es wird vertreten durch. Selbst wenn die Achsen vertauscht werden, fungiert es dennoch als affine Konvertierung.
def anchor_box():
bounding_boxes = np.array([[10, 20, 30, 40], [30, 30, 50, 50]]) # (2, 4)
points = bounding_boxes.reshape(-1, 2).T # (4, 2) -> (2, 4)
points = np.concatenate([points, np.ones_like(points[0:1,:])], axis=0) # (3, 4)
#Denken Sie in yx-Koordinaten
a1 = np.array([[0.8, 0, 0], [0, 1.5, 0], [0, 0, 1]]) #0 in y-Richtung.8 mal, 1 in x-Richtung.5 mal
#Anker
offset_x, offset_y = np.meshgrid(-(np.arange(4) + 0.5), -(np.arange(4) + 0.5)) #Da der Ursprung des Eingabebildes vom Anker aus gesehen wird, abzüglich paralleler Bewegung
a2 = np.zeros((4, 4, 3, 3)) + np.eye(3).reshape(1, 1, 3, 3) / 16.0 # (4, 4, 3, 3)Ausstrahlung an
a2[:,:,0,2] = offset_y
a2[:,:, 1, 2] = offset_x
a2[:,:, 2, 2] = 1.0
#Affinsynthese
affine = np.matmul(a2, a1)
#Affin-Konvertierung
raw_dest = np.matmul(affine, points) # (4, 4, 3, 4)
dest = raw_dest.swapaxes(-1, -2)[:,:,:,:2] # (4, 4, 4, 3)Relocation Tensol Version-> (4, 4, 4, 2)
dest = dest.reshape(4, 4, 2, 4)
print("Koordinaten nach affiner Konvertierung, wenn der Begrenzungsrahmen des Originalbilds an jedem Anker angezeigt wird")
print(dest)
#Konvertierung rückgängig machen und prüfen
raw_inv = np.matmul(np.linalg.inv(affine), raw_dest)
inv = raw_inv.swapaxes(-1, -2)[:,:,:,:2]
inv = inv.reshape(4, 4, 2, 4) #Stimmt mit Begrenzungsrahmen überein
print("Die inverse Konvertierung der konvertierten Koordinaten kehrt zum ursprünglichen Wert zurück")
print(inv)
#Inverse Conversion affine (Bestätigung)
inv_transoform = np.linalg.inv(affine)
print("Inverse Conversion affine (zum Debuggen)")
print(inv_transoform)
Koordinaten nach affiner Konvertierung, wenn der Begrenzungsrahmen des Originalbilds an jedem Anker angezeigt wird
[[[[ 0. 1.375 1. 3.25 ]
[ 1. 2.3125 2. 4.1875]]
[[ 0. 0.375 1. 2.25 ]
[ 1. 1.3125 2. 3.1875]]
[[ 0. -0.625 1. 1.25 ]
[ 1. 0.3125 2. 2.1875]]
[[ 0. -1.625 1. 0.25 ]
[ 1. -0.6875 2. 1.1875]]]
[[[-1. 1.375 0. 3.25 ]
[ 0. 2.3125 1. 4.1875]]
[[-1. 0.375 0. 2.25 ]
[ 0. 1.3125 1. 3.1875]]
[[-1. -0.625 0. 1.25 ]
[ 0. 0.3125 1. 2.1875]]
[[-1. -1.625 0. 0.25 ]
[ 0. -0.6875 1. 1.1875]]]
[[[-2. 1.375 -1. 3.25 ]
[-1. 2.3125 0. 4.1875]]
[[-2. 0.375 -1. 2.25 ]
[-1. 1.3125 0. 3.1875]]
[[-2. -0.625 -1. 1.25 ]
[-1. 0.3125 0. 2.1875]]
[[-2. -1.625 -1. 0.25 ]
[-1. -0.6875 0. 1.1875]]]
[[[-3. 1.375 -2. 3.25 ]
[-2. 2.3125 -1. 4.1875]]
[[-3. 0.375 -2. 2.25 ]
[-2. 1.3125 -1. 3.1875]]
[[-3. -0.625 -2. 1.25 ]
[-2. 0.3125 -1. 2.1875]]
[[-3. -1.625 -2. 0.25 ]
[-2. -0.6875 -1. 1.1875]]]]
Die inverse Konvertierung der konvertierten Koordinaten kehrt zum ursprünglichen Wert zurück
[[[[10. 20. 30. 40.]
[30. 30. 50. 50.]]
[[10. 20. 30. 40.]
[30. 30. 50. 50.]]
[[10. 20. 30. 40.]
[30. 30. 50. 50.]]
[[10. 20. 30. 40.]
[30. 30. 50. 50.]]]
[[[10. 20. 30. 40.]
[30. 30. 50. 50.]]
[[10. 20. 30. 40.]
[30. 30. 50. 50.]]
[[10. 20. 30. 40.]
[30. 30. 50. 50.]]
[[10. 20. 30. 40.]
[30. 30. 50. 50.]]]
[[[10. 20. 30. 40.]
[30. 30. 50. 50.]]
[[10. 20. 30. 40.]
[30. 30. 50. 50.]]
[[10. 20. 30. 40.]
[30. 30. 50. 50.]]
[[10. 20. 30. 40.]
[30. 30. 50. 50.]]]
[[[10. 20. 30. 40.]
[30. 30. 50. 50.]]
[[10. 20. 30. 40.]
[30. 30. 50. 50.]]
[[10. 20. 30. 40.]
[30. 30. 50. 50.]]
[[10. 20. 30. 40.]
[30. 30. 50. 50.]]]]
Inverse Conversion affine (zum Debuggen)
[[[[20. 0. 10. ]
[ 0. 10.66666667 5.33333333]
[ 0. 0. 1. ]]
[[20. 0. 10. ]
[ 0. 10.66666667 16. ]
[ 0. 0. 1. ]]
[[20. 0. 10. ]
[ 0. 10.66666667 26.66666667]
[ 0. 0. 1. ]]
[[20. 0. 10. ]
[ 0. 10.66666667 37.33333333]
[ 0. 0. 1. ]]]
[[[20. 0. 30. ]
[ 0. 10.66666667 5.33333333]
[ 0. 0. 1. ]]
[[20. 0. 30. ]
[ 0. 10.66666667 16. ]
[ 0. 0. 1. ]]
[[20. 0. 30. ]
[ 0. 10.66666667 26.66666667]
[ 0. 0. 1. ]]
[[20. 0. 30. ]
[ 0. 10.66666667 37.33333333]
[ 0. 0. 1. ]]]
[[[20. 0. 50. ]
[ 0. 10.66666667 5.33333333]
[ 0. 0. 1. ]]
[[20. 0. 50. ]
[ 0. 10.66666667 16. ]
[ 0. 0. 1. ]]
[[20. 0. 50. ]
[ 0. 10.66666667 26.66666667]
[ 0. 0. 1. ]]
[[20. 0. 50. ]
[ 0. 10.66666667 37.33333333]
[ 0. 0. 1. ]]]
[[[20. 0. 70. ]
[ 0. 10.66666667 5.33333333]
[ 0. 0. 1. ]]
[[20. 0. 70. ]
[ 0. 10.66666667 16. ]
[ 0. 0. 1. ]]
[[20. 0. 70. ]
[ 0. 10.66666667 26.66666667]
[ 0. 0. 1. ]]
[[20. 0. 70. ]
[ 0. 10.66666667 37.33333333]
[ 0. 0. 1. ]]]]
Sie können sehen, dass die Koordinaten des ursprünglichen Begrenzungsrahmens wiederhergestellt werden, auch wenn das Originalbild → Anker und Anker → Originalbild umgekehrt konvertiert werden. Es ist stark, dass es bei der Matrixberechnung nur eine inverse Umwandlung gibt. Wenn Sie sehen möchten, ob die Ankerkonvertierung funktioniert, können Sie die affine inverse Konvertierung (inverse Matrix) leicht überprüfen.
Sie können dies auch tun, indem Sie die affine Transformation durch den Tensor nutzen. Bitte schauen Sie sich das Video unten an.
Ich werde die Erklärung weglassen, aber wenn Sie interessiert sind, schauen Sie sich bitte den Code an.
def atamanowaruihito2():
with Image.open("atamanowaruihito.png ") as img:
img = img.resize((img.width // 2, img.height // 2))
img = img.convert("L").point(lambda x: 255 if x >= 128 else 0) #Vergrauung, Binarisierung
points = np.stack(np.where(np.array(img) == 0)[::-1], axis=0) # yx ->xy, um die Punkte zu matrixisieren
points[1,:] = img.height - points[1,:] #Korrigieren Sie die y-Achse von positiv nach unten nach positiv nach oben(2, 5912)
points = np.concatenate([points, np.ones_like(points[0:1, :])], axis=0) #Fügen Sie 1 in die 3. Zeile ein(3, 5912)
#Zufallszahl für Rotationsmatrix
a = np.random.uniform(1.0, 5.0, size=(4, 4))
b = np.random.uniform(-180, 180, size=a.shape)
#Zufallszahl für Expansionsmatrix
c = np.random.uniform(0.5, 1.5, size=a.shape)
d = np.random.uniform(1.0, 5.0, size=a.shape)
e = np.random.uniform(-180, 180, size=a.shape)
f = np.random.uniform(0.5, 1.0, size=a.shape) + c
#Zufallszahl für Parallelbewegung
e = np.random.uniform(0, 200, size=a.shape)
g = np.random.uniform(1.0, 5.0, size=a.shape)
h = np.random.uniform(-180, 180, size=a.shape)
for theta in range(0, 360, 10):
#Rotationsumwandlung
rad = np.radians(a * theta + b)
rotate_tensor = np.broadcast_to(np.eye(3)[None, None,:], (4, 4, 3, 3)).copy()
rotate_tensor[:,:, 0, 0] = np.cos(rad)
rotate_tensor[:,:, 0, 1] = -np.sin(rad)
rotate_tensor[:,:, 1, 0] = np.sin(rad)
rotate_tensor[:,:, 1, 1] = np.cos(rad)
#Erweiterungskonvertierung
rad = np.radians(d * theta + e)
scale_tensor = np.broadcast_to(np.eye(3)[None, None,:], (4, 4, 3, 3)).copy()
scale_tensor[:,:, 0, 0] = c * np.sin(rad) + f
scale_tensor[:,:, 1, 1] = c * np.sin(rad) + f
#Individuelle Parallelbewegung
rad = np.radians(g * theta + h)
transform_tensor = np.broadcast_to(np.eye(3)[None, None,:], (4, 4, 3, 3)).copy()
transform_tensor[:,:, 0, 2] = e * np.cos(rad)
transform_tensor[:,:, 1, 2] = e * np.sin(rad)
#Insgesamt parallele Bewegung
shift_x, shift_y = np.meshgrid(np.arange(4), np.arange(4))
anchor_tensor = np.broadcast_to(np.eye(3)[None, None,:], (4, 4, 3, 3)).copy()
anchor_tensor[:,:, 0, 2] = shift_x * 500
anchor_tensor[:,:, 1, 2] = shift_y * 500
#Drehung → Vergrößerung → Parallelbewegung → Gesamtparallelbewegung
affine = np.matmul(anchor_tensor, transform_tensor)
affine = np.matmul(affine, scale_tensor)
affine = np.matmul(affine, rotate_tensor)
dest_points = np.matmul(affine, points)[:, :, :2, :] #Punktgruppe nach Drehung
rectangle = np.concatenate([np.min(dest_points, axis=-1),
np.max(dest_points, axis=-1)], axis=-1) #Begrenzungsrahmen für Punkte
dest_points = dest_points.swapaxes(-1, -2).reshape(-1, 2)
rectangle = rectangle.reshape(-1, 4)
plt.clf()
plt.scatter(dest_points[:, 0], dest_points[:, 1], s=1)
ax = plt.gca()
for i in range(rectangle.shape[0]):
rect = patches.Rectangle(rectangle[i, :2], *(rectangle[i, 2:] - rectangle[i, :2]),
linewidth=1, edgecolor="magenta", fill=False)
ax.add_patch(rect)
plt.ylim(-750, 2500)
plt.xlim(-750, 2500)
plt.title("theta = " + str(theta))
plt.show()
Recommended Posts