Pillow — работа с картинками
Pillow — самая популярная библиотека для работы с изображениями в Python. С помощью неё картинки можно открывать, вращать, накладывать фильтры и даже работать с отдельными пикселями.
Обзор
Импортируется библиотека так:
from PIL import Image
Pillow — улучшенная версия библиотеки PIL, поэтому импортируется она таким странным образом. В коде она будет называться PIL.
Далее попробуем что-нибудь сделать с картинкой:
from PIL import Image
image = Image.open("example.jpg")
rotated_image = image.rotate(45)
rotated_image.save("rotated.jpg")
Сначала открываем картинку с названием example.jpg и кладём её в переменную image.
На следущей строке поворачиваем картинку на 45 градусов. Метод .rotate() не меняет картинку, а создаёт новую, поэтому положим её в переменную rotated_image.
И в конце сохраняем повёрнутую картинку в новый файл rotated.jpg.
Атрибуты картинок
В Pillow есть новые типы данных: JpegImageFile, PngImageFile… Они позволяют хранить картинки прямо в переменных Python. У картинок есть несколько атрибутов, которые понадобятся вам в будущем:
- format — формат данных картинки:
jpeg,png… - mode — цветовая модель картинки:
CMYK,RGB,L— для чёрно-белых изображений. - width — ширина картинки в пикселях.
- height — высота картинки в пикселях.
- size — размер картинки в пикселях. Возвращает
tuple: (ширина, высота).
Как их извлечь:
from PIL import Image
image = Image.open("example.jpg")
print(image.format) # Выведет JPG
print(image.mode) # Например, может вывести RGB
Открыть картинку
Для открытия картинки используется функция Image.open().
В качестве аргументов она принимает на вход путь до файла, который нужно открыть:
from PIL import Image
image = Image.open("example.jpg")
Сохранить картинку в файл
Для сохранения картинки есть метод .save().
В качестве аргументов он принимает:
- Путь до файла, в который сохранить картинку.
- Именованный необязательный параметр
format, в котором передаётся формат сохраняемой картинки.
from PIL import Image
image = Image.open("example.jpg")
image.save("new.jpg")
image.save("another.jpg", format="JPEG")
В качестве результата появится 2 копии картинки: new.jpg и another.jpg.
Перевести картинку в другую цветовую модель
О цветовой модели вы можете прочитать в разделе Атрибуты. Чтобы поменять цветовую модель картинки, нужно воспользоваться методом .convert(). Он принимает на вход именной аргумент mode:
from PIL import Image
image = Image.open("example.jpg")
print(image.mode) # Вывелось RGB
cmyk_image = image.convert("CMYK")
print(cmyk_image.mode) # Вывелось CMYK
print(image.mode) # Вывелось RGB
Заметим, что метод не меняет исходную картинку, а создаёт её копию с цветовой моделью CMYK. Поэтому мы положили её в отдельную переменную.
Обрезать картинку
За обрезание картинки отвечает метод .crop(). Он принимает на вход кортеж из 4 чисел: координат углов новой картинки. Координаты отсчитываются с левого верхнего угла картинки:
Координаты нужно передать в таком порядке: слева, сверху, справа, снизу. Например, вы хотите отрезать 10 пикселей слева и 15 сверху:
Пример:
from PIL import Image
image = Image.open("example.jpg")
coordinates = (10, 15, image.width, image.height)
cropped = image.crop(coordinates) # Отрежется 10 пикселей слева и 15 сверху
Этот код отрезает 10 пикселей слева и 15 сверху. Самая правая координата — это и есть ширина картинки, а самая нижняя — высота, поэтому мы и использовали эти атрибуты картинки.
Разделить картинку на каналы
Картинки состоят из пикселей разных цветов. Каждый пиксель картинки в RGB состоит из 3 значений: сколько в нём красного, сколько зелёного и сколько синего. А в цветовой схеме CMYK из четырёх: голубой, пурпурный, жёлтый и чёрный. Все значения от 0 до 255. 0 — нет такого цвета, а 255 — его очень-очень много.
На самом деле картинки хранят не по пикселям, а по каналам. RGB картинка хранится как 3 картинки: в первой в каждом пикселе число от 0 до 255, показывающее, сколько в нём красного. Во второй то же, только с зелёным, а в третьем — с синим.
Получается 3 картинки. Но если взять какой-то цветовой канал отдельно от картинки, то она не будет знать, какой цвет ей показывать. У неё в каждом пикселе всего одно значение от 0 до 255. Поэтому она отображается как чёрно-белая. Если в пикселе хранится 0, то пиксель будет чёрный, а если 255 — белый. Чем больше число, тем светлее пиксель.
Метод .split() разбивает картинку на каналы. Работает так:
from PIL import Image
image = Image.open("example.jpg")
print(image.mode) # Вернуло CMYK, значит канала 4
cyan, magenta, yellow, key_color = image.split() # В переменные запишутся 4 чёрно-белые картинки.
Собрать картинку из каналов
Pillow позволяет разделять картинку на каналы. Но так же позволяет и собирать её обратно. За это отвечает функция Image.merge(). Она принимает на вход 2 аргумента:
- Цветовая модель будущей картинки
- Кортеж из цветовых каналов. Если модель RGB, то первый канал будет покрашен в красный, второй в зелёный, третий в синий.
Пример:
from PIL import Image
image = Image.open("example.jpg")
print(image.mode) # Вернуло CMYK, значит канала 4
cyan, magenta, yellow, key_color = image.split() # В переменные запишутся 4 чёрно-белые картинки.
new_image = Image.merge("CMYK", (cyan, magenta, yellow, key_color))
new_image ничем не отличается от image, т.к. состоит из тех же каналов в том же порядке.
Покрасить цветовой канал
Pillow позволяет раскрашивать чёрно-белые картинки. За это отвечает функция ImageOps.colorize().
Она принимает 3 аргумента: Картинка, какой цвет показывать вместо чёрного и какой вместо белого. Пример:
from PIL import Image, ImageOps
image = Image.open("example.jpg")
colorized = ImageOps.colorize(image, black ="red", white ="yellow")
Код выше сделает из такой картинки:

Такую картинку:

Изменить размер картинки
Как работает thumbnail
Метод resize приводит картинку к желаемому размеру без сохранения пропорций. Картинка жмётся, становится некрасивой:
Метод thumbnail сохраняет пропорции:
Подробнее о thumbnail
С помощью метода .thumbnail() можно легко сделать миниатюру изображения. Миниатюра — уменьшенная версия картинки, с сохранением пропорций. На вход принимается кортеж с максимальными шириной и высотой. Метод .thumbnail() сам подберёт новые координаты так, чтобы картинка поместилась в заданную область. Например, у вас есть картинка 800x1200 и вы хотите поместить её в рамку 1200x600, то результат метода будет 400x600, т.к. 400x600 как раз помещается в 1200x600:
from PIL import Image
image = Image.open("example.jpg")
print(image.size) # Вывелось (800, 1200)
image.thumbnail((1200, 600)) # Картинка теперь размера 400 на 600
print(image.size) # Вывелось (400, 600)
Наложить картинки друг на друга
Функция Image.blend() создаёт новую картинку, накладывая одно изображение поверх другого. Для работы ему необходимы три аргумента:
- Первая картинка.
- Вторая картинка, того же размера, что и первая.
- Коэффициент прозрачности.
Если прозрачность равна 0.5, то картинки смешаются в равных долях. Если коэффициент равен 1.0, то первая картинка станет полностью прозрачной и останется только вторая. Если 0.0, то наоборот. Прозрачность задаётся дробным числом через точку.
from PIL import Image
image1 = Image.open("image1.jpg")
image2 = Image.open("image2.jpg")
image3 = Image.blend(image1, image2, 0.5) # Получится картинка, сложенная из двух
Наложить со смещением
Отдельного метода для этого нет, но получается за счёт комбинации .crop() и Image.blend().
- Выберите картинку для эффекта. У нас это картинка
wave.pngс шириной в 1000 пикселей. - Отрежьте от неё 200 пикселей слева. Получится
wave_left.pngшириной 800 пикселей. - Возьмите исходную картинку
wave.pngи отрежьте от неё по 100 пикселей с обоих сторон: слева и справа. Получитсяwave_middle.pngтоже шириной в 800 пикселей. - Наложите
wave_left.pngнаwave_middle.pngс помощью Image.blend() - Сохраните в файл то, что получилось. Это картинка смещённая влево.