Come convertire un'immagine PIL in una matrice numpy?


257

Bene, sto giocando con la conversione di un oggetto immagine PIL avanti e indietro in un array intorpidito in modo da poter effettuare trasformazioni pixel per pixel più veloci di quelle PixelAccessconsentite dall'oggetto PIL . Ho capito come posizionare le informazioni sui pixel in una matrice numpy 3D utile mediante:

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

Ma non riesco a capire come caricarlo nuovamente nell'oggetto PIL dopo aver fatto tutte le mie fantastiche trasformazioni. Sono a conoscenza del putdata()metodo, ma non riesco proprio a farlo comportare.


6
Si noti che pic.size[0]e pic.size[1]deve essere scambiato (ad es. reshape(pic.size[1], pic.size[0], 3)), Poiché sizeè width x heighto x * y, mentre l'ordine della matrice è rows x columns.
nebbia il

Risposte:


287

Non stai dicendo come esattamente putdata()non si sta comportando. Suppongo che lo stai facendo

>>> 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

Questo perché si putdataaspetta una sequenza di tuple e gli stai dando un array intorpidito. Questo

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

funzionerà ma è molto lento.

A partire da PIL 1.1.6, il modo "corretto" di convertire tra immagini e array intorpiditi è semplicemente

>>> pix = numpy.array(pic)

sebbene l'array risultante sia in un formato diverso dal tuo (array 3-d o righe / colonne / rgb in questo caso).

Quindi, dopo aver apportato le modifiche all'array, dovresti essere in grado di eseguire una pic.putdata(pix)o creare una nuova immagine con Image.fromarray(pix).


2
Innanzitutto, non dovrebbe essere pic.putdata (dati)? E numpy.asarray (foto) produce un array di sola lettura, quindi devi chiamare numpy.array (immagine) e non hai risposto alla domanda ... dal link che hai fornito sembra essere pic = Image.fromarray ( pix). Risolvi la tua risposta e la accetterò.
Akdom

2
Grazie per questo ... Image.fromarraynon è elencato nella documentazione PIL (!), Quindi non l'avrei mai trovato se non fosse stato per questo.
Nathan Reed,

13
Quella pagina elenca numpy.asarray(pic)come il modo "corretto" di convertire, no numpy.array(pic). Secondo questa risposta array ne farà una copia, mentre asarraynon lo farà (ma il asarrayrisultato sarà di sola lettura).
Arthur Tacca,

1
Un avvertimento qui (dal mio errore): è necessario considerare anche la scala e gli intervalli dei dati. In molti casi d'uso renderizzeresti immagini con 0-255 byte, ma potresti aspettarti che queste vengano convertite, ad esempio, in 0,0-1,0 nell'array numpy. Alcune conversioni di unità da uint8 fanno questo, ma in questo caso non lo fa .. quindi controllalo :)
BjornW

La seconda risposta è migliore.
Nathan,

194

Apri Icome un array:

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

Fai qualcosa per I, poi, convertilo nuovamente in un'immagine:

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

Filtra immagini intorpidite con FFT, Python

Se vuoi farlo esplicitamente per qualche motivo, ci sono funzioni pil2array () e array2pil () che usano getdata () in questa pagina in correlation.zip.


2
@ArditS .: Sei stato tu per import Imageprimo? PIL è installato?
endolith

5
La uint8conversione è necessaria?
Neil Traft,

4
numpy.asarray(Image.open(filename))sembra funzionare per immagini .jpg ma non per .png. Il risultato viene visualizzato come array(<PngImagePlugin.PngImageFile image mode=LA size=500x500 at 0x3468198>, dtype=object). Sembra che non ci siano metodi chiaramente definiti PngImagePlugin.PngImageFiledell'oggetto per risolverlo. Immagino che dovrei porlo come una nuova domanda, ma è molto rilevante per questa discussione. Qualcuno capisce cosa non va qui?
jez

3
@Rebs: ecco il motivo per cui questo è molto più veloce: getdata()restituisce una sequenza come object ( pillow.readthedocs.io/en/3.4.x/reference/… ), ma un'immagine pillow implementa quella __array_interface__che numpypuò usare per accedere ai byte grezzi di un'immagine senza dover passare attraverso un iteratore (vedere github.com/python-pillow/Pillow/blob/… e docs.scipy.org/doc/numpy/reference/arrays.interface.html ). Puoi persino usarenumpy.array(PIL.Image.open('test.jpg'))
tdp2110 il

3
@jez Controlla se l'oggetto Image è chiuso prima di convertirlo in numpy. Lo stesso è successo a me e ho scoperto di aver chiuso l'oggetto immagine da qualche parte.
Shaohua Li,

65

Sto usando Pillow 4.1.1 (il successore di PIL) in Python 3.5. La conversione tra cuscino e intorpidimento è semplice.

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 che bisogna notare è che lo stile Pillow imè importante per la colonna mentre lo stile intorpidito im2arrè importante per le file. Tuttavia, la funzione lo Image.fromarraytiene già in considerazione. Cioè, arr2im.size == im.sizee arr2im.mode == im.modenell'esempio sopra.

Dovremmo occuparci del formato dei dati HxWxC durante l'elaborazione delle matrici numpy trasformate, ad es. Fare la trasformazione im2arr = np.rollaxis(im2arr, 2, 0)o im2arr = np.transpose(im2arr, (2, 0, 1))nel formato CxHxW.


2
Questo è l'esempio più pulito, comprese le dichiarazioni di importazione (grazie per quel dettaglio). Votiamo questa risposta per aumentare la visibilità.
David Parks,

Ho scoperto che quando ho convertito un'immagine disegnata PIL in un array intorpidito, quando ho usato matplotlib imshow sull'array, lo ha mostrato sottosopra richiedendo una np.flipudcorrezione. Sebbene la mia immagine PIL sia stata creata da zero utilizzando ImageDraw.Draw. Penso che bisogna stare attenti da dove viene l'origine delle loro coordinate.
CMCDragonkai

Salute!! Ho cercato questa risposta per mezza giornata. Risolve il mio problema di ripristinare l'asse originale dopo l'immagine della trama su quella originale.
Campanellino,

16

È necessario convertire l'immagine in una matrice numpy in questo modo:

import numpy
import PIL

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

Questo modo di conversione mantiene l'immagine ma provoca una perdita di colori. Ad ogni modo per evitare la perdita di colore?
Moondra,

7
@moondra Se capisco la tua domanda, puoi sostituirla .convert("L") con.convert("RGB")
Billal Begueradj,

3

L'esempio che ho usato oggi:

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

Se l'immagine è archiviata in un formato BLOB (ovvero in un database) è possibile utilizzare la stessa tecnica spiegata da Billal Begueradj per convertire l'immagine da BLOB in un array di byte.

Nel mio caso, avevo bisogno che le mie immagini fossero archiviate in una colonna BLOB in una tabella db:

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

Ho quindi creato una funzione di supporto per modificare il mio set di dati in 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

Successivamente, sono stato in grado di utilizzare i byteArrays nella mia rete neurale.

plt.imshow(imagesList[0])

0

Converti Numpy to PILimmagine ePIL 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()

È possibile trasformare l'immagine in numpy analizzando l'immagine in funzione numpy () dopo aver eliminato le funzionalità (non normalizzazione)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.