[PYTHON] Approximation de bas rang des images par décomposition de singularité

introduction

Faites-vous une décomposition de valeurs singulières? > Salutations

J'ai l'impression que les gens autour de moi ne décomposent que récemment des valeurs singulières, alors j'ai décidé de l'essayer également. Pour le moment, considérez l'image comme une matrice telle qu'elle est et effectuez une décomposition en valeur singulière (SVD) pour créer une image avec une approximation de faible rang. Pour la décomposition des singularités, [Wikipedia](https://ja.wikipedia.org/wiki/%E7%89%B9%E7%95%B0%E5%80%A4%E5%88%86%E8%A7% Veuillez vous référer à A3).

Je ne sais pas qui a commencé l'histoire de la décomposition des images à valeur singulière, mais je suis dans cet article [T. Kumamoto, M. Suzuki et H. Matsueda arXiv: 1608.08333](https://arxiv.org/abs/ J'ai appris de 1608.08333).

Le code source est https://github.com/kaityo256/image_svd C'est dedans.

Chargement des images

Utilisez Pillow of Python pour charger l'image. Si non

$ pip install Pillow

Mettons-le dedans.

Bien qu'il s'agisse d'une image d'entrée, il est plus facile de comprendre la précision d'approximation s'il y a des caractères, j'ai donc préparé quelque chose comme ça pour le moment.

stop.jpg

Commencez par convertir cela en échelle de gris.

from PIL import Image
img = Image.open('stop.jpg')
gray_img = img.convert('L')
gray_img.save('stop_mono.jpg')

Je me sens comme cela.

stop_mono.jpg

Décomposition de singularité

Utilisez numpy et scipy pour la décomposition de singularité. Importons-le.

import numpy as np
from scipy import linalg

L'accès aux données d'image peut être lu tel quel avec un tableau de numpy. Après cela, vous pouvez SVD avec linalg.svd de scipy. C'est trop facile.

a = np.asarray(gray_img)
u, s, v = linalg.svd(a)

Les u, s et v créés ici sont les résultats d'une décomposition de valeurs singulières. Parmi ceux-ci, s est une liste de valeurs singulières.

Approximation de bas rang

Si seuls les rangs supérieurs sont sélectionnés et reconstruits à partir des décompositions de singularité, une approximation de rang bas sera obtenue.

image.png

Cependant, bien que Σ (s dans le code) soit vraiment une matrice, c'est un vecteur dans la valeur de retour de linalg.svd, il doit donc être converti en matrice. Après cela, si vous multipliez les morceaux coupés par la quantité requise, vous obtiendrez une matrice approximative de bas rang. Le code ressemble à ceci.

rank = 10
ur = u[:, :rank]
sr = np.matrix(linalg.diagsvd(s[:rank], rank,rank))
vr = v[:rank, :]
b = np.asarray(ur*sr*vr)
img2 = Image.fromarray(np.uint8(b))
img2.save('stop_r10_mono.jpg')

Le résultat obtenu est comme ça.

stop_r10_mono.jpg

Version couleur

Ce qui précède est une échelle de gris pour plus de simplicité, mais si vous SVD chaque élément de RVB, vous pouvez également créer une version couleur. Le seul point addictif ici est que dans la version monochrome, j'ai utilisé Image.fromarray tel quel, mais en couleur, je dois en faire un tableau de (r, g, b) tapples. L'objet qui peut être créé en multipliant la matrice de numpy est un objet Matrix, donc pour y accéder en tant que tableau après cela, vous devez le renvoyer dans un tableau avec np.asarray. Si vous faites attention à cela, vous pouvez le faire tout de suite.

Créez une fonction d'approximation de bas rang de la matrice comme ceci.

def perform_svd(a,rank):
    u, s, v = linalg.svd(a)
    ur = u[:, :rank]
    sr = np.matrix(linalg.diagsvd(s[:rank], rank,rank))
    vr = v[:rank, :]
    return np.asarray(ur*sr*vr)

Le fait est que la valeur de retour est un tableau avec un tableau. Avec cela, vous pouvez facilement créer une version couleur.

    w = img.width
    h = img.height
    A = np.asarray(img)
    r = perform_svd(A[:,:,0],rank).reshape(w*h)
    g = perform_svd(A[:,:,1],rank).reshape(w*h)
    b = perform_svd(A[:,:,2],rank).reshape(w*h)
    B = np.asarray([r,g,b]).transpose(1,0).reshape(h,w,3)
    img2 = Image.fromarray(np.uint8(B))
    img2 = Image.fromarray(np.uint8(data))
    img2.save(`stop_r10.jpg`)

Si vous créez un tableau numpy à partir de données d'image, ce sera un tableau tridimensionnel de (hauteur, largeur, couleur), donc si vous SVD chaque couleur et l'attachez, ce sera un tableau de (couleur, hauteur * largeur). Donc, après l'avoir remplacé par transpose, remodelez-le à la forme du tableau 3D d'origine et plongez-le dans ʻImage.fromarray`.

L'image résultante ressemble à ceci.

stop_r10.jpg

en conclusion

Avec cette image, si vous prenez 20 rangs, vous pouvez presque restaurer l'image d'origine. Ce serait amusant de savoir combien il faut prendre et quel type d'image a quel type de spectre.

Non, mais si vous lisez l'image, faites-en une échelle de gris, transformez-la en matrice, SVD, faites une approximation de rang bas, restaurez-la dans l'image et enregistrez-la, et importez la bibliothèque appropriée avec Python, vous pouvez le faire en 15 lignes. Je vois ... Je pense que "la richesse de la bibliothèque est la force de la langue" ...

Recommended Posts

Approximation de bas rang des images par décomposition de singularité
Approximation de bas rang de l'image par décomposition de Tucker
Approximation de bas rang des images par HOSVD étape par étape
Approximation de bas rang des images par HOSVD et HOOI
Décomposition de singularité (SVD), approximation de bas rang (LRA) en Python
Essayez de décomposer la matrice daimyo par valeur singulière
Essayez la décomposition de valeurs singulières avec Python
Histoire d'approximation de puissance par Python
Détection de visage en collectant des images d'Angers.
Classification des images de guitare par apprentissage automatique Partie 1
Classification des images de guitare par apprentissage automatique, partie 2
Rechercher par la valeur de l'instance dans la liste
Optical Flow, l'image dynamique capturée par OpenCV
J'ai comparé l'identité des images par moment Hu