Como converter uma matriz NumPy em imagem PIL aplicando o mapa de cores matplotlib

133

Eu tenho um problema simples, mas não consigo encontrar uma boa solução para ele.

Eu quero pegar uma matriz NumPy 2D que representa uma imagem em escala de cinza e convertê-la em uma imagem RGB PIL enquanto aplico alguns dos mapas de cores matplotlib.

Posso obter uma saída PNG razoável usando o 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')

Embora eu possa adaptar isso para obter o que quero (provavelmente usando o StringIO para obter a imagem PIL), pergunto-me se não há uma maneira mais simples de fazer isso, pois parece ser um problema muito natural de visualização de imagens. Digamos, algo como isto:

colored_PIL_image = magic_function(array, cmap)
heltonbiker
fonte

Respostas:

221

Bastante ocupado, mas aqui está:

  1. Primeiro verifique se sua matriz NumPy,, myarrayé normalizada com o valor máximo em 1.0.
  2. Aplique o mapa de cores diretamente em myarray.
  3. Rescale ao 0-255alcance.
  4. Converta em números inteiros, usando np.uint8().
  5. Use Image.fromarray().

E pronto:

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

com plt.savefig():

Digite a descrição da imagem aqui

com im.save():

Digite a descrição da imagem aqui

fraxel
fonte
7
A parte "Aplique o mapa de cores diretamente a myarray" é cortada diretamente no coração! Não sabia que era possível, obrigado!
heltonbiker
34
Estudando os documentos sobre LinearSegmentedColormap (a partir do qual cm.gist_earth é uma instância), descobri que é possível chamá-lo com um argumento "bytes" que já o converte em uint8. Em seguida, o one-liner recebe um silencioso monte:im = Image.fromarray(cm.gist_earth(myarray, bytes=True))
heltonbiker
1
@CiprianTomoiaga, o formato da matriz deve ser as dimensões da imagem que você deseja. Por exemplo, uma imagem VGA seria gerada a partir de uma matriz com forma (1024.768). Você deve observar que isso se aplica a imagens monocromáticas. Isso é importante porque, geralmente, quando você converte uma imagem RGB em uma matriz, seu formato é, por exemplo, (1024.768,3), pois possui três canais.
precisa saber é o seguinte
5
Estou recebendo erroNameError: name 'cm' is not defined
rnso
10
@msofrom matplotlib import cm
Quantum7 /
10
  • input = numpy_image
  • np.unit8 -> converte em números inteiros
  • converter ('RGB') -> converte em RGB
  • Image.fromarray -> retorna um objeto de imagem

    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
fonte
5
Espero que ele resolva o problema, mas por favor, inclua uma explicação do seu código para que o usuário tenha uma compreensão perfeita do que ele / ela realmente deseja.
Jaimil Patel
1
Resposta boa e atualizada. Os anteriores são de vários anos atrás.
Catalina Chircu 23/07
7

O método descrito na resposta aceita não funcionou para mim, mesmo depois de aplicar as alterações mencionadas em seus comentários. Mas o código simples abaixo funcionou:

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

np_array pode ser uma matriz 2D com valores de 0..1 flutua o2 0..255 uint8 e, nesse caso, precisa de cmap. Para matrizes 3D, o cmap será ignorado.

Shital Shah
fonte