Jak przekonwertować obraz PIL na tablicę numpy?

257

W porządku, bawię się z konwertowaniem obiektu obrazu PIL tam iz powrotem na tablicę numpy, dzięki czemu mogę wykonywać szybsze transformacje piksel po pikselu, niż PixelAccesspozwala obiekt PIL . Nauczyłem się, jak umieszczać informacje o pikselach w przydatnej macierzy liczb 3D w następujący sposób:

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

Ale nie potrafię wymyślić, jak załadować go z powrotem do obiektu PIL po wykonaniu wszystkich moich niesamowitych transformacji. Zdaję sobie sprawę z tej putdata()metody, ale nie wydaje mi się, żeby mogła się zachowywać.

akdom
źródło
6
Zauważ, że pic.size[0]i pic.size[1]należy zamieniać (tj. reshape(pic.size[1], pic.size[0], 3)), Ponieważ sizejest width x heightlub x * y, podczas gdy porządkowanie macierzy jest rows x columns.
foges

Odpowiedzi:

286

Nie mówisz, jak dokładnie putdata()się nie zachowuje. Zakładam, że robisz

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

Wynika to z faktu, putdataże oczekuje sekwencji krotek, a Ty dajesz jej tablicę numpy. To

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

będzie działać, ale jest bardzo wolny.

Od PIL 1.1.6 „właściwym” sposobem konwersji między obrazami a tablicami liczbowymi jest po prostu

>>> pix = numpy.array(pic)

chociaż wynikowa tablica ma inny format niż twój (w tym przypadku tablica 3-d lub wiersze / kolumny / rgb).

Następnie, po dokonaniu zmian w tablicy, powinieneś być w stanie zrobić albo pic.putdata(pix)utworzyć nowy obraz za pomocą Image.fromarray(pix).

dF.
źródło
2
Po pierwsze, czy nie powinien to być pic.putdata (data)? A numpy.asarray (pic) tworzy tablicę tylko do odczytu, więc musisz wywołać numpy.array (pic), a ty nie odpowiedziałeś na pytanie ... z podanego linku wygląda na to, że pic = Image.fromarray ( szkatułka). Napraw swoją odpowiedź, a ja ją zaakceptuję.
akdom
2
Dzięki za to ... Image.fromarraynie ma go w dokumentacji PIL (!), Więc nigdy bym go nie znalazł, gdyby nie to.
Nathan Reed
13
Ta strona jest wymieniona numpy.asarray(pic)jako „właściwy” sposób konwersji, a nie numpy.array(pic). Zgodnie z tą odpowiedzią array zrobi kopię, podczas gdy asarraynie będzie (ale wtedy asarraywynik będzie tylko do odczytu).
Arthur Tacca
1
Ostrzeżenie tutaj (z mojego własnego błędu): musisz również wziąć pod uwagę skalę i zakresy danych. W wielu przypadkach użycia renderowałbyś obrazy z 0-255 bajtami, ale możesz się spodziewać, że zostaną przekonwertowane na przykład na 0,0-1,0 w tablicy numpy. Robią to niektóre konwersje jednostek z uint8, ale w tym przypadku nie .. więc sprawdź to :)
BjornW 21.01.19
Druga odpowiedź jest lepsza.
Nathan
193

Otwórz Ijako tablicę:

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

Zrób kilka rzeczy I, a następnie przekonwertuj go z powrotem na obraz:

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

Filtruj niezliczone obrazy za pomocą FFT, Python

Jeśli z jakiegoś powodu chcesz to zrobić jawnie, istnieją funkcje pil2array () i array2pil () za pomocą getdata () na tej stronie w correlation.zip.

endolit
źródło
2
@ArditS .: Czy import Imagepierwszy? Czy masz zainstalowany PIL?
endolith
5
Czy uint8konwersja jest konieczna?
Neil Traft
4
numpy.asarray(Image.open(filename))wydaje się działać dla obrazów .jpg, ale nie dla .png. Wynik wyświetla się jako array(<PngImagePlugin.PngImageFile image mode=LA size=500x500 at 0x3468198>, dtype=object). Wydaje się, że nie ma metod o oczywistych nazwach PngImagePlugin.PngImageFileobiektu do rozwiązania tego. Chyba powinienem zadać to pytanie jako nowe pytanie, ale jest to bardzo istotne w tym wątku. Czy ktoś rozumie, co się tu dzieje nie tak?
jez
3
@Rebs: oto powód, dla którego jest to o wiele szybsze: getdata()zwraca obiekt podobny do sekwencji ( pillow.readthedocs.io/en/3.4.x/reference/... ), ale obraz poduszki implementuje to, __array_interface__czego numpymożna użyć, aby uzyskać dostęp do surowych bajtów obrazu bez konieczności przechodzenia przez iterator (patrz github.com/python-pillow/Pillow/blob/... i docs.scipy.org/doc/numpy/reference/arrays.interface.html ). Możesz nawet użyćnumpy.array(PIL.Image.open('test.jpg'))
tdp2110,
3
@jez Sprawdź, czy obiekt Image jest zamknięty, zanim przekształcisz go w numpy. To samo mi się przydarzyło i odkryłem, że gdzieś zamknąłem obiekt obrazu.
Shaohua Li,
65

Korzystam z Pillow 4.1.1 (następca PIL) w Pythonie 3.5. Konwersja między Pillow a Numpy jest prosta.

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)

Jedną rzeczą, na którą należy zwrócić uwagę, jest to, że styl Poduszki imjest major-kolumna, podczas gdy styl numpy im2arr-dur-dur. Jednak funkcja Image.fromarrayjuż to uwzględnia. Oznacza to, że arr2im.size == im.sizei arr2im.mode == im.modew powyższym przykładzie.

Podczas przetwarzania transformowanych tablic numpy, np. Przeprowadzania transformacji im2arr = np.rollaxis(im2arr, 2, 0)lub im2arr = np.transpose(im2arr, (2, 0, 1))do formatu CxHxW, powinniśmy zadbać o format danych HxWxC.

Daniel
źródło
2
Chodzi o najczystszy przykład, w tym instrukcje importu (dzięki za ten szczegół). Głosujmy na tę odpowiedź, aby zwiększyć widoczność.
David Parks,
Przekonałem się, że kiedy przekonwertowałem obraz narysowany w PIL na tablicę numpy, kiedy użyłem imshow matplotlib na tablicy, pokazało to do góry nogami wymagającą np.flipudnaprawy. Chociaż mój obraz PIL został utworzony od podstaw przy użyciu ImageDraw.Draw. Myślę, że trzeba uważać, skąd bierze się pochodzenie ich współrzędnych.
CMCDragonkai
Na zdrowie!! Odpowiedzi szukałem od pół dnia. To rozwiązuje mój problem przywracania oryginalnej osi po obrazie wydruku do oryginalnej.
Tinkerbell
16

Musisz przekonwertować obraz na tablicę numpy w następujący sposób:

import numpy
import PIL

img = PIL.Image.open("foo.jpg").convert("L")
imgarr = numpy.array(img) 
Billal Begueradj
źródło
Ten sposób konwersji zachowuje obraz, ale powoduje utratę kolorów. W każdym razie, aby uniknąć utraty koloru?
Moondra
7
@moondra Jeśli rozumiem Twoje pytanie, można zastąpić .convert("L") przez.convert("RGB")
Billal Begueradj
3

Przykład, którego użyłem dzisiaj:

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
źródło
0

Jeśli twój obraz jest przechowywany w formacie Blob (tj. W bazie danych), możesz użyć tej samej techniki objaśnionej przez Billal Begueradj, aby przekonwertować swój obraz z obiektów Blob do tablicy bajtów.

W moim przypadku potrzebowałem obrazów, które były przechowywane w kolumnie obiektów blob w tabeli db:

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

Następnie utworzyłem funkcję pomocnika, aby zmienić mój zestaw danych na 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

Po tym byłem w stanie używać byteArrays w mojej sieci neuronowej.

plt.imshow(imagesList[0])
Charles Vogt
źródło
0

Konwertuj Numpy to PILobraz iPIL 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
źródło
-1
def imshow(img):
    img = img / 2 + 0.5     # unnormalize
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()

Możesz przekształcić obraz w numpy, parsując obraz w funkcję numpy () po wycięciu funkcji (nienormalizacja)

Thiyagu
źródło