Guardar una matriz de Numpy como imagen

261

Tengo una matriz en el tipo de una matriz de Numpy. ¿Cómo lo escribiría en el disco como una imagen? Cualquier formato funciona (png, jpeg, bmp ...). Una restricción importante es que PIL no está presente.

M456
fuente
12
Solo me gustaría señalar que algunas de las respuestas a continuación, y seguramente algunas de las personas que vienen y encuentran esta pregunta, no cumplen con la restricción mencionada anteriormente de estar sin PIL . Dado que algunos de los que preguntan y algunas respuestas evitan esa restricción, animo a cualquiera que esté aquí y no le importe que PIL mire a continuación, y cualquier respuesta que no sea PIL (nueva o antigua) para mencionar que se usa PIL tipo de respuesta, para distinguirse de las respuestas que cumplen con la restricción original.
lindes

Respuestas:

54

Puedes usar PyPNG . Es un codificador / decodificador PNG de código abierto de Python puro (sin dependencias) y admite la escritura de matrices NumPy como imágenes.

dF.
fuente
44
Recuerde escalar los valores al rango correcto para PNG, generalmente 0..255. Los rangos de valores en las redes neuronales son frecuentemente 0..1 o -1..1.
Tomáš Gavenčiak
8
PyPNG es Python puro, lo que reduce sus dependencias externas, pero lo hace mucho más lento que PIL y sus clases derivadas. Por ejemplo, guardar una imagen de 3000x4000 en mi máquina tomó 4.05 segundos con PyPNG pero solo 0.59 segundos con scipy.misc.imsave (6 veces más rápido).
Zvika
@ TomášGavenčiak - scipy.misc.imsave ahora está en desuso en las versiones más recientes de Scipy. Una alternativa de algunos comentarios a continuación es usar imageio.imwrite ('image_file.jpg', array)
Psi-Ed
259

Esto usa PIL, pero tal vez algunos puedan encontrarlo útil:

import scipy.misc
scipy.misc.imsave('outfile.jpg', image_array)

EDITAR : La scipyversión actual comenzó a normalizar todas las imágenes para que min (datos) se vuelva negro y max (datos) se vuelva blanco. Esto no es deseado si los datos deben ser niveles de grises exactos o canales RGB exactos. La solución:

import scipy.misc
scipy.misc.toimage(image_array, cmin=0.0, cmax=...).save('outfile.jpg')
Steve Tjoa
fuente
19
imsave vive en ... / scipy / misc / pilutil.py que usa PIL
denis
55
Tenga cuidado al convertir a jpg, ya que es con pérdidas y, por lo tanto, es posible que no pueda recuperar los datos exactos utilizados para generar la imagen.
Feanil
8
Esto ahora está en desuso en scipy 0.19 use - scipy.io.imwrite
g.stevo
66
"imsave está en desuso en SciPy 1.0.0, y se eliminará en 1.2.0" ( Scipy 1.1.0 doc )
noobar
15
scipy.misc.imsave está en desuso. usar import imageio; imageio.imwrite ('file_name.jpg', nmupy_array)
ChaosPredictor
228

Una respuesta usando PIL (por si acaso es útil).

dado una matriz numpy "A":

from PIL import Image
im = Image.fromarray(A)
im.save("your_file.jpeg")

puede reemplazar "jpeg" con casi cualquier formato que desee. Más detalles sobre los formatos aquí

Migas
fuente
55
La imagen es un módulo de PIL. Hacer "imprimir imagen .__ archivo__"
Juh_
10
Muy útil para aquellos de nosotros que deambulamos aquí y tenemos PIL - Creo que lo usaré from PIL import Imagepara mantenerlo claro ...
sabio
44
Si tiene una imagen RGB, puede obtener la imagen usando im = Image.fromarray (A) .convert ('RGB') Más información: stackoverflow.com/questions/4711880/…
Roger Veciana
El uso del tercer eje de una matriz de uint8 para codificar RGB funciona con este método. El módulo PIL se puede instalar usando "almohada de instalación de pip".
bli
1
@Ludovico Verniani No distorsiona las imágenes, pero sí utiliza una codificación de color poco común en la que el orden de los colores es BGR en lugar de RGB.
Zvika
88

Con matplotlib:

import matplotlib

matplotlib.image.imsave('name.png', array)

Funciona con matplotlib 1.3.1, no sé sobre la versión inferior. Desde la cadena de documentación:

Arguments:
  *fname*:
    A string containing a path to a filename, or a Python file-like object.
    If *format* is *None* and *fname* is a string, the output
    format is deduced from the extension of the filename.
  *arr*:
    An MxN (luminance), MxNx3 (RGB) or MxNx4 (RGBA) array.

ingrese la descripción de la imagen aquí

christianbrodbeck
fuente
Usando esto. Pero sufriendo de pérdida de memoria
SolessChong
matplotlib.imsave () en versiones más recientes
Vinay Lodha
66
Está matplotlib.pyplot.imsaveen matplotlib 2+
Aleksei Petrenko
1
@HughPerkins prueba Pillow como reemplazo de PIL en Python 3
christianbrodbeck
10
import matplotlib.pyplot as plty luegoplt.imsave('name.png', array)
Alessandro Jacopson
62

Python puro (2 y 3), un fragmento sin dependencias de terceros.

Esta función escribe RGBAPNG comprimidos de color verdadero (4 bytes por píxel) .

def write_png(buf, width, height):
    """ buf: must be bytes or a bytearray in Python3.x,
        a regular string in Python2.x.
    """
    import zlib, struct

    # reverse the vertical line order and add null bytes at the start
    width_byte_4 = width * 4
    raw_data = b''.join(
        b'\x00' + buf[span:span + width_byte_4]
        for span in range((height - 1) * width_byte_4, -1, - width_byte_4)
    )

    def png_pack(png_tag, data):
        chunk_head = png_tag + data
        return (struct.pack("!I", len(data)) +
                chunk_head +
                struct.pack("!I", 0xFFFFFFFF & zlib.crc32(chunk_head)))

    return b''.join([
        b'\x89PNG\r\n\x1a\n',
        png_pack(b'IHDR', struct.pack("!2I5B", width, height, 8, 6, 0, 0, 0)),
        png_pack(b'IDAT', zlib.compress(raw_data, 9)),
        png_pack(b'IEND', b'')])

... Los datos deben escribirse directamente en un archivo abierto como binario, como en:

data = write_png(buf, 64, 64)
with open("my_image.png", 'wb') as fh:
    fh.write(data)

ideasman42
fuente
2
Esto parece ser exactamente lo que estoy buscando, pero ¿podría agregar algunos comentarios? No veo cómo esto escribe en un archivo. ¿Tiene que escribir la salida en un archivo abierto previamente? ¡Gracias!
PhilMacKay
1
@PhilMacKay, los datos solo tienen que escribirse en un archivo binario. comentario agregado
ideasman42
1
¿Alguien puede especificar en qué formato bufse supone que debe estar la imagen ( )? No parece ser una matriz numpy ...
christianbrodbeck
1
@christianmbrodbeck, un bytearray (RGBARGBA ...)
ideasman42
1
Gracias @ ideasman42. Porté este código para usarlo en Blender .
emackey
57

Hay opencvpara python ( documentación aquí ).

import cv2
import numpy as np

cv2.imwrite("filename.png", np.zeros((10,10)))

útil si necesita hacer más procesamiento que no sea guardar.

Xocoatzin
fuente
1
¿Por qué matriz de tamaño 10? ¿Qué llevó a la elección de 10 utilizados en esta solución?
Gathide
3
@Gathide Solo como un ejemplo de escritura de una matriz numpy arbitraria en un archivo. En la vida real, reemplace np.zeros((10,10))con su imagen.
Xocoatzin
55
¿Cómo puedo agregar algo como cmap="gray"cuando guardo la imagen usando cv2?
Mona Jalal
@Xocoatzin ¿Enlace roto?
jtlz2
1
@ jtlz2 Enlace actualizado.
Xocoatzin
30

Si tiene matplotlib, puede hacer:

import matplotlib.pyplot as plt
plt.imshow(matrix) #Needs to be in row,col order
plt.savefig(filename)

Esto guardará la trama (no las imágenes en sí). ingrese la descripción de la imagen aquí

Desplazamiento Doppler
fuente
10
No, para la interfaz de pyplot, plt.figure () es superfluo. Además, solo necesita plt.show () si también desea ver una ventana de figura, en este caso solo se deseaba guardar un archivo de imagen, por lo que no era necesario llamar a show ().
DopplerShift
77
Tenga en cuenta que el archivo de imagen resultante contendrá los ejes y el área gris de la figura matlplotlib, no solo los datos de píxeles.
Dave
1
no funcionará si ejecuta su secuencia de comandos en un host remoto, si lo hace sin soporte de interfaz gráfica.
Temak
Si desea mostrar la imagen en un cuaderno, puede agregar lo siguiente: >> "desde IPython.display import Image" y luego >> "Image (filename = filename)"
Robert
Para quitar el eje:plt.axis('off')
yakout
15

Puedes usar la biblioteca 'skimage' en Python

Ejemplo:

from skimage.io import imsave
imsave('Path_to_your_folder/File_name.jpg',your_array)
PURNENDU MISHRA
fuente
15

scipy.miscda advertencia de desaprobación sobre la imsavefunción y sugiere el uso de en su imageiolugar.

import imageio
imageio.imwrite('image_name.png', img)
Sefa
fuente
12

Anexo a la respuesta de @ ideasman42:

def saveAsPNG(array, filename):
    import struct
    if any([len(row) != len(array[0]) for row in array]):
        raise ValueError, "Array should have elements of equal size"

                                #First row becomes top row of image.
    flat = []; map(flat.extend, reversed(array))
                                 #Big-endian, unsigned 32-byte integer.
    buf = b''.join([struct.pack('>I', ((0xffFFff & i32)<<8)|(i32>>24) )
                    for i32 in flat])   #Rotate from ARGB to RGBA.

    data = write_png(buf, len(array[0]), len(array))
    f = open(filename, 'wb')
    f.write(data)
    f.close()

Entonces puedes hacer:

saveAsPNG([[0xffFF0000, 0xffFFFF00],
           [0xff00aa77, 0xff333333]], 'test_grid.png')

Produciendo test_grid.png:

Rejilla de rojo, amarillo, aguamarina oscura, gris

(La transparencia también funciona al reducir el byte alto de 0xff).

Evgeni Sergeev
fuente
8

Para aquellos que buscan un ejemplo directo y totalmente funcional:

from PIL import Image
import numpy

w,h = 200,100
img = numpy.zeros((h,w,3),dtype=numpy.uint8) # has to be unsigned bytes

img[:] = (0,0,255) # fill blue

x,y = 40,20
img[y:y+30, x:x+50] = (255,0,0) # 50x30 red box

Image.fromarray(img).convert("RGB").save("art.png") # don't need to convert

Además, si quieres archivos JPEG de alta calidad
.save(file, subsampling=0, quality=100)

Charco
fuente
6

matplotlib svn tiene una nueva función para guardar imágenes como solo una imagen: sin ejes, etc. También es una función muy simple para hacer backport, si no desea instalar svn (copiado directamente de image.py en matplotlib svn, eliminó el docstring por brevedad):

def imsave(fname, arr, vmin=None, vmax=None, cmap=None, format=None, origin=None):
    from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
    from matplotlib.figure import Figure

    fig = Figure(figsize=arr.shape[::-1], dpi=1, frameon=False)
    canvas = FigureCanvas(fig)
    fig.figimage(arr, cmap=cmap, vmin=vmin, vmax=vmax, origin=origin)
    fig.savefig(fname, dpi=1, format=format)
Autoplectic
fuente
3

El mundo probablemente no necesita otro paquete para escribir una matriz numpy en un archivo PNG, pero para aquellos que no pueden obtener suficiente, recientemente puse numpngwen github:

https://github.com/WarrenWeckesser/numpngw

y en pypi: https://pypi.python.org/pypi/numpngw/

La única dependencia externa es numpy.

Aquí está el primer ejemplo del examplesdirectorio del repositorio. La línea esencial es simplemente

write_png('example1.png', img)

donde imghay una matriz numpy Todo el código antes de esa línea es declaraciones de importación y código para crear img.

import numpy as np
from numpngw import write_png


# Example 1
#
# Create an 8-bit RGB image.

img = np.zeros((80, 128, 3), dtype=np.uint8)

grad = np.linspace(0, 255, img.shape[1])

img[:16, :, :] = 127
img[16:32, :, 0] = grad
img[32:48, :, 1] = grad[::-1]
img[48:64, :, 2] = grad
img[64:, :, :] = 127

write_png('example1.png', img)

Aquí está el archivo PNG que crea:

ejemplo1.png

Warren Weckesser
fuente
Tengo curiosidad, ¿en qué se diferencia su lib de las demás? ¿Es más rápido? ¿Tiene características elegantes?
F Lekschas
Algunas características: (1) Utiliza matrices numpy. (2) Está escrito usando solo python y numpy, por lo que no requiere la instalación de una biblioteca C. (3) Puede crear archivos PNG animados. (4) Proporciona una clase para escribir animaciones matplotlib como archivos PNG animados.
Warren Weckesser
¡Gracias! Me gustaría saber cómo se compara con stackoverflow.com/a/19174800/981933 en términos de rendimiento, que también es puro Python. El primer método es superior a 2 veces más rápido que PIL, lo cual es bastante impresionante. No importa si ese no es tu objetivo :)
F Lekschas
2

Suponiendo que desea una imagen en escala de grises:

im = Image.new('L', (width, height))
im.putdata(an_array.flatten().tolist())
im.save("image.tiff")
Guillaume Lebreton
fuente
2

Imageio es una biblioteca de Python que proporciona una interfaz fácil para leer y escribir una amplia gama de datos de imágenes, incluidas imágenes animadas, videos, datos volumétricos y formatos científicos. Es multiplataforma, se ejecuta en Python 2.7 y 3.4+, y es fácil de instalar.

Este es un ejemplo de imagen en escala de grises:

import numpy as np
import imageio

# data is numpy array with grayscale value for each pixel.
data = np.array([70,80,82,72,58,58,60,63,54,58,60,48,89,115,121,119])

# 16 pixels can be converted into square of 4x4 or 2x8 or 8x2
data = data.reshape((4, 4)).astype('uint8')

# save image
imageio.imwrite('pic.jpg', data)
Denis Rasulev
fuente
1

Si ya usa [Py] Qt, puede estar interesado en qimage2ndarray . A partir de la versión 1.4 (recién lanzada), PySide también es compatible, y habrá una pequeña imsave(filename, array)función similar a scipy's, pero usando Qt en lugar de PIL. Con 1.3, solo usa algo como lo siguiente:

qImage = array2qimage(image, normalize = False) # create QImage from ndarray
success = qImage.save(filename) # use Qt's image IO functions for saving PNG/JPG/..

(Otra ventaja de 1.4 es que es una solución pura de Python, lo que lo hace aún más liviano).

hans_meine
fuente
La versión 1.4 ya está disponible. :-) (Edité la respuesta en consecuencia.)
hans_meine
1

Si está trabajando en el entorno de Python Spyder, entonces no puede ser más fácil que simplemente hacer clic derecho en la matriz en el explorador de variables y luego elegir la opción Mostrar imagen.

ingrese la descripción de la imagen aquí

Esto le pedirá que guarde la imagen en dsik, principalmente en formato PNG.

La biblioteca PIL no será necesaria en este caso.

abunickabhi
fuente
1

Uso cv2.imwrite.

import cv2
assert mat.shape[2] == 1 or mat.shape[2] == 3, 'the third dim should be channel'
cv2.imwrite(path, mat) # note the form of data should be height - width - channel  
Christy Lee
fuente
1

para guardar una matriz numpy como imagen, U tiene varias opciones:

1) lo mejor de otro: OpenCV

 import cv2   
 cv2.imwrite('file name with extension(like .jpg)', numpy_array)

2) Matplotlib

  from matplotlib import pyplot as plt
  plt.imsave('file name with extension(like .jpg)', numpy_array)

3) PIL

  from PIL import Image
  image = Image.fromarray(numpy_array)
  image.save('file name with extension(like .jpg)')

4) ...

nima farhadi
fuente