Comment convertir un tableau numpy en (et afficher) une image?

228

J'ai ainsi créé un tableau:

import numpy as np
data = np.zeros( (512,512,3), dtype=np.uint8)
data[256,256] = [255,0,0]

Ce que je veux faire, c'est afficher un seul point rouge au centre d'une image 512x512. (Au moins pour commencer ... je pense que je peux comprendre le reste à partir de là)

jlswint
la source
1
Voir aussi stackoverflow.com/questions/902761/… bien que celui-ci imposait la contrainte que PIL ne pouvait pas être utilisé.
Peter Hansen
Pourriez-vous envisager de changer la réponse acceptée à celle de Peter ? Cela évite à la fois la nécessité d'enrouler un objet autour du tableau numpy et évite d'écrire un fichier temporaire pour afficher l'image.
Josiah Yoder

Réponses:

225

Vous pouvez utiliser PIL pour créer (et afficher) une image:

from PIL import Image
import numpy as np

w, h = 512, 512
data = np.zeros((h, w, 3), dtype=np.uint8)
data[0:256, 0:256] = [255, 0, 0] # red patch in upper left
img = Image.fromarray(data, 'RGB')
img.save('my.png')
img.show()
unutbu
la source
3
Il semble qu'il y ait un bug. Vous créez un tableau avec une taille (w,h,3), mais cela devrait l'être (h,w,3), car l'indexation dans PIL diffère de l'indexation dans numpy. Il y a une question connexe: stackoverflow.com/questions/33725237/…
fdermishin
1
@ user502144: Merci d'avoir signalé mon erreur. J'aurais dû créer un tableau de formes (h,w,3). (Il est maintenant fixe, ci-dessus.) La longueur du premier axe peut être considérée comme le nombre de lignes dans le tableau, et la longueur du deuxième axe, le nombre de colonnes. (h, w)Correspond donc à un tableau de "hauteur" het "largeur" w. Image.fromarrayconvertit ce tableau en une image de hauteur het de largeur w.
unutbu
1
img.show()ne fonctionne pas dans le cahier ipython. img_pil = Image.fromarray(img, 'RGB') display(img_pil.resize((256,256), PIL.Image.LANCZOS))
mrgloom
@unutbu cette méthode semble déformer les images ... stackoverflow.com/questions/62293077/…
Ludovico Verniani
285

Les éléments suivants devraient fonctionner:

from matplotlib import pyplot as plt
plt.imshow(data, interpolation='nearest')
plt.show()

Si vous utilisez le cahier / laboratoire Jupyter, utilisez cette commande en ligne avant d'importer matplotlib:

%matplotlib inline 
Steve Tjoa
la source
3
C'est plus précis que PIL. PIL redimensionne / normalise les valeurs du tableau, tandis que pyplot utilise les valeurs RVB réelles telles quelles.
GaryO
21
Peut-être bon à savoir: si vous souhaitez afficher des images en niveaux de gris, il est conseillé d'appeler plt.gray()une fois dans votre code pour basculer tous les graphiques suivants en niveaux de gris. Pas ce que l'OP veut mais bon à savoir quand même.
Cerno
2
Comment l'enregistrer?
user334639
Fichier "<ipython-input-29-29c784f62838>", ligne 39 plt.show () ^ SyntaxError: syntaxe non valide
Mona Jalal
1
@Cerno De plus, les images en niveaux de gris doivent avoir une forme (h, w) plutôt que (h, w, 1). Vous pouvez utiliser squeeze()pour éliminer la troisième dimension:plt.imshow(data.squeeze())
Josiah Yoder
51

Le chemin le plus court est d'utiliser scipy, comme ceci:

from scipy.misc import toimage
toimage(data).show()

Cela nécessite également l'installation de PIL ou d'oreiller.

Une approche similaire nécessitant également PIL ou Pillow mais qui peut invoquer une visionneuse différente est:

from scipy.misc import imshow
imshow(data)
Peter Hansen
la source
Cette méthode est donc incompatible avec python 3.5 ...?
Christopher
@bordeo, pourquoi serait-il incompatible avec 3.5? C'est juste une importation et quelques appels de fonction.
Peter Hansen
PIL est incompatible avec 3.5 (ne s'installe pas)
Christopher
1
Ftr: vous pouvez encore raccourcir cela en utilisant directement scipy.misc.imshow(data).
dtk
3
toimagea été déconseillé dans scipy-1.0.0 et supprimé dans 1.2.0, en faveur de Pillow's Image.fromarray.
Sid
4

En utilisant pygame , vous pouvez ouvrir une fenêtre, obtenir la surface sous forme de tableau de pixels et manipuler comme vous le souhaitez à partir de là. Vous devrez cependant copier votre tableau numpy dans le tableau de surface, ce qui sera beaucoup plus lent que d'effectuer des opérations graphiques réelles sur les surfaces de pygame elles-mêmes.

Stefan Kendall
la source
3

Comment afficher des images stockées dans un tableau numpy avec un exemple (fonctionne dans le cahier Jupyter)

Je sais qu'il existe des réponses plus simples, mais celle-ci vous permettra de comprendre comment les images sont réellement noyées à partir d'un tableau numpy.

Exemple de chargement

from sklearn.datasets import load_digits
digits = load_digits()
digits.images.shape   #this will give you (1797, 8, 8). 1797 images, each 8 x 8 in size

Afficher le tableau d'une image

digits.images[0]
array([[ 0.,  0.,  5., 13.,  9.,  1.,  0.,  0.],
       [ 0.,  0., 13., 15., 10., 15.,  5.,  0.],
       [ 0.,  3., 15.,  2.,  0., 11.,  8.,  0.],
       [ 0.,  4., 12.,  0.,  0.,  8.,  8.,  0.],
       [ 0.,  5.,  8.,  0.,  0.,  9.,  8.,  0.],
       [ 0.,  4., 11.,  0.,  1., 12.,  7.,  0.],
       [ 0.,  2., 14.,  5., 10., 12.,  0.,  0.],
       [ 0.,  0.,  6., 13., 10.,  0.,  0.,  0.]])

Créez des sous-tracés vides de 10 x 10 pour visualiser 100 images

import matplotlib.pyplot as plt
fig, axes = plt.subplots(10,10, figsize=(8,8))

Tracer 100 images

for i,ax in enumerate(axes.flat):
    ax.imshow(digits.images[i])

Résultat:

entrez la description de l'image ici

Que fait axes.flat-il? Il crée un énumérateur numpy afin que vous puissiez itérer sur l'axe afin de dessiner des objets dessus. Exemple:

import numpy as np
x = np.arange(6).reshape(2,3)
x.flat
for item in (x.flat):
    print (item, end=' ')
Harvey
la source
2

Utilisation de fromarray d'oreiller, par exemple:

from PIL import Image
from numpy import *

im = array(Image.open('image.jpg'))
Image.fromarray(im).show()
user3322286
la source
0

Supplément pour le faire avec matplotlib. Je l'ai trouvé pratique pour effectuer des tâches de vision par ordinateur. Disons que vous avez des données avec dtype = int32

from matplotlib import pyplot as plot
import numpy as np

fig = plot.figure()
ax = fig.add_subplot(1, 1, 1)
# make sure your data is in H W C, otherwise you can change it by
# data = data.transpose((_, _, _))
data = np.zeros((512,512,3), dtype=np.int32)
data[256,256] = [255,0,0]
ax.imshow(data.astype(np.uint8))
user140536
la source