Как преобразовать изображение PIL в массив Numpy?

257

Хорошо, я играю с преобразованием объекта изображения PIL взад-вперед в массив, чтобы я мог сделать более быстрое преобразование пиксель за пикселем, чем PixelAccessпозволил бы объект PIL . Я выяснил, как разместить информацию о пикселях в полезном трехмерном массиве с помощью:

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

Но я не могу понять, как загрузить его обратно в объект PIL после того, как я выполнил все свои удивительные преобразования. Я знаю о putdata()методе, но не могу заставить его вести себя.

akdom
источник
6
Обратите внимание, что pic.size[0]и pic.size[1]следует поменять местами (т. Е. reshape(pic.size[1], pic.size[0], 3)), Поскольку sizeесть width x heightили x * y, в то время как порядок упорядочения матрицы rows x columns.
Фогес

Ответы:

287

Вы не говорите, как именно putdata()не ведет себя. Я предполагаю, что вы делаете

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

Это потому, что putdataожидает последовательность кортежей, а вы присваиваете ей пустой массив. это

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

будет работать, но это очень медленно.

Начиная с PIL 1.1.6, «правильный» способ преобразования между изображениями и массивами просто

>>> pix = numpy.array(pic)

хотя полученный массив имеет формат, отличный от вашего (в этом случае 3-й массив или row / columns / rgb).

Затем, после того, как вы внесете изменения в массив, вы сможете сделать то же самое pic.putdata(pix)или создать новое изображение с помощью Image.fromarray(pix).

дР.
источник
2
Во-первых, не должно ли это быть pic.putdata (data)? И numpy.asarray (pic) создает массив только для чтения, поэтому вам нужно вызвать numpy.array (pic), и вы не ответили на вопрос ... по предоставленной вами ссылке он выглядит как pic = Image.fromarray ( пикс). Исправьте свой ответ, и я приму его.
akdom
2
Спасибо за это ... Image.fromarrayне указано в документации PIL (!), Поэтому я бы никогда не нашел его, если бы не это.
Натан Рид
13
Эта страница указана numpy.asarray(pic)как «правильный» способ конвертации, а не numpy.array(pic). Согласно этому ответу array сделаю копию, а asarrayне будет (но тогда asarrayрезультат будет только для чтения).
Артур Такка
1
Предупреждение здесь (из моей собственной ошибки): вам также необходимо учитывать масштаб и диапазон данных. Во многих случаях вы бы отображали изображения с 0-255 байтами, но вы могли бы ожидать, что они будут преобразованы, например, в 0.0-1.0 в массиве numpy. Некоторые преобразования единиц из uint8 делают это, но в этом случае это не так ... так что проверяйте :)
BjornW
Второй ответ лучше.
Натан
195

Открыть Iкак массив:

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

Сделайте некоторые вещи, чтобы Iзатем преобразовать их обратно в изображение:

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

Фильтрация изображений с помощью FFT, Python

Если вы хотите сделать это явно по какой-то причине, есть функции pil2array () и array2pil (), использующие getdata () на этой странице в correlation.zip.

эндолиты
источник
2
@ArditS .: Ты import Imageпервый? У вас установлен PIL?
эндолит
5
uint8Нужно ли преобразование?
Нил Трафт
4
numpy.asarray(Image.open(filename))Кажется, работает для изображений .jpg, но не для .png. Результат отображается как array(<PngImagePlugin.PngImageFile image mode=LA size=500x500 at 0x3468198>, dtype=object). Кажется, нет никаких явно названных методов PngImagePlugin.PngImageFileобъекта для решения этого. Думаю, я должен задать это как новый вопрос, но это очень актуально для этой темы. Кто-нибудь понимает, что здесь происходит не так?
Jez
3
@Rebs: вот причина, почему это намного быстрее: getdata()возвращает последовательность, подобную объекту ( pillow.readthedocs.io/en/3.4.x/reference/… ), но изображение подушки реализует то, __array_interface__что numpyможно использовать для доступа к необработанным байтам изображения без необходимости проходить через итератор (см. github.com/python-pillow/Pillow/blob/… и docs.scipy.org/doc/numpy/reference/arrays.interface.html ). Вы можете даже просто использоватьnumpy.array(PIL.Image.open('test.jpg'))
tdp2110
3
@jez Проверьте, не закрыт ли объект Image, прежде чем конвертировать его в numpy. То же самое случилось со мной, и я обнаружил, что где-то закрыл объект изображения.
Шаохуа Ли
65

Я использую Pillow 4.1.1 (преемник PIL) в Python 3.5. Преобразование между Подушкой и NumPy является простым.

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)

Одна вещь, на которую нужно обратить внимание, заключается в том, что стиль подушек im- основной столбец, в то время как стиль пустышек im2arr- основной ряд. Однако функция Image.fromarrayуже принимает это во внимание. То есть arr2im.size == im.sizeи arr2im.mode == im.modeв приведенном выше примере.

Мы должны позаботиться о формате данных HxWxC при обработке преобразованных числовых массивов, например, выполнить преобразование im2arr = np.rollaxis(im2arr, 2, 0)или im2arr = np.transpose(im2arr, (2, 0, 1))в формат CxHxW.

Даниил
источник
2
Это самый чистый пример, включая операторы импорта (спасибо за эту информацию). Давайте проголосуем за этот ответ, чтобы увеличить видимость.
Дэвид Паркс
Я обнаружил, что когда я конвертировал нарисованное PIL-изображение в массив numpy, при использовании в массиве matplotlib imshow он показывал его вверх ногами, требуя np.flipudисправления. Хотя мое изображение PIL было создано с нуля, используя ImageDraw.Draw. Я думаю, что нужно быть осторожным, откуда происходит их координаты.
CMCDragonkai
Будьте здоровы!! Я искал этот ответ в течение половины дня. Это решает мою проблему восстановления исходной оси после изображения графика к исходной.
Тинкербелл
16

Вам нужно преобразовать ваше изображение в массив numy следующим образом:

import numpy
import PIL

img = PIL.Image.open("foo.jpg").convert("L")
imgarr = numpy.array(img) 
Биллаль Бегерадж
источник
Этот способ преобразования сохраняет изображение, но приводит к потере цветов. Во всяком случае, чтобы избежать потери цвета?
Moondra
7
@moondra Если я понимаю ваш вопрос, вы можете заменить .convert("L") на.convert("RGB")
Биллал Бегерадж
3

Пример, который я использовал сегодня:

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

Если ваше изображение хранится в формате BLOB-объектов (т. Е. В базе данных), вы можете использовать ту же технику, которая описана Биллом Бегераджем, чтобы преобразовать ваше изображение из BLOB-объектов в байтовый массив.

В моем случае мне нужны были мои изображения, которые хранятся в столбце BLOB-объектов в таблице БД:

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

Затем я создал вспомогательную функцию для изменения набора данных в 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

После этого я смог использовать byteArrays в моей нейронной сети.

plt.imshow(imagesList[0])
Чарльз Фогт
источник
0

Конвертировать Numpy to PILизображение иPIL 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()

Вы можете преобразовать изображение в NumPy, проанализировав изображение в функцию NUMPY () после удаления функций (ненормализация)

Thiyagu
источник