Як перетворити зображення PIL в масивний рядок?


257

Гаразд, я розмовляю з перетворенням об'єкта зображення PIL туди-сюди в масивний масив, щоб я міг зробити швидші пікселі за допомогою піксельних перетворень, ніж PixelAccessдозволив об’єкт PIL . Я зрозумів, як розмістити інформацію пікселів у корисному 3D-нумеровому масиві за допомогою:

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

Але я не можу зрозуміти, як завантажити його назад в об'єкт PIL після того, як я зробив усі свої дивовижні перетворення. Я знаю про putdata()метод, але, здається, не можу змусити його вести себе.


6
Зауважте, що pic.size[0]і pic.size[1]слід їх замінювати (тобто reshape(pic.size[1], pic.size[0], 3)), оскільки sizeє width x heightабо x * y, поки впорядкування матриці є rows x columns.
foges

Відповіді:


286

Ти не кажеш, як саме 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-денний масив або рядки / стовпці / rgb).

Потім, зробивши зміни в масиві, ви зможете зробити pic.putdata(pix)або створити нове зображення за допомогою Image.fromarray(pix).


2
По-перше, чи не повинні це бути pic.putdata (дані)? І 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

Друга відповідь - краще.
Натан

193

Відкрити Iяк масив:

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

Зробіть кілька речей, щоб Iпотім перетворити їх на зображення:

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

Фільтруйте тупі зображення за допомогою FFT, Python

Якщо ви хочете зробити це явно з якихось причин, на цій сторінці є кореляція.zip функцій pil2array () та array2pil (), що використовують getdata () .


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

Я використовую Подушку 4.1.1 (спадкоємця PIL) в Python 3.5. Перетворення між Подушкою та нумером просте.

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 в масивний масив, під час використання implohow matplotlib в масиві він показав це догори дном, вимагаючи np.flipudвиправити. Хоча моє зображення PIL було створене з нуля за допомогою ImageDraw.Draw. Я думаю, що треба бути обережним, звідки походить їх координат.
CMCDragonkai

Будь здоровий!! Я відповідав цю відповідь вже пів дня. Це вирішує мою проблему відновлення вихідної осі після зображення сюжету до оригінальної.
Тінкербелл

16

Вам потрібно перетворити ваше зображення в масивний рядок таким чином:

import numpy
import PIL

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

Цей спосіб перетворення зберігає зображення, але призводить до втрати кольорів. У всякому разі, щоб уникнути втрати кольору?
Мондра

7
@moondra Якщо я зрозумів ваше запитання, ви можете замінити .convert("L") його.convert("RGB")
Billal Begueradj

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 (тобто в базі даних), ви можете скористатися тією ж технікою, яку пояснив Billal Begueradj, щоб перетворити ваше зображення з Blobs в байтовий масив.

У моєму випадку мені потрібні були мої зображення, де вони зберігаються у колоні blob у db-таблиці:

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 () після видалення функцій (ненормалізація)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.