[PYTHON] Schritt-für-Schritt-Approximation von Bildern mit niedrigem Rang durch HOSVD

Einführung

Wenn ich mit Tensoren zu tun habe, bin ich oft verwirrt über "das? Welcher Fuß ist wo?" Basierend auf Näherung von Bildern mit niedrigem Rang durch HOSVD fahren wir mit den Schritten fort, während wir jedes einzelne überprüfen.

Unter der Annahme einer praktischen Ausbildung werde ich den Prozess im Folgenden ausführlich beschreiben.

Schritt für Schritt

Schritt 1 Bis das Bild geladen ist

Im Folgenden habe ich es zur Vereinfachung der Anzeige im interaktiven Python-Modus geschrieben, aber in Wirklichkeit ist es bequemer, es mit ipython zu tun.

Importieren wir zunächst die erforderlichen Bibliotheken.

>>> import numpy as np
>>> from scipy import linalg
>>> from PIL import Image

Laden Sie als Nächstes ein entsprechendes Bild. Ich hatte gerade ein Bild von angemessener Größe zur Hand, also lasst es uns verwenden.

uma.jpg

Dies ist das Itanum 2 Spirit Horse.

Lassen Sie uns dies lesen und die Größe überprüfen.

>>> img = Image.open("uma.jpg ")
>>> img.size
(480, 340)

Es handelt sich um Bilddaten mit 480 x 340 Pixel. Legen Sie für später die Höhe und Breite in Variablen ab.

>>> w, h = img.size

Lassen Sie uns nun die Bilddaten in ein Numpy-Array konvertieren.

>>> X = np.asarray(img)
>>> X.shape
(340, 480, 3)

Beachten Sie, dass die Reihenfolge "Höhe, Breite, 3 (RGB)" lautet.

Schritt 2 Tauschen Sie die Beine aus, um die SVD vorzubereiten

Ich werde von nun an SVD machen, aber ich muss den Fuß bringen, um SVD ganz rechts zu machen und den Tensor im 3. Stock in eine Matrix zu verwandeln. Verwenden Sie Transponieren, um die Beine zu tauschen.

Überprüfen Sie erneut die Abmessung von X.

>>> X.shape
(340, 480, 3)

Dies ist jetzt "Höhe, Breite, Farbe", aber zuerst möchte ich meine Beine über die Breite quetschen, also muss ich "Höhe, Farbe, Breite" bestellen. Da die Reihenfolge "Höhe, Breite, Farbe" (0,1,2) ist, ist die Zielreihenfolge (0,2,1).

>>> X.transpose(0,2,1).shape
(340, 3, 480)

Die Reihenfolge hat sich geändert. Dies wird weiter zu einer Matrix mit den beiden linken Beinen kombiniert.

>>> X.transpose(0,2,1).reshape(h*3,w).shape
(1020, 480)

Sie haben erfolgreich eine Matrix mit Abmessungen (Höhe und Farbe, Breite) erstellt. Speichern wir dies als X1.

>>> X1 = X.transpose(0,2,1).reshape(h*3,w)

Ebenso möchte ich eine Matrix mit einer Höhenbemaßung ganz rechts erstellen. Schauen Sie sich die X-Dimension noch einmal an.

>>> X.shape
(340, 480, 3)

Ich möchte dies machen (480, 3, 340) [^ rgb]. Zu diesem Zweck sollte die Reihenfolge (1,2,0) sein.

>>> X.transpose(1,2,0).shape
(480, 3, 340)

Stellen Sie die beiden linken Beine in einer Warteschlange zusammen und speichern Sie diese in X2.

>>> X2 = X.transpose(1,2,0).reshape(w*3,h)
>>> X2.shape
(1440, 340)

Die Abmessung des rechten Fußes ist die Höhe. Zu diesem Zeitpunkt ist die SVD bereit.

Schritt 3 SVD zur Herstellung eines Kerntensors

Erstens SVD X1. Lassen Sie uns jede Größe weiter überprüfen.

>>> U, s, A1 = linalg.svd(X1)
>>> U.shape
(1020, 1020)
>>> s.shape
(480,)
>>> A1.shape
(480, 480)

Komprimieren Sie nun die Informationen von A1 auf 5%. Ursprünglich waren es 480 Zeilen, daher werden nur die obersten 24 Zeilen abgerufen. Nennen wir das a1.

>>> a1 = A1[:24, :]
>>> a1.shape
(24, 480)

In ähnlicher Weise SVD X2 und nur die oberen 17 Zeilen (5% von 340) von A2 abrufen.

>>> U, s, A2 = linalg.svd(X2)
>>> A2.shape
(340, 340)
>>> a2 = A2[:17,:]
>>> a2.shape
(17, 340)

Wenn man die hier erhaltene Inversion von a1 und a2 nimmt, wird sie zu einer Kompressionsmatrix, die die Breite und Höhe zerquetscht.

>>> a1.T.shape
(480, 24)
>>> a2.T.shape
(340, 17)

Es ist ersichtlich, dass die Matrizen in 480 → 24 bzw. 340 → 17 zerkleinert werden. Wenn dies als inneres Produkt mit dem geeigneten Fuß von X genommen wird, wird ein Kerntensor erhalten.

Multiplizieren Sie zunächst X mit a1.T. Anhand der Form können Sie erkennen, welcher Fuß und welcher Fuß zu zerquetschen ist.

>>> X.shape
(340, 480, 3)
>>> a1.T.shape
(480, 24)

Zerdrücke das 1. Bein von X und das 0. Bein von a1.T. Ersetzen Sie dies durch X3.

>>> X3 = np.tensordot(X, a1.T, (1,0))
>>> X3.shape
(340, 3, 24)

Es wurde erfolgreich von 480 auf 24 komprimiert. Was hier zu beachten ist, ist die Reihenfolge der Beine nach dem Tensorpunkt. Bis Sie sich daran gewöhnt haben, sollten Sie jedes Mal die Form des Fußes des neuen Tensors überprüfen.

Wenden Sie als nächstes a2.T auf den Fuß an, der die Höhe von X3 darstellt, und komprimieren Sie ihn. Finden Sie heraus, welches wieder zerkleinert werden soll.

>>> X3.shape
(340, 3, 24)
>>> a2.T.shape
(340, 17)

Wenn alle Füße unterschiedlich groß sind, ist es praktisch, sofort zu wissen, dass Sie dieselbe Abmessung zerdrücken sollten. In diesem Fall können Sie also die Zahlen 0 zerdrücken

>>> x = np.tensordot(X3,a2.T,(0,0))
>>> x.shape
(3, 24, 17)

Sie haben erfolgreich einen Kerntensor x mit einer reduzierten Abmessung von X erhalten.

Schließlich wurde X in eine Breitenkomprimierungs- / Wiederherstellungsmatrix a1, eine Höhenkomprimierungs- / Wiederherstellungsmatrix a2 und einen Kerntensor x komprimiert. Lassen Sie uns dieses Komprimierungsverhältnis untersuchen.

>>> float(x.size + a1.size + a2.size)/X.size
0.03783496732026144

Wir konnten es also auf etwa 3,8% der Originaldaten komprimieren.

Schritt 4 Informationen wiederherstellen

Jetzt habe ich den Kerntensor x und die Breiten- und Höhenrekonstruktionsmatrizen a1 und a2. Wenn Sie den Kerntensor mit a1 und a2 multiplizieren, erhalten Sie den ungefähren Tensor Y des ursprünglichen Tensors. Machen wir es also.

Überprüfen Sie zunächst die Abmessungen.

>>> x.shape
(3, 24, 17)
>>> a1.shape
(24, 480)

Weil du nur den 1. von x und den 0. von a1 zerquetschen musst

>>> x2 = np.tensordot(x,a1,(1,0))
>>> x2.shape
(3, 17, 480)

Die Breite wurde von 24 auf 480 wiederhergestellt. In ähnlicher Weise sei x3 die wiederhergestellte Höhe.

>>> x3 = np.tensordot(x2,a2,(1,0))
>>> x3.shape
(3, 480, 340)

Die Reihenfolge der Beine ist jedoch unterschiedlich. Schauen Sie sich noch einmal X an.

>>> X.shape
(340, 480, 3)

Wenn Sie es mit X vergleichen, können Sie sehen, dass die Beine in der Größenordnung von (2,1,0) liegen sollten.

>>> Y = x3.transpose(2,1,0)
>>> Y.shape
(340, 480, 3)

Dies ist der Tensor, der aus dem Kerntensor x unter Verwendung der Wiederherstellungsmatrizen a1 und a2 wiederhergestellt wurde. Jetzt, da wir die gleichen Abmessungen wie die Originaldaten haben, können wir ein Bildobjekt erstellen. Es muss jedoch vom Typ uint8 sein, bevor es in "Image.fromarray" eingefügt werden kann.

>>> img2 = Image.fromarray(np.uint8(Y))
>>> img2.save("approximated.jpg ")

Das auf diese Weise erstellte wiederhergestellte Bild sieht folgendermaßen aus. approximated.jpg

Nun, ich habe das Gefühl, dass ich es aus den auf 3,8% komprimierten Daten wiederherstellen konnte, ohne die Information zu verwenden, dass "das Original überhaupt ein Bild ist".

Zusammenfassung

Ich habe versucht, das Bild mit HOSVD (Higher Order Singular Value Decomposition) zu komprimieren und wiederherzustellen. Die Verwendung von IPython ist sehr praktisch, da es wie das Ausfüllen von Registerkarten funktioniert. Nachdem Sie die Beine des Tensors gequetscht haben, ist es leicht zu verwechseln, welche Zahl was ist, aber ich habe das Gefühl, dass Fehler / Verwirrung verringert werden, wenn Sie arbeiten, während Sie die Abmessungen mit jeder Form überprüfen.

Python ist praktisch, nicht wahr ... [^ ruby].

[^ rgb]: Hier liegt der Grund dafür, dass Höhe und Farbe der Beine nicht in der Größenordnung von (3.480.340) ausgetauscht werden, darin, dass die zusammengefassten Fußdaten mit (R, G, B, R, G, B ...) ausgerichtet sind. Ich möchte, dass. In der Reihenfolge (3.480.340) werden die Daten in der Reihenfolge (RRR ..., GGG ...., BBB ...) anders angeordnet als in X1.

[^ ruby]: Zur Zeit ist Ruby meine Lieblingssprache, aber der Reichtum der Bibliothek scheint zu sein, dass Python einen langen Tag hat ...

Recommended Posts

Schritt-für-Schritt-Approximation von Bildern mit niedrigem Rang durch HOSVD
Niedrigrangige Approximation von Bildern durch HOSVD und HOOI
Niedrigrangige Approximation des Bildes durch Tucker-Zerlegung
Niedrigrangige Approximation von Bildern durch Singularitätszerlegung
Geschichte der Potenznäherung von Python
Gesichtserkennung durch Sammeln von Bildern von Angers.
Rekonstruktion von bewegten Bildern mit dem Autoencoder unter Verwendung von 3D-CNN
Klassifizierung von Gitarrenbildern durch maschinelles Lernen Teil 1
Klassifizierung von Gitarrenbildern durch maschinelles Lernen Teil 2
Optischer Fluss, das von OpenCV aufgenommene dynamische Bild
Ich verglich die Identität der Bilder nach Hu Moment
Versuchen Sie, die Schritte umzugestalten