HOWTO · NumPy

Guardar array NumPy como imagen en Python

Este tutorial demuestra cómo guardar un array numpy como imagen en Python

En esta página

Puedes escribir un array de NumPy en un archivo de imagen con Pillow, imageio, Matplotlib u OpenCV. La opción adecuada depende de la biblioteca que ya use tu proyecto y de cómo estén organizados los datos de píxeles del array. Un array bidimensional suele representar píxeles en escala de grises; uno tridimensional suele representar los canales de color con las dimensiones alto × ancho × canales. Los datos RGB tienen tres canales en la última dimensión, mientras que RGBA añade un canal alfa.

Para las imágenes habituales de 8 bits, los valores de numpy.uint8 entre 0 y 255 son un punto de partida práctico. Cada biblioteca puede interpretar o reescalar de forma distinta un array de punto flotante, así que comprueba el rango que espera el escritor antes de guardar. Los ejemplos ejecutables que aparecen a continuación usan arrays pequeños y rutas temporales para archivos PNG. Si aún no están disponibles, instala NumPy y la biblioteca que use el ejemplo (por ejemplo, para Pillow, ejecuta python -m pip install numpy pillow).

Preparar un array de NumPy para guardarlo como imagen

Elige una forma de array que coincida con los datos de imagen: (height, width) para escala de grises, (height, width, 3) para RGB o (height, width, 4) para RGBA cuando el escritor espera que los canales estén al final. La forma describe la disposición de los datos, pero no indica qué significa cada canal. Comprueba si los datos de origen están en RGB o BGR antes de pasar los píxeles de color a una biblioteca.

Usa un tipo de dato y un rango numérico compatibles tanto con el formato de imagen como con el escritor elegido. Para la salida habitual de 8 bits, numpy.uint8 con valores entre 0 y 255 es ampliamente compatible. Si los valores de origen son de punto flotante o usan otro rango, conviértelos o escálalos de forma deliberada; los escritores pueden recortar, reescalar o rechazar esos valores de distintas maneras.

Usar la función Image.fromarray() para guardar un array de NumPy como imagen

Image.fromarray() de Pillow crea una imagen a partir de un array, y Image.save() la escribe en un archivo. Un array bidimensional de uint8 representa datos en escala de grises. Para obtener color, proporciona un array adecuado de tres canales en orden RGB. Este ejemplo guarda un pequeño array en escala de grises como gray.png:

from pathlib import Path
from tempfile import TemporaryDirectory

import numpy as np
from PIL import Image

pixels = np.array([[0, 64, 128], [192, 224, 255]], dtype=np.uint8)
with TemporaryDirectory() as directory:
    output_path = Path(directory) / "gray.png"
    image = Image.fromarray(pixels)
    image.save(output_path)
    print("Saved gray.png")
Saved gray.png

El directorio temporal permite ejecutar el ejemplo de forma autónoma. Para un ejemplo en color, puedes usar un array con forma (height, width, 3) y canales en orden RGB; Pillow puede inferir el modo RGB a partir de un array adecuado de tres canales.

Usar la función imageio.imwrite() para guardar un array de NumPy como imagen

imageio.imwrite() escribe un array en la ruta que recibe como primer argumento. Por lo general, la extensión del nombre de archivo selecciona el escritor; usa una extensión compatible con los complementos de imageio instalados. Este ejemplo autónomo crea su propio array en escala de grises y mantiene la ruta de salida dentro del directorio temporal durante toda la escritura. Los resultados de ejecución suministrados no cubren este ejemplo con imageio; para ejecutarlo en tu entorno, instala NumPy y imageio (por ejemplo, con python -m pip install numpy imageio).

from pathlib import Path
from tempfile import TemporaryDirectory

import numpy as np

pixels = np.array([[0, 64, 128], [192, 224, 255]], dtype=np.uint8)
try:
    import imageio.v2 as imageio
except ImportError:
    print("imageio is unavailable; install imageio to write the image.")
else:
    with TemporaryDirectory() as directory:
        output_path = Path(directory) / "gray.png"
        imageio.imwrite(output_path, pixels)
        print("Saved gray.png")

Para esta tarea, usa una biblioteca de escritura de imágenes como imageio. El ejemplo histórico de scipy.io.imsave() no se presenta como una recomendación actual; este artículo no se basa en afirmaciones históricas ni de obsolescencia sobre las API de SciPy.

Usar la función matplotlib.pyplot.imsave() para guardar un array de NumPy como imagen

Matplotlib escribe arrays directamente con matplotlib.pyplot.imsave(). Para un array 2D, pasa cmap="gray" para solicitar una salida en escala de grises. Sin un mapa de color explícito, Matplotlib puede asignar colores a los valores escalares. La entrada de tres canales se interpreta como RGB. Este ejemplo guarda valores en escala de grises con un mapa de color gris explícito:

from pathlib import Path
from tempfile import TemporaryDirectory

import matplotlib.pyplot as plt
import numpy as np

pixels = np.array([[0, 64, 128], [192, 224, 255]], dtype=np.uint8)
with TemporaryDirectory() as directory:
    output_path = Path(directory) / "gray.png"
    plt.imsave(output_path, pixels, cmap="gray")
    print("Saved gray.png")
Saved gray.png

Si el rango numérico de los datos escalares tiene significado, elige deliberadamente la normalización y el mapa de color. Así se mantiene diferenciada la asignación de colores para la visualización de los canales de píxeles originales.

Usar la función cv2.imwrite() para guardar un array de NumPy como imagen

OpenCV elige el codificador según la extensión del nombre de archivo y cv2.imwrite() devuelve un valor booleano que indica si la escritura se realizó correctamente. Comprueba ese valor, sobre todo si el directorio de salida o el códec podrían no estar disponibles. Por convención, OpenCV usa el orden de canales BGR para los arrays de color. Convierte los datos RGB antes de escribirlos si quieres que los colores guardados coincidan con los de origen. Un array 2D en escala de grises no necesita conversión del orden de canales. El ejemplo crea una ruta de salida válida durante la escritura y gestiona tanto un valor de retorno falso como la falta de una instalación de OpenCV, mostrando un mensaje útil. Los resultados de ejecución suministrados no cubren este ejemplo con OpenCV; para ejecutarlo en tu entorno, instala NumPy y opencv-python (por ejemplo, con python -m pip install numpy opencv-python).

from pathlib import Path
from tempfile import TemporaryDirectory

import numpy as np

pixels = np.array([[0, 64, 128], [192, 224, 255]], dtype=np.uint8)
try:
    import cv2
except ImportError:
    print("OpenCV is unavailable; install opencv-python to write the image.")
else:
    with TemporaryDirectory() as directory:
        output_path = Path(directory) / "gray.png"
        written = cv2.imwrite(str(output_path), pixels)
        if written:
            print("Saved gray.png")
        else:
            print(f"Could not write {output_path}; check the directory and image encoder.")

Para una entrada de color RGB, conviértela con cv2.cvtColor(rgb, cv2.COLOR_RGB2BGR) antes de llamar a cv2.imwrite(). Mantén la conversión y la disposición del array coherentes con los datos de origen.

Elegir un formato de salida y verificar la imagen

Por lo general, la extensión del nombre de archivo determina o indica el formato de salida, pero los formatos y las opciones disponibles varían según la biblioteca y los complementos instalados. PNG no tiene pérdidas; JPEG usa compresión con pérdidas y no conserva la transparencia. Confirma que el escritor seleccionado admita la extensión que elijas.

Comprueba el valor de retorno cuando la API lo proporcione, como hace OpenCV. Si necesitas confirmar el resultado, vuelve a abrir el archivo guardado e inspecciona sus dimensiones, modo o número de canales y valores de píxeles. Los colores inesperados pueden indicar un orden de canales RGB/BGR incorrecto, mientras que una salida en color a partir de datos en escala de grises puede indicar que Matplotlib aplicó un mapa de color. Si el resultado no es el esperado, compara la forma, el tipo de dato, el rango y el orden de canales del array con lo que espera el escritor.