Comment convertir une image PIL en un tableau numpy?

257

D'accord, je joue avec la conversion d'un objet image PIL d'avant en arrière en un tableau numpy afin que je puisse faire des transformations pixel par pixel plus rapidement que l' PixelAccessobjet PIL ne le permettrait. J'ai compris comment placer les informations sur les pixels dans un tableau numpy 3D utile au moyen de:

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

Mais je n'arrive pas à comprendre comment le recharger dans l'objet PIL après avoir fait toutes mes transformations impressionnantes. Je connais la putdata()méthode, mais je n'arrive pas vraiment à la faire se comporter.

akdom
la source
6
Notez que pic.size[0]et pic.size[1]doivent être échangés (c.-à-d. reshape(pic.size[1], pic.size[0], 3)), Puisque sizeest width x heightou x * y, tandis que l'ordre matriciel est rows x columns.
foges

Réponses:

287

Vous ne dites pas comment putdata()ne se comporte pas exactement . Je suppose que tu fais

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

En effet, putdataattend une séquence de tuples et vous lui donnez un tableau numpy. Ce

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

fonctionnera mais il est très lent.

Depuis PIL 1.1.6, la manière "correcte" de convertir entre les images et les tableaux numpy est simplement

>>> pix = numpy.array(pic)

bien que le tableau résultant soit dans un format différent du vôtre (tableau 3D ou lignes / colonnes / RVB dans ce cas).

Ensuite, après avoir apporté vos modifications au tableau, vous devriez pouvoir faire l'une pic.putdata(pix)ou l' autre ou créer une nouvelle image avec Image.fromarray(pix).

dF.
la source
2
Tout d'abord, ne devrait-il pas s'agir de pic.putdata (données)? Et numpy.asarray (pic) produit un tableau en lecture seule, vous devez donc appeler numpy.array (pic), et vous n'avez pas répondu à la question ... à partir du lien que vous avez fourni, il semble être pic = Image.fromarray ( pix). Fixez votre réponse et je l'accepterai.
akdom
2
Merci pour cela ... Image.fromarrayn'est pas répertorié dans la documentation PIL (!) Donc je ne l'aurais jamais trouvé s'il n'y avait pas eu cela.
Nathan Reed
13
Cette page numpy.asarray(pic)n'est pas la bonne façon de convertir numpy.array(pic). Selon cette réponse array , une copie asarraysera effectuée, mais pas (mais le asarrayrésultat sera en lecture seule).
Arthur Tacca
1
Un avertissement ici (de ma propre erreur): vous devez également prendre en compte l'échelle et les plages de données. Dans de nombreux cas d'utilisation, vous rendriez des images avec 0 à 255 octets, mais vous pourriez vous attendre à ce qu'elles soient converties par exemple en 0,0-1,0 dans le tableau numpy. Certaines conversions d'unités de uint8 le font, mais dans ce cas, ce n'est pas le cas. Vérifiez donc :)
BjornW
La deuxième réponse est meilleure.
Nathan
194

Ouvrir en Itant que tableau:

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

Faites quelques trucs pour Iensuite le reconvertir en image:

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

Filtrer les images numpy avec FFT, Python

Si vous voulez le faire explicitement pour une raison quelconque, il existe des fonctions pil2array () et array2pil () utilisant getdata () sur cette page dans correlation.zip.

endolith
la source
2
@ArditS .: L'avez-vous d' import Imageabord fait? Avez-vous installé PIL?
endolith
5
La uint8conversion est-elle nécessaire?
Neil Traft
4
numpy.asarray(Image.open(filename))semble fonctionner pour les images .jpg mais pas pour .png. Le résultat s'affiche sous la forme array(<PngImagePlugin.PngImageFile image mode=LA size=500x500 at 0x3468198>, dtype=object). Il ne semble pas y avoir de méthode nommée de manière évidente PngImagePlugin.PngImageFilepour résoudre ce problème. Je suppose que je devrais poser cette question comme une nouvelle question, mais elle est très pertinente pour ce fil. Quelqu'un comprend-il ce qui ne va pas ici?
2015
3
@Rebs: voici la raison pour laquelle cela est tellement plus rapide: getdata()retourne une séquence comme un objet ( pillow.readthedocs.io/en/3.4.x/reference/… ), mais une image d'oreiller implémente celle __array_interface__qui numpypeut être utilisée pour accéder aux octets bruts d'une image sans avoir à passer par un itérateur (voir github.com/python-pillow/Pillow/blob/… et docs.scipy.org/doc/numpy/reference/arrays.interface.html ). Vous pouvez même simplement utilisernumpy.array(PIL.Image.open('test.jpg'))
tdp2110
3
@jez Vérifiez si l'objet Image est fermé avant de le convertir en numpy. La même chose m'est arrivée et j'ai trouvé que j'avais fermé l'objet image quelque part.
Shaohua Li
65

J'utilise Pillow 4.1.1 (le successeur de PIL) dans Python 3.5. La conversion entre Pillow et numpy est simple.

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)

Une chose qui doit être notée est que le style oreiller imest majeur sur colonne tandis que le style numpy im2arrest majeur sur ligne. Cependant, la fonction Image.fromarrayprend déjà cela en considération. C'est-à-dire, arr2im.size == im.sizeet arr2im.mode == im.modedans l'exemple ci-dessus.

Nous devons prendre soin du format de données HxWxC lors du traitement des tableaux numpy transformés, par exemple faire la transformation im2arr = np.rollaxis(im2arr, 2, 0)ou im2arr = np.transpose(im2arr, (2, 0, 1))au format CxHxW.

Daniel
la source
2
Il s'agit de l'exemple le plus propre, y compris les instructions d'importation (merci pour ce détail). Votons cette réponse pour augmenter la visibilité.
David Parks
J'ai constaté que lorsque j'ai converti une image dessinée PIL en un tableau numpy, lors de l'utilisation de matplotlib imshow sur le tableau, il l'a montrée à l'envers nécessitant une np.flipudcorrection. Bien que mon image PIL ait été créée à partir de zéro en utilisant ImageDraw.Draw. Je pense qu'il faut faire attention d'où vient l'origine de leurs coordonnées.
CMCDragonkai
Soyez bénis!! Je cherchais cette réponse depuis une demi-journée. Cela résout mon problème de restauration de l'axe d'origine après l'image du tracé à l'image d'origine.
Fée
16

Vous devez convertir votre image en un tableau numpy de cette façon:

import numpy
import PIL

img = PIL.Image.open("foo.jpg").convert("L")
imgarr = numpy.array(img) 
Billal Begueradj
la source
Ce mode de conversion conserve l'image mais entraîne une perte de couleurs. Quoi qu'il en soit pour éviter la perte de couleur?
Moondra
7
@moondra Si je comprends votre question, vous pouvez remplacer .convert("L") par.convert("RGB")
Billal Begueradj
3

L'exemple que j'ai utilisé aujourd'hui:

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)
Uki D. Lucas
la source
0

Si votre image est stockée au format Blob (c'est-à-dire dans une base de données), vous pouvez utiliser la même technique expliquée par Billal Begueradj pour convertir votre image de Blobs en un tableau d'octets.

Dans mon cas, j'avais besoin que mes images soient stockées dans une colonne blob dans une table db:

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

J'ai ensuite créé une fonction d'aide pour changer mon jeu de données en 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

Après cela, j'ai pu utiliser les byteArrays dans mon réseau de neurones.

plt.imshow(imagesList[0])
Charles Vogt
la source
0

Convertir l' Numpy to PILimage etPIL to Numpy

import numpy as np
from PIL import Image

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

def NumpyToPil(img):
    return Image.fromarray(img)
Kamran Gasimov
la source
-1
def imshow(img):
    img = img / 2 + 0.5     # unnormalize
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()

Vous pouvez transformer l'image en numpy en analysant l'image en fonction numpy () après avoir éliminé les fonctionnalités (dé-normalisation)

Thiyagu
la source