Comment convertir un tableau NumPy en image PIL en appliquant la palette de couleurs matplotlib

134

J'ai un problème simple, mais je ne trouve pas de bonne solution.

Je veux prendre un tableau NumPy 2D qui représente une image en niveaux de gris et le convertir en une image RGB PIL tout en appliquant certaines des cartes de couleurs matplotlib.

Je peux obtenir une sortie PNG raisonnable en utilisant la pyplot.figure.figimagecommande:

dpi = 100.0
w, h = myarray.shape[1]/dpi, myarray.shape[0]/dpi
fig = plt.figure(figsize=(w,h), dpi=dpi)
fig.figimage(sub, cmap=cm.gist_earth)
plt.savefig('out.png')

Bien que je puisse adapter cela pour obtenir ce que je veux (probablement en utilisant StringIO pour obtenir l'image PIL), je me demande s'il n'y a pas un moyen plus simple de le faire, car cela semble être un problème très naturel de visualisation d'image. Disons quelque chose comme ça:

colored_PIL_image = magic_function(array, cmap)
heltonbiker
la source
Pour un code entièrement fonctionnel, vous pouvez vous référer: Y a
Adam

Réponses:

222

Un one-liner assez chargé, mais le voici:

  1. Assurez-vous d'abord que votre tableau NumPy,, myarrayest normalisé avec la valeur maximale à 1.0.
  2. Appliquez la palette de couleurs directement sur myarray.
  3. Redimensionner à la 0-255gamme.
  4. Convertir en nombres entiers, en utilisant np.uint8().
  5. Utilisez Image.fromarray().

Et tu as fini:

from PIL import Image
from matplotlib import cm
im = Image.fromarray(np.uint8(cm.gist_earth(myarray)*255))

avec plt.savefig():

Entrez la description de l'image ici

avec im.save():

Entrez la description de l'image ici

Fraxel
la source
7
La partie «Appliquer la palette de couleurs directement sur myarray» est coupée directement au cœur! Je ne savais pas que c'était possible, merci!
heltonbiker
34
En étudiant la documentation sur LinearSegmentedColormap (dont cm.gist_earth est une instance), j'ai découvert qu'il est possible de l'appeler avec un argument "bytes" qui le convertit déjà en uint8. Ensuite, le one-liner devient beaucoup plus silencieux:im = Image.fromarray(cm.gist_earth(myarray, bytes=True))
heltonbiker
1
@CiprianTomoiaga, la forme du tableau doit correspondre aux dimensions de l'image souhaitées. Par exemple, une image VGA serait générée à partir d'un tableau de forme (1024 768). Vous devriez remarquer que cela s'applique aux images monochromes. Ceci est important car généralement, lorsque vous convertissez une image RVB en un tableau, sa forme est, par exemple, (1024,768,3), car elle comporte trois canaux.
heltonbiker
5
Je reçois une erreurNameError: name 'cm' is not defined
rnso
10
@msofrom matplotlib import cm
Quantum7
10
  • input = numpy_image
  • np.unit8 -> convertit en entiers
  • convert ('RGB') -> convertit en RVB
  • Image.fromarray -> renvoie un objet image

    from PIL import Image
    import numpy as np
    
    PIL_image = Image.fromarray(np.uint8(numpy_image)).convert('RGB')
    
    PIL_image = Image.fromarray(numpy_image.astype('uint8'), 'RGB')
Aravinda_gn
la source
5
J'espère que cela résoudra le problème, mais veuillez ajouter une explication de votre code afin que l'utilisateur comprenne parfaitement ce qu'il / elle veut vraiment.
Jaimil Patel le
1
Bonne réponse mise à jour. Les précédents datent d'il y a plusieurs années.
Catalina Chircu le
7

La méthode décrite dans la réponse acceptée n'a pas fonctionné pour moi même après avoir appliqué les modifications mentionnées dans ses commentaires. Mais le code simple ci-dessous a fonctionné:

import matplotlib.pyplot as plt
plt.imsave(filename, np_array, cmap='Greys')

np_array pourrait être soit un tableau 2D avec des valeurs de 0..1 floats o2 0..255 uint8, et dans ce cas, il a besoin de cmap. Pour les tableaux 3D, cmap sera ignoré.

Shital Shah
la source