¿Cómo convertir una imagen PIL en una matriz numpy?


257

Muy bien, estoy jugando con la conversión de un objeto de imagen PIL de ida y vuelta a una matriz numpy para poder hacer algunas transformaciones de píxel a píxel más rápidas de PixelAccesslo que permitiría el objeto de PIL . He descubierto cómo colocar la información de píxeles en una útil matriz numpy 3D mediante:

pic = Image.open("foo.jpg")
pix = numpy.array(pic.getdata()).reshape(pic.size[0], pic.size[1], 3)

Pero parece que no puedo entender cómo cargarlo de nuevo en el objeto PIL después de haber realizado todas mis transformaciones increíbles. Soy consciente del putdata()método, pero parece que no puedo lograr que se comporte.


66
Tenga en cuenta que pic.size[0]y pic.size[1]debe intercambiarse (es decir reshape(pic.size[1], pic.size[0], 3)), ya que sizees width x heighto x * y, mientras que el ordenamiento matricial es rows x columns.
Foges

Respuestas:


287

No estás diciendo cómo exactamente putdata()no se está comportando. Supongo que lo estás haciendo

>>> pic.putdata(a)
Traceback (most recent call last):
  File "...blablabla.../PIL/Image.py", line 1185, in putdata
    self.im.putdata(data, scale, offset)
SystemError: new style getargs format but argument is not a tuple

Esto se debe a que putdataespera una secuencia de tuplas y le está dando una matriz numpy. Esta

>>> data = list(tuple(pixel) for pixel in pix)
>>> pic.putdata(data)

funcionará pero es muy lento.

A partir de PIL 1.1.6, la forma "adecuada" de convertir entre imágenes y matrices numpy es simplemente

>>> pix = numpy.array(pic)

aunque la matriz resultante tiene un formato diferente al tuyo (matriz 3-d o filas / columnas / rgb en este caso).

Luego, después de realizar los cambios en la matriz, debería poder hacer pic.putdata(pix)o crear una nueva imagen con Image.fromarray(pix).


2
Primero, ¿no debería ser pic.putdata (datos)? Y numpy.asarray (pic) produce una matriz de solo lectura, por lo que debe llamar a numpy.array (pic), y no respondió la pregunta ... desde el enlace que proporcionó parece ser pic = Image.fromarray ( pix). Arregla tu respuesta y la aceptaré.
akdom

2
Gracias por esto ... Image.fromarrayno aparece en la documentación de PIL (!) Así que nunca lo habría encontrado si no fuera por esto.
Nathan Reed

13
Esa página aparece numpy.asarray(pic)como la forma "adecuada" de convertir, no numpy.array(pic). Según esta respuesta array , hará una copia mientras asarrayque no lo hará (pero luego el asarrayresultado será de solo lectura).
Arthur Tacca

1
Una advertencia aquí (de mi propio error): también debe considerar la escala y los rangos de los datos. En muchos casos de uso, representaría imágenes con 0-255 bytes, pero puede esperar que se conviertan a, por ejemplo, 0.0-1.0 en la matriz numpy. Algunas conversiones de unidades de uint8 hacen esto, pero en este caso, no lo hace ... así que
verifíquelo

La segunda respuesta es mejor.
Nathan

194

Abrir Icomo una matriz:

>>> I = numpy.asarray(PIL.Image.open('test.jpg'))

Haga algunas cosas para Iluego convertirlo nuevamente a una imagen:

>>> im = PIL.Image.fromarray(numpy.uint8(I))

Filtra imágenes numpy con FFT, Python

Si desea hacerlo explícitamente por alguna razón, hay funciones pil2array () y array2pil () que usan getdata () en esta página en correlation.zip.


2
@ArditS .: ¿Lo hiciste import Imageprimero? ¿Tienes PIL instalado?
endolito el

55
¿Es uint8necesaria la conversión?
Neil Traft

44
numpy.asarray(Image.open(filename))parece funcionar para imágenes .jpg pero no para .png. El resultado se muestra como array(<PngImagePlugin.PngImageFile image mode=LA size=500x500 at 0x3468198>, dtype=object). Parece que no hay métodos obviamente nombrados del PngImagePlugin.PngImageFileobjeto para resolver esto. Supongo que debería hacer esto como una nueva pregunta, pero es muy relevante para este hilo. ¿Alguien entiende lo que está pasando aquí?
jez

3
@Rebs: esta es la razón por la que esto es mucho más rápido: getdata()devuelve una secuencia como objeto ( pillow.readthedocs.io/en/3.4.x/reference/… ), pero una imagen de almohada implementa la __array_interface__que numpypuede usar para acceder a los bytes sin procesar de una imagen sin tener que pasar por un iterador (consulte github.com/python-pillow/Pillow/blob/… y docs.scipy.org/doc/numpy/reference/arrays.interface.html ). Incluso puedes usarnumpy.array(PIL.Image.open('test.jpg'))
tdp2110

3
@jez Compruebe si el objeto Imagen está cerrado antes de convertirlo a numpy. Lo mismo me sucedió y descubrí que cerré el objeto de la imagen en alguna parte.
Shaohua Li

65

Estoy usando Pillow 4.1.1 (el sucesor de PIL) en Python 3.5. La conversión entre Pillow y numpy es sencilla.

from PIL import Image
import numpy as np
im = Image.open('1.jpg')
im2arr = np.array(im) # im2arr.shape: height x width x channel
arr2im = Image.fromarray(im2arr)

Una cosa que debe imtenerse en cuenta es que el estilo Pillow es de columna principal mientras que el estilo numpy im2arres de fila mayor. Sin embargo, la función Image.fromarrayya tiene esto en cuenta. Es decir, arr2im.size == im.sizey arr2im.mode == im.modeen el ejemplo anterior.

Deberíamos ocuparnos del formato de datos HxWxC al procesar las matrices numpy transformadas, por ejemplo, hacer la transformación im2arr = np.rollaxis(im2arr, 2, 0)o im2arr = np.transpose(im2arr, (2, 0, 1))en formato CxHxW.


2
Este es el ejemplo más claro, incluidas las declaraciones de importación (gracias por ese detalle). Vamos a votar esta respuesta para aumentar la visibilidad.
David Parks

Descubrí que cuando convertía una imagen dibujada PIL en una matriz numpy, cuando usaba matplotlib imshow en la matriz, la mostraba al revés y requería una np.flipudreparación. Aunque mi imagen PIL fue creada desde cero usando ImageDraw.Draw. Creo que hay que tener cuidado de dónde viene el origen de sus coordenadas.
CMCDragonkai

¡¡Salud!! He estado buscando esta respuesta durante medio día. Resuelve mi problema de restaurar el eje original después de la imagen de la trama al original.
Tinkerbell

16

Necesita convertir su imagen en una matriz numpy de esta manera:

import numpy
import PIL

img = PIL.Image.open("foo.jpg").convert("L")
imgarr = numpy.array(img) 

Esta forma de conversión retiene la imagen pero da como resultado una pérdida de colores. De todos modos para evitar la pérdida de color?
Moondra

77
@moondra Si entiendo tu pregunta, puedes reemplazarla .convert("L") por.convert("RGB")
Billal Begueradj el

3

El ejemplo que he usado hoy:

import PIL
import numpy
from PIL import Image

def resize_image(numpy_array_image, new_height):
    # convert nympy array image to PIL.Image
    image = Image.fromarray(numpy.uint8(numpy_array_image))
    old_width = float(image.size[0])
    old_height = float(image.size[1])
    ratio = float( new_height / old_height)
    new_width = int(old_width * ratio)
    image = image.resize((new_width, new_height), PIL.Image.ANTIALIAS)
    # convert PIL.Image into nympy array back again
    return array(image)

0

Si su imagen se almacena en un formato Blob (es decir, en una base de datos), puede usar la misma técnica explicada por Billal Begueradj para convertir su imagen de Blobs en una matriz de bytes.

En mi caso, necesitaba mis imágenes almacenadas en una columna de blob en una tabla db:

def select_all_X_values(conn):
    cur = conn.cursor()
    cur.execute("SELECT ImageData from PiecesTable")    
    rows = cur.fetchall()    
    return rows

Luego creé una función auxiliar para cambiar mi conjunto de datos a np.array:

X_dataset = select_all_X_values(conn)
imagesList = convertToByteIO(np.array(X_dataset))

def convertToByteIO(imagesArray):
    """
    # Converts an array of images into an array of Bytes
    """
    imagesList = []

    for i in range(len(imagesArray)):  
        img = Image.open(BytesIO(imagesArray[i])).convert("RGB")
        imagesList.insert(i, np.array(img))

    return imagesList

Después de esto, pude usar byteArrays en mi red neuronal.

plt.imshow(imagesList[0])

0

Convertir Numpy to PILimagen yPIL to Numpy

import numpy as np
from PIL import Image

def pilToNumpy(img):
    return np.array(img)

def NumpyToPil(img):
    return Image.fromarray(img)

-1
def imshow(img):
    img = img / 2 + 0.5     # unnormalize
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()

Puede transformar la imagen en numpy analizando la imagen en función numpy () después de eliminar las características (sin normalización)

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.