¿Cómo convierto una matriz numpy en (y visualizo) una imagen?

228

He creado una matriz así:

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

Lo que quiero que haga es mostrar un único punto rojo en el centro de una imagen de 512x512. (Al menos para empezar ... creo que puedo entender el resto a partir de ahí)

jlswint
fuente
1
Vea también stackoverflow.com/questions/902761/… aunque eso impuso la restricción de que PIL no podía usarse.
Peter Hansen el
¿Podría considerar cambiar la respuesta aceptada a la de Peter ? Evita la necesidad de envolver un objeto alrededor de la matriz numpy y evita escribir un archivo temporal para mostrar la imagen.
Josiah Yoder

Respuestas:

225

Puede usar PIL para crear (y mostrar) una imagen:

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
fuente
3
Parece que hay un error. Crea una matriz con tamaño (w,h,3), pero debería serlo (h,w,3), porque la indexación en PIL difiere de la indexación en numpy. Hay una pregunta relacionada: stackoverflow.com/questions/33725237/…
fdermishin
1
@ user502144: Gracias por señalar mi error. Debería haber creado una variedad de formas (h,w,3). (Ahora está fijo, arriba). La longitud del primer eje se puede considerar como el número de filas en la matriz, y la longitud del segundo eje, el número de columnas. Entonces (h, w)corresponde a una matriz de "altura" hy "ancho" w. Image.fromarrayconvierte esta matriz en una imagen de alto hy ancho w.
unutbu
1
img.show()no funciona en el cuaderno de ipython. img_pil = Image.fromarray(img, 'RGB') display(img_pil.resize((256,256), PIL.Image.LANCZOS))
mrgloom
@unutbu, este método parece distorsionar las imágenes ... stackoverflow.com/questions/62293077/…
Ludovico Verniani
285

Lo siguiente debería funcionar:

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

Si está utilizando Jupyter notebook / lab, use este comando en línea antes de importar matplotlib:

%matplotlib inline 
Steve Tjoa
fuente
3
Esto es más preciso que PIL. PIL reescala / normaliza los valores de la matriz, mientras que pyplot usa los valores RGB reales tal como son.
GaryO
21
Quizás sea bueno saberlo: si desea mostrar imágenes en escala de grises, es recomendable llamar plt.gray()una vez en su código para cambiar todos los gráficos siguientes a escala de grises. No es lo que quiere el OP, pero es bueno saberlo.
Cerno
2
¿Cómo guardarlo?
user334639
Archivo "<ipython-input-29-29c784f62838>", línea 39 plt.show () ^ SyntaxError: sintaxis no válida
Mona Jalal
1
@Cerno Además, las imágenes en escala de grises deben tener forma (h, w) en lugar de (h, w, 1). Puede usar squeeze()para eliminar la tercera dimensión:plt.imshow(data.squeeze())
Josiah Yoder
51

El camino más corto es usar scipy, así:

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

Esto requiere instalar PIL o Pillow también.

Un enfoque similar que también requiere PIL o Pillow pero que puede invocar a un espectador diferente es:

from scipy.misc import imshow
imshow(data)
Peter Hansen
fuente
Entonces, ¿este método es incompatible con Python 3.5 ...?
Christopher
@bordeo, ¿por qué sería incompatible con 3.5? Es solo una importación y un par de llamadas a funciones.
Peter Hansen
PIL es incompatible con 3.5 (no se instala)
Christopher
1
Ftr: puede acortar esto aún más directamente usando scipy.misc.imshow(data).
dtk
3
toimagefue desaprobado en scipy-1.0.0 y eliminado en 1.2.0, a favor de Pillow's Image.fromarray.
Sid
4

Usando pygame , puedes abrir una ventana, obtener la superficie como una matriz de píxeles y manipular como quieras desde allí. Sin embargo, deberá copiar su matriz numpy en la matriz de superficie, lo que será mucho más lento que realizar operaciones gráficas reales en las superficies de pygame.

Stefan Kendall
fuente
3

Cómo mostrar imágenes almacenadas en una matriz numpy con un ejemplo (funciona en el cuaderno Jupyter)

Sé que hay respuestas más simples, pero esta te dará una idea de cómo las imágenes se ahogan en una matriz numpy.

Ejemplo de carga

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

Muestra la matriz de una imagen

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

Cree subtramas vacías de 10 x 10 para visualizar 100 imágenes

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

Trazar 100 imágenes

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

Resultado:

ingrese la descripción de la imagen aquí

¿Qué axes.flathacer? Crea un enumerador numpy para que pueda iterar sobre el eje para dibujar objetos en ellos. Ejemplo:

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

Usando la matriz de almohadas, por ejemplo:

from PIL import Image
from numpy import *

im = array(Image.open('image.jpg'))
Image.fromarray(im).show()
usuario3322286
fuente
0

Suplemento para hacerlo con matplotlib. Me resultó útil hacer tareas de visión por computadora. Digamos que tienes datos con 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))
usuario140536
fuente