Como converter uma matriz numpy em (e exibir) uma imagem?

228

Eu criei uma matriz assim:

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

O que eu quero que isso faça é exibir um único ponto vermelho no centro de uma imagem de 512x512. (Pelo menos para começar ... acho que consigo descobrir o resto a partir daí)

jlswint
fonte
1
Consulte também stackoverflow.com/questions/902761/…, embora esse tenha imposto a restrição de que o PIL não pudesse ser usado.
Peter Hansen
Você poderia considerar alterar a resposta aceita para a de Peter ? Isso evita a necessidade de envolver um objeto em torno da matriz numpy e evita a gravação de um arquivo temporário para exibir a imagem.
Josiah Yoder

Respostas:

225

Você pode usar o PIL para criar (e exibir) uma imagem:

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
fonte
3
Parece que há um erro. Você cria uma matriz com tamanho (w,h,3), mas deve ser (h,w,3), porque a indexação no PIL difere da indexação em numpy. Existe uma pergunta relacionada: stackoverflow.com/questions/33725237/…
fdermishin
1
@ user502144: Obrigado por apontar o meu erro. Eu deveria ter criado uma matriz de formas (h,w,3). (Agora está fixo, acima.) O comprimento do primeiro eixo pode ser pensado como o número de linhas na matriz e o comprimento do segundo eixo, o número de colunas. Então (h, w)corresponde a uma matriz de "altura" he "largura" w. Image.fromarrayconverte essa matriz em uma imagem de altura he largura w.
Unutbu
1
img.show()não funciona no notebook ipython. img_pil = Image.fromarray(img, 'RGB') display(img_pil.resize((256,256), PIL.Image.LANCZOS))
mrgloom
@unutbu esse método parece distorcer imagens ... stackoverflow.com/questions/62293077/…
Ludovico Verniani
285

O seguinte deve funcionar:

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

Se você estiver usando o notebook / laboratório Jupyter, use este comando embutido antes de importar o matplotlib:

%matplotlib inline 
Steve Tjoa
fonte
3
Isso é mais preciso que o PIL. O PIL redimensiona / normaliza os valores da matriz, enquanto o pyplot usa os valores RGB reais como estão.
GaryO
21
Talvez seja bom saber: se você deseja exibir imagens em escala de cinza, é aconselhável ligar plt.gray()uma vez no código para mudar todos os gráficos a seguir para escala de cinza. Não é o que o OP quer, mas é bom saber, no entanto.
Cerno 28/02
2
Como salvá-lo?
user334639
Arquivo "<ipython-input-29-29c784f62838>", linha 39 plt.show () ^ SyntaxError: sintaxe inválida
Mona Jalal
1
@Cerno Além disso, as imagens em escala de cinza devem ter a forma (h, w) em vez de (h, w, 1). Você pode usar squeeze()para eliminar a terceira dimensão:plt.imshow(data.squeeze())
Josiah Yoder
51

O caminho mais curto é usar scipy, assim:

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

Isso requer a instalação de PIL ou Pillow.

Uma abordagem semelhante que também exige PIL ou Pillow, mas que pode chamar um visualizador diferente, é:

from scipy.misc import imshow
imshow(data)
Peter Hansen
fonte
Portanto, este método é incompatível com python 3.5 ...?
530 Christopher
@bordeo, por que seria incompatível com o 3.5? É apenas uma importação e algumas chamadas de função.
Peter Hansen
PIL é incompatível com 3,5 (não vai instalar)
Christopher
1
Ftr: você pode encurtar ainda mais isso usando diretamente scipy.misc.imshow(data).
dtk
3
toimagefoi descontinuado no scipy-1.0.0 e removido no 1.2.0, a favor do Pillow's Image.fromarray.
Sid
4

Usando pygame , você pode abrir uma janela, obter a superfície como uma matriz de pixels e manipular como quiser a partir daí. Você precisará copiar sua matriz numpy para a matriz de superfície, no entanto, o que será muito mais lento do que realizar operações gráficas reais nas próprias superfícies do pygame.

Stefan Kendall
fonte
3

Como mostrar imagens armazenadas em uma matriz numpy com exemplo (funciona no notebook Jupyter)

Eu sei que existem respostas mais simples, mas esta lhe dará uma compreensão de como as imagens são realmente afogadas de um array numpy.

Carregar exemplo

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

Exibir matriz de uma imagem

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

Crie sub-plotagens 10 x 10 vazias para visualizar 100 imagens

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

Plotar 100 imagens

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

Resultado:

insira a descrição da imagem aqui

O que axes.flatfaz? Ele cria um enumerador numpy para que você possa iterar sobre o eixo, a fim de desenhar objetos neles. Exemplo:

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

Usando o fromarray do travesseiro, por exemplo:

from PIL import Image
from numpy import *

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

Suplemento para fazê-lo com matplotlib. Achei útil fazer tarefas de visão por computador. Digamos que você tenha dados com 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
fonte