Wie konvertiere ich ein PIL-Bild in ein Numpy-Array?

257

Okay, ich spiele damit herum, ein PIL-Bildobjekt hin und her in ein numpy-Array zu konvertieren, damit ich einige Pixel-für-Pixel-Transformationen schneller durchführen kann, als es das PIL- PixelAccessObjekt zulässt. Ich habe herausgefunden, wie man die Pixelinformationen in einem nützlichen 3D-Numpy-Array platziert:

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

Aber ich kann nicht herausfinden, wie ich es wieder in das PIL-Objekt laden kann, nachdem ich alle meine fantastischen Transformationen durchgeführt habe. Ich bin mir der putdata()Methode bewusst , kann sie aber anscheinend nicht dazu bringen, sich zu verhalten.

Akdom
quelle
6
Beachten Sie, dass pic.size[0]und pic.size[1]ausgetauscht werden sollten (dh reshape(pic.size[1], pic.size[0], 3)), da sizeist width x heightoder x * y, während die Matrixreihenfolge ist rows x columns.
Nebel

Antworten:

286

Sie sagen nicht, wie genau putdata()sich nicht verhält. Ich gehe davon aus, dass du es tust

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

Dies liegt daran, putdatadass eine Folge von Tupeln erwartet wird und Sie ihr ein numpy-Array geben. Dies

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

wird funktionieren, aber es ist sehr langsam.

Ab PIL 1.1.6 ist die "richtige" Konvertierung zwischen Bildern und Numpy-Arrays einfach

>>> pix = numpy.array(pic)

obwohl das resultierende Array ein anderes Format als Ihr Array hat (3D-Array oder Zeilen / Spalten / RGB in diesem Fall).

Nachdem Sie Ihre Änderungen am Array vorgenommen haben, sollten Sie in der Lage sein, entweder pic.putdata(pix)ein neues Image zu erstellen oder ein neues Image mit zu erstellen Image.fromarray(pix).

dF.
quelle
2
Sollte es nicht pic.putdata (Daten) sein? Und numpy.asarray (Bild) erzeugt ein schreibgeschütztes Array. Sie müssen also numpy.array (Bild) aufrufen, und Sie haben die Frage nicht beantwortet ... über den von Ihnen angegebenen Link scheint es sich um pic = Image.fromarray ( pix). Korrigieren Sie Ihre Antwort und ich werde sie akzeptieren.
Akdom
2
Vielen Dank dafür ... Image.fromarrayist nicht in der PIL-Dokumentation (!) Aufgeführt, daher hätte ich es ohne dies nie gefunden.
Nathan Reed
13
Diese Seite wird numpy.asarray(pic)als "richtige" Art der Konvertierung aufgeführt, nicht numpy.array(pic). Gemäß dieser Antwort array wird eine Kopie erstellt, während dies asarraynicht der asarrayFall ist (aber dann ist das Ergebnis schreibgeschützt).
Arthur Tacca
1
Eine Warnung hier (aus meinem eigenen Fehler): Sie müssen auch den Umfang und die Bereiche der Daten berücksichtigen. In vielen Fällen würden Sie Bilder mit 0-255 Bytes rendern, aber Sie könnten erwarten, dass diese im numpy-Array beispielsweise in 0.0-1.0 konvertiert werden. Einige Einheitenumrechnungen von uint8 tun dies, aber in diesem Fall nicht ... also überprüfen Sie es :)
BjörnW
Die zweite Antwort ist besser.
Nathan
193

IAls Array öffnen :

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

Machen Sie dann einige Dinge I, um es wieder in ein Bild umzuwandeln:

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

Filtern Sie numpy Bilder mit FFT, Python

Wenn Sie dies aus irgendeinem Grund explizit tun möchten, gibt es auf dieser Seite in korrelation.zip die Funktionen pil2array () und array2pil (), die getdata () verwenden .

Endolith
quelle
2
@ArditS.: Hast du import Imagezuerst? Haben Sie PIL installiert?
Endolith
5
Ist die uint8Umstellung notwendig?
Neil Traft
4
numpy.asarray(Image.open(filename))scheint für .jpg-Bilder zu funktionieren, aber nicht für .png. Das Ergebnis wird als angezeigt array(<PngImagePlugin.PngImageFile image mode=LA size=500x500 at 0x3468198>, dtype=object). Es scheint keine offensichtlich benannten Methoden des PngImagePlugin.PngImageFileObjekts zu geben, um dies zu lösen. Ich denke, ich sollte dies als neue Frage stellen, aber es ist sehr relevant für diesen Thread. Versteht jemand, was hier falsch läuft?
Jez
3
@Rebs: Hier ist der Grund, warum dies so viel schneller geht: Gibtgetdata() eine Sequenz wie das Objekt ( pillow.readthedocs.io/en/3.4.x/reference/… ) zurück, aber ein Kissenbild implementiert das __array_interface__, numpymit dem auf die Rohbytes zugegriffen werden kann eines Bildes, ohne einen Iterator durchlaufen zu müssen (siehe github.com/python-pillow/Pillow/blob/… und docs.scipy.org/doc/numpy/reference/arrays.interface.html ). Sie können sogar einfach verwendennumpy.array(PIL.Image.open('test.jpg'))
tdp2110
3
@jez Überprüfen Sie, ob das Image-Objekt geschlossen ist, bevor Sie es in numpy konvertieren. Das gleiche passierte mir und ich stellte fest, dass ich das Bildobjekt irgendwo geschlossen hatte.
Shaohua Li
65

Ich verwende Pillow 4.1.1 (den Nachfolger von PIL) in Python 3.5. Die Umstellung zwischen Pillow und Numpy ist unkompliziert.

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)

Eine Sache, die imbeachtet werden muss, ist, dass der Kissenstil Spalten-Major ist, während der Numpy-Stil im2arrZeilen-Major ist. Die Funktion Image.fromarrayberücksichtigt dies jedoch bereits. Das heißt, arr2im.size == im.sizeund arr2im.mode == im.modeim obigen Beispiel.

Wir sollten das HxWxC-Datenformat berücksichtigen, wenn wir die transformierten Numpy-Arrays verarbeiten, z. B. die Transformation im2arr = np.rollaxis(im2arr, 2, 0)oder das im2arr = np.transpose(im2arr, (2, 0, 1))CxHxW-Format.

Daniel
quelle
2
Hier geht es um das sauberste Beispiel, einschließlich Importanweisungen (danke für dieses Detail). Lassen Sie uns diese Antwort abstimmen, um die Sichtbarkeit zu erhöhen.
David Parks
Ich stellte fest, dass beim Konvertieren eines von PIL gezeichneten Bilds in ein Numpy-Array bei Verwendung von matplotlib imshow für das Array das Bild verkehrt herum angezeigt wurde und ein np.flipudFix erforderlich war . Obwohl mein PIL-Image von Grund auf neu erstellt wurde ImageDraw.Draw. Ich denke, man muss vorsichtig sein, woher der Ursprung ihrer Koordinaten kommt.
CMCDragonkai
Gesundheit!! Ich habe einen halben Tag nach dieser Antwort gesucht. Es löst mein Problem, die ursprüngliche Achse nach dem Plotbild auf die ursprüngliche wiederherzustellen.
Tinkerbell
16

Sie müssen Ihr Bild folgendermaßen in ein Numpy-Array konvertieren:

import numpy
import PIL

img = PIL.Image.open("foo.jpg").convert("L")
imgarr = numpy.array(img) 
Billal Begueradj
quelle
Diese Art der Konvertierung behält das Bild bei, führt jedoch zu einem Farbverlust. Wie auch immer, um den Farbverlust zu vermeiden?
Moondra
7
@moondra Wenn ich Ihre Frage verstehe, können Sie ersetzen .convert("L") durch.convert("RGB")
Billal Begueradj
3

Das Beispiel, das ich heute verwendet habe:

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

Wenn Ihr Bild in einem Blob-Format (dh in einer Datenbank) gespeichert ist, können Sie dieselbe von Billal Begueradj erläuterte Technik verwenden, um Ihr Bild von Blobs in ein Byte-Array zu konvertieren.

In meinem Fall brauchte ich meine Bilder, die in einer Blob-Spalte in einer DB-Tabelle gespeichert waren:

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

Ich habe dann eine Hilfsfunktion erstellt, um meinen Datensatz in np.array zu ändern:

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

Danach konnte ich die byteArrays in meinem neuronalen Netzwerk verwenden.

plt.imshow(imagesList[0])
Charles Vogt
quelle
0

Numpy to PILBild konvertieren undPIL 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
quelle
-1
def imshow(img):
    img = img / 2 + 0.5     # unnormalize
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()

Sie können das Bild in Numpy umwandeln, indem Sie das Bild nach dem Ausquetschen der Features in die Funktion Numpy () analysieren (Unnormalisierung).

Thiyagu
quelle