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() сам подберёт новые координаты так, чтобы картинка поместилась в заданную область. Например, у вас есть картинка 800×1200 и вы хотите поместить её в рамку 1200×600, то результат метода будет 400×600, т.к. 400×600 как раз помещается в 1200×600:
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()
- Сохраните в файл то, что получилось. Это картинка смещённая влево.
Попробуйте бесплатные уроки по Python
Получите крутое код-ревью от практикующих программистов с разбором ошибок и рекомендациями, на что обратить внимание — бесплатно.
Переходите на страницу учебных модулей «Девмана» и выбирайте тему.
Четыре метода загрузки изображений с веб-сайта с помощью Python
Недавно пришлось по работе написать простенький парсер на питоне, который бы скачивал с сайта изображения (по идее тот же самый парсер может качать не только изображения, но и файлы других форматов) и сохранял их на диске. Всего я нашел в интернете четыре метода. В этой статье я их решил собрать все вместе.
1-ый метод
Первый метод использует модуль urllib (или же urllib2). Пусть имеется ссылка на некое изображение img. Метод выглядит следующим образом:
import urllib resource = urllib.urlopen(img) out = open(". \img.jpg", 'wb') out.write(resource.read()) out.close()
Здесь нужно обратить внимание, что режим записи для изображений — ‘wb’ (бинарный), а не просто ‘w’.
2-ой метод
Второй метод использует тот же самый urllib. В дальнейшем будет показано, что этот метод чуть медленнее первого (отрицательный оттенок фактора скорости парсинга неоднозначен), но достоин внимания из-за своей краткости:
import urllib urllib.urlretrieve(img, ". \img.jpg")
Притом стоит заметить, что функция urlretrieve в библиотеке urllib2 по неизвестным мне причинам (может кто подскажет по каким) отсутствует.
3-ий метод
Третий метод использует модуль requests. Метод имеет одинаковый порядок скорости выгрузки картинок с первыми двумя методами:
import requests p = requests.get(img) out = open(". \img.jpg", "wb") out.write(p.content) out.close()
При этом при работе с веб в питоне рекомендуется использовать именно requests вместо семейств urllib и httplib из-за его краткости и удобства обращения с ним.
4-ый метод
Четвертый метод по скорости кардинально отличается от предыдущих методов (на целый порядок). Основан на использовании модуля httplib2. Выглядит следующим образом:
import httplib2 h = httplib2.Http('.cache') response, content = h.request(img) out = open('. \img.jpg', 'wb') out.write(content) out.close()
Здесь явно используется кэширование. Без кэширования (h = httplib2.Http()) метод работает в 6-9 раза медленнее предыдущих аналогов.
Тестирование скорости проводилось на примере скачивания картинок с расширением *.jpg c сайта новостной ленты lenta.ru. Выбор картинок, подпадающих под этот критерий и измерение времени выполнения программы производились следующим образом:
import re, time, urllib2 url = "http://lenta.ru/" content = urllib2.urlopen(url).read() imgUrls = re.findall('img .*?src="https://habr.com/ru/articles/210238/(.*?)"', сontent) start = time.time() for img in imgUrls: if img.endswith(".jpg"): """реализация метода по загрузке изображения из url""" print time.time()-start
Постоянно меняющиеся картинки на сайте не повлияли на чистоту измерений, поскольку методы отрабатывали друг за другом. Полученные результаты таковы:
Метод 1, с | Метод 2, с | Метод 3, с | Метод 4, с (без кэширования, с) |
---|---|---|---|
0.823 | 0.908 | 0.874 | 0.089 (7.625) |
Данные представлены как результат усреднения результатов семи измерений.
Просьба к тем, кто имел дело с библиотекой Grab (и с другими), написать в комментариях аналогичный метод по скачиванию изображений с помощью этой и других библиотек.
- питон и парсинг
- изображения
Как сохранять картинки и файлы локально?
Как изменить код, чтобы по ссылкам, которые указывают например на картинки и архивы zip или rar, если они там встретятся, локально сохранились эти файлы и картинки отображались бы на скачанной странице, а не подгружались из интернета?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
import requests url = "https://сайт/" # headers = { "Accept": "*/*", "User-Agent": "Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1" } # req = requests.get(url, headers=headers) src = req.text #print(src) # распечатать код страницы полностью with open("sait.html", "w") as file: # записываем на жесткий диск полученный html file.write(src)
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:
Как загружать картинки в папку и сохранять название в бд?
Подскажите кто делал такое или дайте ссылку на туториал пожалуйста. Как загрузить картинку через.
Как сохранять сгенерированные файлы
Добрый вечер. Как задать путь для сохранения файла? Я указываю напрямую, так конечно не стоит.
Как сохранять файлы в формате Word?
Подскажите, как сохранять текстовку в DOC (Word-97)? И еще как искать текст по шаблону (пример.
Как с OpenFileDialog сохранять файлы в нужной кодировке?
Делаю так: saveFileDialog1.Filter = "Текстовые файлы (*.txt)|*.txt"; //.
Просто Лис
5321 / 3335 / 1021
Регистрация: 17.05.2012
Сообщений: 9,768
Записей в блоге: 9
Ну а как ты делаешь руками? Находишь ссылку и жмёшь на неё.
Так же и в питоне: внутри html находишь ссылку и скачиваешь контент по ней.
138 / 103 / 35
Регистрация: 28.11.2013
Сообщений: 346
Когда вы получили список ссылок, то сохраняете файлы в папку как объекты «wb»
1 2 3 4 5 6 7
import requests url = "http://craphound.com/images/1006884_2adf8fc7.jpg" response = requests.get(url) if response.status_code == 200: with open("my_picture/sample.jpg", 'wb') as f: f.write(response.content)
Добавлено через 11 минут
Чтобы найти все теги «img» можно воспользоваться командой
images = soup.findAll('img')
Пример кода:
Кликните здесь для просмотра всего текста
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
from bs4 import * import requests import os # CREATE FOLDER def folder_create(images): try: folder_name = input("Enter Folder Name:- ") # folder creation os.mkdir(folder_name) # if folder exists with that name, ask another name except: print("Folder Exist with that name!") folder_create() # image downloading start download_images(images, folder_name) # DOWNLOAD ALL IMAGES FROM THAT URL def download_images(images, folder_name): # initial count is zero count = 0 # print total images found in URL print(f"Total Image Found!") # checking if images is not zero if len(images) != 0: for i, image in enumerate(images): # From image tag ,Fetch image Source URL # 1.data-srcset # 2.data-src # 3.data-fallback-src # 4.src # Here we will use exception handling # first we will search for "data-srcset" in img tag try: # In image tag ,searching for "data-srcset" image_link = image["data-srcset"] # then we will search for "data-src" in img # tag and so on.. except: try: # In image tag ,searching for "data-src" image_link = image["data-src"] except: try: # In image tag ,searching for "data-fallback-src" image_link = image["data-fallback-src"] except: try: # In image tag ,searching for "src" image_link = image["src"] # if no Source URL found except: pass # After getting Image Source URL # We will try to get the content of image try: r = requests.get(image_link).content try: # possibility of decode r = str(r, 'utf-8') except UnicodeDecodeError: # After checking above condition, Image Download start with open(f"/images.jpg", "wb+") as f: f.write(r) # counting number of image downloaded count += 1 except: pass # There might be possible, that all # images not download # if all images download if count == len(images): print("All Images Downloaded!") # if all images not download else: print(f"Total Images Downloaded Out of ") # MAIN FUNCTION START def main(url): # content of URL r = requests.get(url) # Parse HTML Code soup = BeautifulSoup(r.text, 'html.parser') # find all images in URL images = soup.findAll('img') # Call folder create function folder_create(images) # take url url = input("Enter URL:- ") # CALL MAIN FUNCTION main(url)
как можно в python открывать, редактировать, и сохранять графические файлы?
Как я понимаю, по-разному. Вот, к примеру, с использованием библиотеки PIL(python imaging library):
# конвертируем картинку from PIL import Image, ImageDraw img = Image.open('pic.png') # открываем PNG img.save('pic.gif') # сохраняем как GIF # создаем картинку, пишем в неё текст и сохраняем from PIL import Image, ImageDraw text = "Abracadabra :)" # готовим текст color = (0, 100, 100) # создаем цвет img = Image.new('RGB', (100, 100), color) # создаем изображение imgDrawer = ImageDraw.Draw(img) imgDrawer.text((10, 20), text) # пишем на изображении наш текст img.save("pic.png") # сохраняем в PNG # проводим манипуляции с картинкой, получаем ее свойства from PIL import Image, ImageDraw img = Image.open('pic.png') #открываем изображение format = img.format #формат изображения size = img.size #размер изображения histogram = image.histogram() # получаем гистограмму
Библиотека позволяет осуществлять массу манипуляций с графическими форматами. Рекомендую также её форк — Pillow: как минимум, интересна существенно возросшей скоростью (для нас еще тем, что подддерживает, в отличие от PIL, формат PNG с одного из наших приборов).
Предупреждения:
- в версии Pillow 5.0 прекратилась поддержка питона 3.3!
- начиная с версии Pillow 5.3.0 наблюдается «странная» работа с многостраничными TIFF-файлами. Пока не разобрались, в чём же дело. Так что, если вы работаете с подобным форматом, рекомендую пока не пользовать версии 5.3.0 и выше
- (новое) В версии Pillow 6.0.0 прекратилась поддержка питона 3.4! Если зачем-то предпочитаете оставаться на 3.4, пользуйтесь версией 5.4.1
- (новое) В версии Pillow 6.0.0 убран ряд функций, ранее объявленных устаревшими. Большинство из них реализовано в модуле ImageFilter.
- (новое) Собственно, таблица совместимости Pillow и версий питона: