Nasıl bir PIL Image numpy dizi dönüştürmek için?


257

Pekala, bir PIL görüntü nesnesini bir numpy diziye dönüştürerek oynuyorum, bu yüzden PIL PixelAccessnesnesinin izin vereceğinden piksel dönüşümleriyle daha hızlı pikseller yapabiliyorum . Ben aşağıdaki gibi yararlı bir 3D numpy dizi piksel bilgileri yerleştirmek nasıl anladım:

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

Ama tüm harika dönüşümlerimi yaptıktan sonra PIL nesnesine nasıl geri yükleyeceğimi anlayamıyorum. putdata()Metodun farkındayım , ama davranmasını pek sağlayamıyor gibi görünüyor.


6
Bu Not pic.size[0]ve pic.size[1]takas (yani. reshape(pic.size[1], pic.size[0], 3)Beri), sizebir width x heightya da x * ymatris sipariş ederken rows x columns.
18'de sisler

Yanıtlar:


287

Tam olarak nasıl putdata()davranmadığını söylemiyorsun . Yaptığınızı varsayıyorum

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

Bunun nedeni, putdatabir dizi tuple beklemesi ve ona numpy dizi vermesidir. Bu

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

çalışacak ama çok yavaş.

PIL 1.1.6 itibariyle, görüntüler ve numpy dizileri arasında dönüştürmenin "uygun" yolu basitçe

>>> pix = numpy.array(pic)

sonuçta elde edilen dizi sizinkinden farklı bir biçimde olsa da (bu durumda 3 boyutlu dizi veya satırlar / sütunlar / rgb).

Sonra, dizi üzerinde değişiklik yaptıktan sonra, ya yapmak ya pic.putdata(pix)da ile yeni bir görüntü oluşturmak gerekir Image.fromarray(pix).


2
İlk olarak, pic.putdata (veri) olmamalı mı? Ve numpy.asarray (pic) salt okunur bir dizi üretir, bu nedenle numpy.array (pic) 'i çağırmanız gerekir ve soruyu cevaplamadınız ... sağladığınız bağlantıdan pic = Image.fromarray ( pix). Cevabınızı düzeltin, kabul edeceğim.
akdom

2
Bunun için teşekkürler ... Image.fromarrayPIL belgelerinde (!) Listelenmedi, bu yüzden bu olmasaydı asla bulamazdım.
Nathan Reed

13
Bu sayfa, numpy.asarray(pic)dönüştürmenin "uygun" yolu olarak listelenir numpy.array(pic). Gereğince bu cevap array bir kopyasını oysa yapacak asarrayolmaz (ama sonra asarraysonuç edilecek salt okunur).
Arthur Tacca

1
Burada bir uyarı (kendi hatamdan): verilerin ölçeğini ve aralıklarını da dikkate almanız gerekir. Birçok kullanımda Görüntüleri 0-255 bayt ile oluşturursunuz, ancak bunların numpy dizisinde örneğin 0,0-1,0 değerine dönüştürülmesini bekleyebilirsiniz. Uint8'den bazı birim dönüşümler bunu yapar, ancak bu durumda, bunu yapmaz .. bu yüzden kontrol edin :)
BjornW

İkinci cevap daha iyi.
Nathan

195

IDizi olarak aç :

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

IArdından, bir görüntüye geri dönüştürmek için bir şeyler yapın :

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

Numune görüntüleri FFT, Python ile filtreleme

Herhangi bir nedenle açık bir şekilde yapmak istiyorsanız , korelasyon.zip içinde bu sayfada getdata () kullanan pil2array () ve array2pil () işlevleri vardır .


2
@ArditS .: import Imageİlk mi yaptınız ? PIL yüklü mü?
endolit

5
uint8dönüşüm gerekli?
Neil Traft

4
numpy.asarray(Image.open(filename)).jpg görüntüleri için çalışıyor gibi görünüyor, ancak .png için çalışmıyor. Sonuç olarak görüntülenir array(<PngImagePlugin.PngImageFile image mode=LA size=500x500 at 0x3468198>, dtype=object). Bunu PngImagePlugin.PngImageFileçözmek için nesnenin açıkça adlandırılmış yöntemleri yoktur . Sanırım bunu yeni bir soru olarak sormalıyım ama bu konu ile çok ilgili. Burada neyin yanlış gittiğini anlayan var mı?
jez

3
@Rebs: Burada sebebidir neden bu kadar çok hızlıdır: getdata()nesne (gibi bir dizi döndüren pillow.readthedocs.io/en/3.4.x/reference/... ), ancak yastık görüntü uygular ham bayt erişmek için kullanabileceğiniz bir yineleyiciden geçmek zorunda kalmadan resim (bkz. github.com/python-pillow/Pillow/blob/… ve docs.scipy.org/doc/numpy/reference/arrays.interface.html ). Hatta sadece kullanabilirsiniz__array_interface__numpynumpy.array(PIL.Image.open('test.jpg'))
tdp2110

3
@jez Image nesnesini numpy'ye dönüştürmeden önce kapalı olup olmadığını kontrol edin. Aynı şey başıma geldi ve görüntü nesnesini bir yerlerde kapattığımı gördüm.
Shaohua Li

65

Python 3.5'te Pillow 4.1.1'i (PIL'in halefi) kullanıyorum. Yastık ve numpy arasındaki dönüşüm basittir.

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)

Dikkat edilmesi gereken bir şey, yastık stilinin imsütun-büyük, numpy stilinin im2arrise satır-büyük olmasıdır. Ancak, işlev Image.fromarrayzaten bunu dikkate almaktadır. Yani arr2im.size == im.sizeve arr2im.mode == im.modeyukarıdaki örnekte.

Dönüştürülmüş numpy dizilerini işlerken HxWxC veri formatına dikkat etmeliyiz, örneğin, dönüşümü yapın im2arr = np.rollaxis(im2arr, 2, 0)veya im2arr = np.transpose(im2arr, (2, 0, 1))CxHxW formatına dönüştürün.


2
Bu, ithalat ifadeleri de dahil olmak üzere en temiz örnekle ilgilidir (bu ayrıntı için teşekkürler). Görünürlüğü artırmak için bu cevabı oylayalım.
David Parks

Ben bir PIL çizilmiş görüntüyü bir numpy diziye dönüştürdüğümde, dizide matplotlib imshow kullanırken, baş aşağı bir np.flipuddüzeltmek gerektiren gösterdi . Her ne kadar benim PIL görüntü sıfırdan kullanılarak oluşturuldu ImageDraw.Draw. Bence koordinatlarının kökeninin nereden geldiğine dikkat edilmelidir.
CMCDragonkai

Seni korusun!! Bu cevabı yarım gündür arıyordum. Çizim görüntüsünden sonra orijinal ekseni orijinaline geri yükleme sorunumu çözer.
Tinkerbell

16

Görüntünüzü bu şekilde bir numpy dizisine dönüştürmeniz gerekir:

import numpy
import PIL

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

Bu dönüştürme yöntemi görüntüyü korur, ancak renk kaybına neden olur. Neyse renk kaybını önlemek için?
Moondra

7
Sorunuzu anlamak @moondra, sen yerine .convert("L") göre.convert("RGB")
Billal Begueradj

3

Bugün kullandığım örnek:

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

Resminiz bir Blob biçiminde (yani bir veritabanında) saklanıyorsa, görüntünüzü Blob'lardan bir bayt dizisine dönüştürmek için Billal Begueradj tarafından açıklananla aynı tekniği kullanabilirsiniz.

Benim durumumda, görüntüleri bir db tablosunda bir blob sütununda depolanan gerekli:

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

Daha sonra veri kümemi np.array olarak değiştirmek için bir yardımcı işlev oluşturdum:

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

Bundan sonra, Sinir Ağımda byteArrays'i kullanabildim.

plt.imshow(imagesList[0])

0

Numpy to PILGörüntüyü dönüştür vePIL 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()

Özelliklere göz attıktan sonra görüntüyü numpy () işlevine ayrıştırarak görüntüyü numpy'ye dönüştürebilirsiniz (normalleştirme)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.