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.
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.
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.
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.
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.
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.
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.
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