Come convertire un array NumPy in immagine PIL applicando la mappa colori matplotlib


133

Ho un problema semplice, ma non riesco a trovare una buona soluzione.

Voglio prendere un array 2D NumPy che rappresenta un'immagine in scala di grigi e convertirlo in un'immagine PIL RGB mentre si applicano alcune delle mappe di colori matplotlib.

Posso ottenere un output PNG ragionevole usando il pyplot.figure.figimagecomando:

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')

Anche se potrei adattare questo per ottenere ciò che voglio (probabilmente usando StringIO ottieni l'immagine PIL), mi chiedo se non ci sia un modo più semplice per farlo, dal momento che sembra essere un problema molto naturale di visualizzazione delle immagini. Diciamo qualcosa del genere:

colored_PIL_image = magic_function(array, cmap)

Risposte:


221

Abbastanza impegnativo one-liner, ma eccolo qui:

  1. Per prima cosa assicurati che l'array NumPy myarray, sia normalizzato con il valore massimo a 1.0.
  2. Applicare la mappa colori direttamente a myarray.
  3. Riscala alla 0-255gamma.
  4. Converti in numeri interi, usando np.uint8().
  5. Usa Image.fromarray().

E hai finito:

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

con plt.savefig():

Inserisci qui la descrizione dell'immagine

con im.save():

Inserisci qui la descrizione dell'immagine


7
La parte "Applica la mappa colori direttamente a myarray" taglia direttamente sul cuore! Non sapevo che fosse possibile, grazie!
heltonbiker,

34
Studiando i documenti su LinearSegmentedColormap (da cui cm.gist_earth è un'istanza), ho scoperto che è possibile chiamarlo con un argomento "bytes" che lo converte già in uint8. Quindi, il one-liner diventa molto più silenzioso:im = Image.fromarray(cm.gist_earth(myarray, bytes=True))
heltonbiker il

1
@CiprianTomoiaga, la forma dell'array dovrebbe essere la dimensione dell'immagine desiderata. Ad esempio, un'immagine VGA verrebbe generata da un array con forma (1024.768). Dovresti notare che questo vale per le immagini monocromatiche. Questo è importante perché di solito quando si converte un'immagine RGB in un array, la sua forma è, ad esempio, (1024.768,3), poiché ha tre canali.
Heltonbiker

5
Ricevo un erroreNameError: name 'cm' is not defined
anche il

10
@msofrom matplotlib import cm
Quantum7,

10
  • input = numpy_image
  • np.unit8 -> converte in numeri interi
  • convert ('RGB') -> converte in RGB
  • Image.fromarray -> restituisce un oggetto immagine

    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')

5
Spero che risolva il problema, ma per favore aggiungi una spiegazione del tuo codice con esso in modo che l'utente possa capire perfettamente ciò che desidera davvero.
Jaimil Patel,

1
Buona risposta aggiornata. I precedenti risalgono a diversi anni fa.
Catalina Chircu,

7

Il metodo descritto nella risposta accettata non ha funzionato per me anche dopo aver applicato le modifiche menzionate nei suoi commenti. Ma il seguente codice semplice ha funzionato:

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

np_array potrebbe essere un array 2D con valori da 0..1 float o2 0..255 uint8 e in tal caso necessita di cmap. Per le matrici 3D, il cmap verrà ignorato.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.