Como converter um PIL Imagem em uma matriz numpy?
-
23-08-2019 - |
Pergunta
Tudo bem, eu estou brincando ao redor com a conversão de um objeto de imagem PIL e para trás em uma matriz de numpy para que eu possa fazer alguma pixels mais rápido por transformações de pixel de objeto PixelAccess
do PIL permitiria. Eu descobri como colocar as informações de pixel em uma matriz útil numpy 3D por meio de:
pic = Image.open("foo.jpg")
pix = numpy.array(pic.getdata()).reshape(pic.size[0], pic.size[1], 3)
Mas eu não consigo descobrir como carregá-lo de volta para o objeto PIL depois que eu fiz todas as minhas transformações impressionantes. Estou ciente do putdata()
método, mas não consegue parecem se ele se comportar.
Solução
Você não está dizendo exatamente como putdata()
não está se comportando. Estou assumindo que você está fazendo
>>> 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
Isto porque putdata
espera uma seqüência de tuplas e você está dando-lhe uma matriz numpy. Este
>>> data = list(tuple(pixel) for pixel in pix)
>>> pic.putdata(data)
vai funcionar, mas é muito lento.
A partir de PIL 1.1.6, o "adequada" maneira de converter entre imagens e numpy matrizes é simplesmente
>>> pix = numpy.array(pic)
embora a matriz resultante é de um formato diferente do que o seu (3-d matriz ou linhas / colunas / RGB neste caso).
Então, depois de fazer as alterações para a matriz, você deve ser capaz de fazer qualquer um pic.putdata(pix)
ou criar uma nova imagem com Image.fromarray(pix)
.
Outras dicas
Open I
como uma matriz:
>>> I = numpy.asarray(PIL.Image.open('test.jpg'))
Faça alguma coisa para I
, em seguida, convertê-lo de volta para uma imagem:
>>> im = PIL.Image.fromarray(numpy.uint8(I))
imagens numpy filtro com FFT, Python
Se você quiser fazê-lo explicitamente, por algum motivo, há pil2array () e array2pil () funções usando getdata () em desta página em correlation.zip.
Eu estou usando Pillow 4.1.1 (o sucessor do PIL) em Python 3.5. A conversão entre Pillow e numpy é simples.
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)
Uma coisa que precisa perceber é que im
Pillow-estilo é a coluna-major enquanto im2arr
-style numpy é da maior linha. No entanto, a função Image.fromarray
já leva isso em consideração. Ou seja, arr2im.size == im.size
e arr2im.mode == im.mode
no exemplo acima.
Devemos cuidar do formato de dados HxWxC ao processar as matrizes numpy transformados, por exemplo, faça o im2arr = np.rollaxis(im2arr, 2, 0)
ou im2arr = np.transpose(im2arr, (2, 0, 1))
transformar em formato CxHxW.
Você precisa converter sua imagem para uma matriz numpy desta maneira:
import numpy
import PIL
img = PIL.Image.open("foo.jpg").convert("L")
imgarr = numpy.array(img)
O exemplo, tenho usado hoje:
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)
Se a imagem é armazenada em um formato Blob (ou seja, em um banco de dados), você pode usar a mesma técnica explicada por Billal Begueradj para converter sua imagem de Blobs para um array de bytes.
No meu caso, eu precisava de minhas imagens onde armazenados em uma coluna blob em uma tabela db:
def select_all_X_values(conn):
cur = conn.cursor()
cur.execute("SELECT ImageData from PiecesTable")
rows = cur.fetchall()
return rows
Então, criamos uma função auxiliar para mudar o meu conjunto de dados em 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
Depois disso, eu era capaz de usar os bytearrays na minha rede neural.
plt.imshow(imagesList[0])
def imshow(img):
img = img / 2 + 0.5 # unnormalize
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))
plt.show()
Você pode transformar a imagem em numpy analisando a imagem em numpy () função depois espremendo para fora as características (unnormalization)