Bagaimana cara mengubah Gambar PIL menjadi array numpy?

257

Baiklah, saya bermain-main dengan mengubah objek gambar PIL bolak-balik ke array numpy sehingga saya dapat melakukan beberapa transformasi pixel demi pixel yang lebih cepat daripada yang PixelAccessdiperbolehkan oleh objek PIL . Saya telah menemukan cara untuk menempatkan informasi piksel dalam array numpy 3D yang bermanfaat dengan cara:

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

Tapi sepertinya saya tidak tahu bagaimana cara memuatnya kembali ke objek PIL setelah saya melakukan semua transformasi yang luar biasa. Saya menyadari putdata()metodenya, tetapi sepertinya tidak bisa berperilaku.

akdom
sumber
6
Perhatikan bahwa pic.size[0]dan pic.size[1]harus ditukar (mis. reshape(pic.size[1], pic.size[0], 3)), Karena sizeis width x heightatau x * y, sedangkan pemesanan matriks rows x columns.
foges

Jawaban:

287

Anda tidak mengatakan bagaimana tepatnya putdata()tidak berperilaku. Saya berasumsi Anda sedang melakukannya

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

Ini karena putdatamengharapkan urutan tupel dan Anda memberikannya array yang numpy. Ini

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

akan bekerja tetapi sangat lambat.

Pada PIL 1.1.6, cara "tepat" untuk mengkonversi antara gambar dan array numpy cukup sederhana

>>> pix = numpy.array(pic)

meskipun array yang dihasilkan dalam format yang berbeda dari milik Anda (array 3-d atau baris / kolom / rgb dalam kasus ini).

Kemudian, setelah Anda membuat perubahan pada array, Anda harus dapat melakukan pic.putdata(pix)atau membuat gambar baru dengan Image.fromarray(pix).

dF.
sumber
2
Pertama, bukankah seharusnya pic.putdata (data)? Dan numpy.asarray (pic) menghasilkan array readonly, jadi Anda perlu memanggil numpy.array (pic), dan Anda tidak menjawab pertanyaan ... dari tautan yang Anda berikan tampak seperti pic = Image.fromarray ( pix). Perbaiki jawaban Anda dan saya akan menerimanya.
akdom
2
Terima kasih untuk ini ... Image.fromarraytidak tercantum dalam dokumentasi PIL (!) Jadi saya tidak akan pernah menemukannya jika bukan karena ini.
Nathan Reed
13
Halaman itu mendaftar numpy.asarray(pic)sebagai cara "tepat" untuk mengonversi, bukan numpy.array(pic). Per jawaban ini array akan membuat salinan sedangkan asarraytidak akan (tetapi kemudian asarrayhasilnya akan menjadi read-only).
Arthur Tacca
1
Peringatan di sini (dari kesalahan saya sendiri): Anda perlu mempertimbangkan skala dan rentang data juga. Di banyak usecases Anda akan membuat Gambar dengan 0-255 byte, tetapi Anda mungkin berharap ini akan dikonversi menjadi misalnya 0,0-1,0 dalam array numpy. Beberapa konversi unit dari uint8 melakukan ini, tetapi dalam kasus ini, tidak .. jadi periksa :)
BjornW
Jawaban kedua lebih baik.
Nathan
194

Buka Isebagai larik:

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

Lakukan beberapa hal untuk I, lalu, konversikan kembali ke gambar:

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

Saring gambar numpy dengan FFT, Python

Jika Anda ingin melakukannya secara eksplisit karena beberapa alasan, ada fungsi pil2array () dan array2pil () menggunakan getdata () pada halaman ini di dalam korelasi.zip.

endolit
sumber
2
@ArditS .: Apakah Anda import Imagepertama kali? Apakah Anda sudah menginstal PIL?
endolith
5
Apakah uint8konversi itu perlu?
Neil Traft
4
numpy.asarray(Image.open(filename))tampaknya berfungsi untuk gambar .jpg tetapi tidak untuk .png. Hasilnya ditampilkan sebagai array(<PngImagePlugin.PngImageFile image mode=LA size=500x500 at 0x3468198>, dtype=object). Tampaknya tidak ada metode objek yang disebutkan dengan jelas PngImagePlugin.PngImageFileuntuk memecahkan masalah ini. Kira saya harus menanyakan ini sebagai pertanyaan baru tetapi sangat relevan dengan utas ini. Adakah yang mengerti apa yang salah di sini?
jez
3
@Rebs: inilah alasan mengapa ini jauh lebih cepat: getdata()mengembalikan urutan seperti objek ( pillow.readthedocs.io/en/3.4.x/reference/… ), tetapi gambar bantal mengimplementasikan __array_interface__yang numpydapat digunakan untuk mengakses byte mentah gambar tanpa harus melewati iterator (lihat github.com/python-pillow/Pillow/blob/… dan docs.scipy.org/doc/numpy/reference/arrays.interface.html ). Anda bahkan dapat menggunakannumpy.array(PIL.Image.open('test.jpg'))
tdp2110
3
@ jez Periksa apakah objek Gambar ditutup sebelum Anda mengubahnya menjadi numpy. Hal yang sama terjadi pada saya dan saya menemukan saya menutup objek gambar di suatu tempat.
Shaohua Li
65

Saya menggunakan Pillow 4.1.1 (penerus PIL) dengan Python 3.5. Konversi antara Bantal dan numpy sangat mudah.

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)

Satu hal yang perlu diperhatikan adalah bahwa bantal-gaya imadalah kolom-utama sedangkan gaya numpy im2arradalah baris-utama Namun, fungsi Image.fromarraysudah mempertimbangkan ini. Yaitu, arr2im.size == im.sizedan arr2im.mode == im.modedalam contoh di atas.

Kita harus menjaga format data HxWxC ketika memproses array numpy yang ditransformasikan, misalnya melakukan transformasi im2arr = np.rollaxis(im2arr, 2, 0)atau im2arr = np.transpose(im2arr, (2, 0, 1))ke dalam format CxHxW.

Daniel
sumber
2
Ini adalah contoh paling bersih, termasuk pernyataan impor (terima kasih untuk detailnya). Mari pilih jawaban ini untuk meningkatkan visibilitas.
David Parks
Saya menemukan bahwa ketika saya mengkonversi gambar yang ditarik PIL ke array numpy, ketika menggunakan matplotlib imshow pada array, itu menunjukkan terbalik yang memerlukan np.flipudperbaikan. Meskipun gambar PIL saya dibuat dari awal menggunakan ImageDraw.Draw. Saya pikir orang harus berhati-hati dari mana asal koordinat mereka.
CMCDragonkai
Diberkatilah Anda!! Saya telah mencari jawaban ini selama setengah hari. Ini memecahkan masalah saya mengembalikan sumbu asli setelah gambar plot ke yang asli.
Tinkerbell
16

Anda perlu mengubah gambar Anda menjadi array numpy dengan cara ini:

import numpy
import PIL

img = PIL.Image.open("foo.jpg").convert("L")
imgarr = numpy.array(img) 
Billal Begueradj
sumber
Konversi seperti ini mempertahankan gambar tetapi menghasilkan hilangnya warna. Pokoknya untuk menghindari kehilangan warna?
Moondra
7
@moondra Jika saya mengerti pertanyaan Anda, Anda dapat menggantinya .convert("L") dengan.convert("RGB")
Billal Begueradj
3

Contohnya, saya telah menggunakan hari ini:

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

Jika gambar Anda disimpan dalam format Blob (yaitu dalam database), Anda dapat menggunakan teknik yang sama yang dijelaskan oleh Billal Begueradj untuk mengubah gambar Anda dari Blobs ke array byte.

Dalam kasus saya, saya membutuhkan gambar saya di mana disimpan dalam kolom gumpalan di tabel db:

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

Saya kemudian membuat fungsi pembantu untuk mengubah dataset saya menjadi 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

Setelah ini, saya bisa menggunakan byteArrays di Jaringan Saraf saya.

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

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

Anda dapat mengubah gambar menjadi fungsi numpy dengan mem-parsing gambar ke fungsi numpy () setelah menghilangkan fitur-fiturnya (tidak normalisasi)

Thiyagu
sumber