Вращение изображения в PyQt5
Нужно открыть картинку и вращать ее по часовой стрелке по команде. Вот мой код, в который нужно вставить данную фичу:
#!/usr/bin/python3 # -*- coding: utf-8 -*- import sys from PyQt5.QtWidgets import (QWidget, QInputDialog, QPushButton, QApplication, QTextEdit, QLabel, QLineEdit,QFrame ) from PyQt5.QtGui import QBrush, QPalette, QPixmap, QPainter, QPen, QImage from PyQt5.QtCore import Qt, QTimer, QPointF, QRect from PIL import Image class Collector(QWidget): def __init__(self): super().__init__() self.timer = QTimer() self.timer.timeout.connect(self.process_timeout) self.timer.start(10) # 50 -- период в милисекундах self.phi = 0 self.lbl = QLabel(self) def process_timeout(self): if self.phi == 0: self.phi += 5 elif self.phi == 5: self.phi -= 5 self.update() def showInputTc_h(self): text, ok = QInputDialog.getText(self, "input Dialog", "Enter data:") if ok: self.textEdit_Tc_h.setText(str(text)) def showInputTr(self): text, ok = QInputDialog.getText(self, "input Dialog", "Enter data:") if ok: self.textEdit_Tr.setText(str(text)) def showInputTt(self): text_Tt, ok = QInputDialog.getText(self, "input Dialog", "Enter data:") if ok: self.textEdit_Tt.setText(str(text_Tt)) def lable_text_button(self): Tt = QPushButton("Tt", self) Tt.move(480, 130) Tc_h = QPushButton("Tc-h", self) Tc_h.move(400, 10) Tr = QPushButton("Tr", self) Tr.move(900, 530) self.textEdit_Tt = QLineEdit(self) self.textEdit_Tt.setGeometry(QRect(100, 90, 81, 31)) self.textEdit_Tt.setObjectName("textEdit") self.textEdit_Tt.move(400, 130) Tt.clicked.connect(self.showInputTt) self.textEdit_Tr = QLineEdit(self) self.textEdit_Tr.setGeometry(QRect(100, 90, 81, 31)) self.textEdit_Tr.setObjectName("textEdit") self.textEdit_Tr.move(800, 530) Tr.clicked.connect(self.showInputTr) self.textEdit_Tc_h = QLineEdit(self) self.textEdit_Tc_h.setGeometry(QRect(100, 90, 81, 31)) self.textEdit_Tc_h.setObjectName("textEdit") self.textEdit_Tc_h.move(300, 10) Tc_h.clicked.connect(self.showInputTc_h) def get_image_size(self, img): im = Image.open(img) (width, height) = im.size return (width, height) # вернем ширину и висоту def draw_y(self, qp, x0, y0, range_int, const_y): for i in range(range_int): y0 -= 20 * i x1 = x0 y1 = y0 + 10 qp.drawLine(QPointF(x0, y0), QPointF(x1, y1)) y0 = const_y def draw_x(self, qp, x0, y0, range_int, const_x): for i in range(range_int): x0 += 20 * i y1 = y0 x1 = x0 + 10 qp.drawLine(QPointF(x0, y0), QPointF(x1, y1)) x0 = const_x def paintEvent(self, e): qp = QPainter() qp.begin(self) pen = QPen(Qt.red, 1) qp.translate(0, self.height()) qp.scale(1, -1) qp.setPen(pen) pomp = QPixmap() QFrame.paintEvent(self, e) # width1 = 992, # height = 679 list_y = [(292, 627, 12), (292, 320, 4), (485, 595, 2), (183, 183, 7), (465, 40, 3)] list_x = [(150, 637, 7), (310, 385, 6), (486, 607, 27), (183, 64, 14), (480, 64, 6), (690, 64, 16)] for y in list_y: self.draw_y(qp=qp, x0=y[0], y0=y[1]+self.phi, range_int=y[2], const_y=y[1]+self.phi) for x in list_x: self.draw_x(qp=qp, x0=x[0]+self.phi, y0=x[1], range_int=x[2], const_x=x[0]+self.phi) pen = QPen(Qt.blue, 1) qp.setPen(pen) list_y_cold = [(5, 627, 15), (240, 386, 3), (183, 317, 4), (296, 183, 2), (485, 312, 3), (652, 562, 15)] list_x_cold = [(10, 347, 3), (113, 347, 3), (199, 347, 6), (345, 347, 4), (296, 153, 37), (485, 272, 26), (656, 570, 18)] for y_cold in list_y_cold: self.draw_y(qp=qp, x0=y_cold[0], y0=y_cold[1]+self.phi, range_int=y_cold[2], const_y=y_cold[1]+self.phi) for x_cold in list_x_cold: self.draw_x(qp=qp, x0=x_cold[0]+self.phi, y0=x_cold[1], range_int=x_cold[2], const_x=x_cold[0]+self.phi) qp.end() def main(): app = QApplication(sys.argv) w = Collector() palette = QPalette() palette.setBrush(QPalette.Background, QBrush(QPixmap("images/scheme.jpg"))) size = w.get_image_size("images/scheme.jpg") w.setMaximumSize(size[0], size[1]) w.setMinimumSize(size[0], size[1]) w.setWindowTitle('Sun') w.setPalette(palette) w.lable_text_button() w.show() sys.exit(app.exec()) if __name__ == '__main__': main()
Обработка и генерация изображений в Python. Библиотека Pillow
Нередко нам нужно изменить размер картинки, кропнуть ее, наложить текст и так далее. Все это можно автоматизировать с помощью Python и библиотеки Pillow.
Установка Pillow
Установка производится через pip3. Вводим в консоль:
pip3 install pillow
Комьюнити теперь в Телеграм
Подпишитесь и будьте в курсе последних IT-новостей
Начало работы с библиотекой
Для начала нам нужно инициализировать библиотеку в нашем скрипте:
from PIL import Image
В папку со скриптом поместим произвольное изображение. Файл назовем test.jpg.
Теперь откроем изображение через метод в библиотеке:
from PIL import Image img = Image.open('test.jpg') img.show()
На экране у нас отобразилось изображение, которое мы добавили в папку:
Для просмотра основной информации об изображении с помощью Pillow используем следующие методы:
from PIL import Image img = Image.open('test.jpg') print(img.format) # Просмотр формата изображения. Выведет 'JPEG' print(img.mode) # Просмотр типа цветового пространства. Выведет 'RGB' print(img.size) # Просмотр размера изображения. Выведет (568, 305) print(img.filename) # Просмотр имени файла. Выведет 'test.jpg' r, g, b = img.split() histogram = img.histogram() print(histogram) # Просмотр значений RGB изображения. Выведет 1750, 255, 267, 237, 276, 299…
Обрезка изображений
В Pillow есть методы для кропа (обрезки) изображений. Обрежем наше изображение с помощью метода crop(), передав в параметры координаты обрезки:
from PIL import Image img = Image.open('test.jpg') cropped = img.crop((0, 0, 100, 200)) cropped.save('cropped_test.jpg') img = Image.open('cropped_test.jpg') img.show()
После выполнения данного кода, получим следующее изображение:
Поворот изображений
С помощью метода Image.rotate() мы можем поворачивать изображение как нам угодно. В скобках указываем количество градусов, на которое нужно повернуть изображение. Рассмотрим на примере:
from PIL import Image img = Image.open('test.jpg') rotated = img.rotate(180) rotated.save('rotated_test.jpg') img = Image.open('rotated_test.jpg') img.show()
Конвертируем из JPG в PNG с помощью Pillow
Для конвертации нам понадобится открыть изображение и просто сохранить его в другом формате. Рассмотрим на примере:
from PIL import Image img = Image.open('test.jpg') img.save('test_png.png', 'png')
Получаем такое же изображение, но в формате PNG.
Изменение размера изображений
Чтобы изменить размер изображения используем метод resize(). Рассмотрим это на примере:
from PIL import Image img = Image.open('test.jpg') img = img.resize((170, 100), Image.ANTIALIAS) img.save('test_text.jpg') img = Image.open('test_text.jpg') img.show()
Пишем текст на изображениях
Для наложения текста на изображение в Pillow существует метод text(), но для начала нужно добавить шрифт. Рассмотрим на примере:
from PIL import Image, ImageDraw, ImageFont img = Image.open('test.jpg') font = ImageFont.truetype("arial.ttf", size=20) idraw = ImageDraw.Draw(img) idraw.text((25, 25), 'TEST test TeSt', font=font) img.save('test_text.jpg') img = Image.open('test_text.jpg') img.show()
Получим изображение с текстом:
Генерация пустого изображения
Для создания пустого холста (изображения) используем метод Image.new(). Рассмотрим на примере:
from PIL import Image, ImageDraw, ImageFont img = Image.new('RGB', (200, 200), 'black') img.save('test1.jpg') img = Image.open('test1.jpg') img.show()
Получаем черный квадрат:
Теперь давайте нарисуем на этом квадрате белый прямоугольник:
from PIL import Image, ImageDraw, ImageFont img = Image.new('RGB', (200, 200), 'black') idraw = ImageDraw.Draw(img) idraw.rectangle((0, 0, 100, 100), fill='white') img.save('test1.jpg') img = Image.open('test1.jpg') img.show()
Вывод
Мы разобрали основные методы библиотеки Pillow в Python: научились писать текст на изображениях, изменять размер, поворачивать их и даже обрезать.
Надеюсь, статья была полезна для вас. Удачи!
Создание вращающегося логотипа с помощью ImageMagick и FFMPEG
Статья может заинтересовать тех, кто хочет слегка оживить оформление своего видеоканала, а также тех, кто только начал работать с указанными в заголовке инструментами. Уверенные же пользователи, рассчитываю, дополнят мой материал.
Задумался, как можно оживить логотип, который накладываю на видеоролики неких спортивных мероприятий. Возникла идея сделать поворачивающийся вокруг своей вертикальной оси каждые секунд 20 логотип. В результате хотелось получить нечто подобное:
Для выполнения задачи понадобится система с установленными imagemagick и ffmpeg. Для формирования команд утилите imagemagick будет использоваться bash. Что повлечет за собой использование утилиты bc, т.к. математика в bash довольно простая и тригонометрические функции вычислить затруднительно.
С помощью python, например, тоже самое сделать еще проще, в нем-то синус и косинус вычисляются.
Для создания видео создадим N кадров, за которые логотип сделает полный оборот, затем превратим их в видеофайл.
По сути, вращение — это последовательное сжатие и расширение изображения по одному из измерений. Если мы хотим получить эффект равномерного вращения вокруг вертикальной оси — ширина изображения будет изменяться кратно значению функций синус или косинус.
Начальное состояние для нас — это видимый в полный размер логотип, поэтому для изменения ширины изображения будем умножать его ширину на косинус (его значение в нуле как раз равно единице).
Вращение изображения для данных целей можно поделить на 4 этапа:
— изображение сужается;
— расширяется, но к зрителю повернуто обратной стороной;
— сужается обратной стороной к зрителю;
— расширяется до исходных размеров.
Сформируем базовый набор кадров построим для вращения на 0-90 градусов, а кадры для остальных 270 получим немного их преобразовывая. Цикл, соответственно, будет не от 0 до 360 градусов, а от 0 до 90.
Пропишем путь к нашему логотипу, чтобы потом обращаться к нему коротким $logo:
logo=../../logo/Moto_Gymkhana_transparent.png
Для удобства введем переменные равные ширине и высоте логотипа, так будет проще подправить скрипт под другую картинку:
width=842 height=595
Заведем переменную, равную количеству кадров, за которые логотип совершит четверть оборота. Она понадобится один раз — для вычисления шага, с которым должен вычисляться угол поворота.
Frames=15
В цикле понадобится:
— вычислить, какова будет ширина изображения при его повороте на заданный переменной «n» угол;
— создать пустой холст размером, скажем 850×600;
— добавить в его центр сжатое по ширине изображение.
for (( n=0; n
Разберем код по частям.
Вычислить ширину изображения под данным углом:
oWidth=$(printf %.$2f $(echo "$width*(c($n*4*a(1)/180))+1" | bc -l))
Удобнее будет разбирать этот кусок справа налево:
"| bc -l" указывает, что вычисляться это будет утилитой bc.
Т.к. косинус в утилите «bc» принимает на вход значения в радианах, а числа пи в bash нет — используем следующее выражение:
c($n*4*a(1)/180) — где
«c» — косинус,
$n — угол в градусах узменяющийся в цикле;
a(1) — арктангенс единицы, равный пи/4. Поэтому 4*a(1) это способ записать число пи. На 180 делим чтобы перейти от радиан к градусам.
Таким образом, "$width*(c($n*4*a(1)/180))" — ширина умноженная на косинус угла «n».
"+1" после этого выражения для того, чтобы ширина изображения не принимала значения 0. Попытку сделать изображение нулевой ширины не поймет ImageMagick.
$(printf %.$2f $(echo "$width*(c($n*4*a(1)/180))+1" | bc -l)) — вычислить значение ширины для данного угла и вывести, округлив до целого.
convert -size 850x600 xc:transparent -background none \ \( -alpha set -channel A -evaluate add -60% $logo -geometry $oWidth\ x$height\! \)\ -gravity center -composite ./tmp/$n.png
convert -size 850x600 xc:transparent -background none — создать прозрачный холст размером 640x360 без заднего фона.
Последующая часть команды взята в экранированные "\" скобки чтобы она выполнялась изолированно. Это важно, иначе изменение размера коснется и холста.
-alpha set — включить канал прозрачности.
-channel A -evaluate add -60% — добавить к значению канала А всех пикселей изображения "-60%".
$logo- путь к изображению.
-geometry $oWidth\ x$height\! — изменить размер изображения.
"-geometry AxB" изменит размеры изображения, но сохранит соотношение сторон. Т.е. если мы попытаемся убавить ширину — высота изображения тоже уменьшится чтобы сохранить соотношение «ширина х высота», а выше и ниже появятся пустые области.
"-geometry AxB\!" не бедут пытаться сохранить соотношение «ширина х высота», а изменит их независимо друг от друга.
-gravity center — разместить посередине.
-composite — объединить изображения.
./tmp/$n.png — сохранить файл в папку «tmp», назвав текущим значением переменной «n».
Вид с угла в 54 градуса:
Из этого эталонного набора изображений создадим 4 кадра будущей анимации.
Пусть логотип вращается по часовой стрелке если смотреть сверху. Для придания объема изображению добавим «тень» сдвинутую вправо или влево в зависимости от того, куда на кадре вращается изображение. И отразим изображение слева-направо на кадрах, где логотип повернут к зрителю задней стороной. «Тень» на этих же кадрах будет добавлена не под исходное изображение, а поверх него, чтобы создать эффект оборотной стороны логотипа.
Рассмотрим подробно выражение для первой четверти поворота. Остальные будут понятны по аналогии. Лишь акцентирую внимание на отличиях от первого:
convert tmp/$n.png \ \( +clone -background '#cccf' -shadow 100x8+$shadowShift-3 \)\ -background none -compose Src_Over -layers merge \ -gravity center tmp/logo$(expr $(( 1000+n ))).png
convert tmp/$n.png — взять за основу исходное изображение.
\( +clone -background '#cccf' -shadow 100x8+$shadowShift-3 \) — склонировать и создать тень изображения.
Цвет заданный опцией background задаст цвет тени.
Насколько тень непрозрачна (в процентах) и размыта задается параметром «100x5».
Сдвиг тени относительно оригинального изображения задается как +x+y. В нашем случае сдвиг по вертикали постоянен (3 пикселя вверх), а сдвиг по горизонтали задается переменной shadowShift.
Значение этой переменной вычислим аналогично сжатию исходного кадра по вертикали. Только возьмем синус угла, а не косинус, т.к. сдвиг при нулевом угле должен быть ноль.
shadowShift=$(printf %.$2f $(echo «15*(s($n*4*a(1)/180))+1» | bc -l))
Для первой и второй четверти тень должна быть сдвинута вправо, поэтому значение shadowShift берем со знаком «плюс», для третьей и четвертой — со знаком «минус».
-background none -compose Dst_Over -layers merge -gravity center -depth 8 tmp/logo$(expr $(( 1000+n ))).png
Тут важная опция это -compose. Она задает какое из изображений будет расположено сверху.
Для первой четверти поворота, сверху располагается сам логотип, поэтому Dst_Over. Для второй и третьей четверти будет прописано Src_Over (тень сверху).
-layers merge -gravity center — совместить слои, расположить посередине.
tmp/logo$(expr $(( 1000+n ))).png — сохранить под именем logo + «1000+значение n» в папку tmp.
имя такое чтобы имена кадров сразу отсортировались в алфавитном порядке и их было удобно отдать на обработку ffmpeg'у.
Для кадров второй четверти поворота будет «1800-n», для третьей «2000+n», для четвертой «2800-n».
Для второй и третьей четвертей появится опция -flop — отразить изображение слева-направо. Из-за этого, кстати, понадобится изменить знак смещения тени на противоположный.
Код для всех четырех четвертей поворота:
convert tmp/$n.png \( +clone -background '#cccf' -shadow 100x8+$shadowShift-3 \) \ -background none -compose Dst_Over -layers merge -gravity center -depth 8 tmp/logo$(expr $(( 1000+n ))).png convert tmp/$n.png \( +clone -background '#cccf' -shadow 100x8-$shadowShift-3 \) \ -background none -compose Src_Over -layers merge -gravity center -flop tmp/logo$(expr $(( 1800-n ))).png convert tmp/$n.png \( +clone -background '#cccf' -shadow 100x8+$shadowShift-3 \) \ -background none -compose Src_Over -layers merge -gravity center -flop tmp/logo$(expr $(( 2000+n ))).png convert tmp/$n.png \( +clone -background '#cccf' -shadow 100x8-$shadowShift-3 \) \ -background none -compose Dst_Over -layers merge -gravity center tmp/logo$(expr $(( 2800-n ))).png
В результате из исходного кадра получены 4 с небольшими отличиями:
Теперь дело за малым, собрать из этих изображений видео:
ffmpeg -pattern_type glob -i 'tmp/logo*.png' -pix_fmt argb -vcodec qtrle -r 30 rotatingLogo.mov
-pattern_type glob — позволяет задать маску имени кадра в привычном по консоли виде
-i 'tmp/logo*.png' — взять как исходные данные изображения из папки tmp чье имя начинается с «logo»
-pix_fmt argb — задать формат изображения с прозрачностью. «a» в ARGB — это как раз альфа-канал
-vcodec qtrle — задать кодек для видео поддерживающий прозрачность. Из известных мне это «qtrle» и «png»
-r 30 — задать частоту итогового видео 30 кадров в секунду.
rotating_logo.mov — сохранить под именем «rotatingLogo.mov»
Теперь можем выполнить команду
ffplay rotatingLogo.mov
и посмотреть на результат:
Получившееся видео длинной всего в пару секунд, т.ч. совместим множество таких кусков вместе.
Для этого используем тот же ffmpeg.
Чтобы логотип вращался не постоянно, а эпизодически создадим кусок видео с неподвижным логотипом. Для статьи пусть будет длительностью в 3 секунды, чтобы не приходилось долго ждать вращения при просмотре:
ffmpeg -loop 1 -pattern_type glob -i 'tmp/logo1000.png' -pix_fmt argb -vcodec qtrle -r 30 -t 3 stillLogo.mov
В этой команде появилась опция "-loop 1" — указывающая ffmpeg повторять входную последовательность изображений (в данном случае одно единственное), и опция "-t 3" указывающая, что продолжительность итогового видео 3 секунды.
Чтобы склеить видео с неподвижным и вращающимся логотипом, создадим файл со списком файлов, которые нужно склеить. В данном случае 20 экземпляров наших файлов:
for (( i=0; i> list.txt echo file 'rotatingLogo.mov' >> list.txt done
Подадим этот файл на вход фильтру concat с указанием копировать кодеки, а не перекодировать (-c copy).
ffmpeg -f concat -i list.txt -c copy logoWithRotation.mov
Осталось наложить получившийся логотип на видео.
Логотип довольно большой, т.ч. при наложении отмасштабируем его, уменьшив в три раза.
ffmpeg -i video.mov -i logoWithRotation.mov \ -filter_complex "[1:0]scale=iw/2:ih/2[logo];[0:0][logo]overlay=shortest=1:x=20:y=500" \ -vcodec libx264 -crf 18 overlay.mov
ffmpeg -i video.mov -i logoWithRotation.mov — взять на вход два видео.
-filter_complex — использовать filter_complex которому мы указываем, следующее:
[1:0]scale=iw/3:ih/3[logo] — взять поток 0 из второго видео (1 отсчет идет с нуля) и уменьшить значения ширины (iw — input width) и высоты (ih — input height) втрое. Передать дальше под именем «logo».
[0:0][logo]overlay=shortest=1:x=20:y=0 — взять поток 0 из первого видео и поток «logo» и наложить их друг на друга.
«shortest=1» — говорит, прекратить по достижении конца любого из потоков.
x=20:y=500 — указывает где располагать левый верхний угол накладываемого видео.
-vcodec libx264 -crf 18 — использовать кодек H264. Значение после crf указывает насколько сильно сжимать. 0 — вообще без сжатия.
overlay.mov — сохранить под этим именем.
ffplay overlay.mov
Рисунки и анимация для статьи созданы с помощью тех же инструментов. В порядке появления в статье:
ffmpeg -i rotatingLogo.mov -filter_complex "[0:0]scale=iw/3:ih/3" rotatingLogo.gif montage tmp/54.png -geometry 300x200 result.png montage -mode concatenate -tile 2x2 tmp/logo1054.png tmp/logo1746.png tmp/logo2054.png tmp/logo2746.png -geometry 300x200 result.png ffmpeg -i logoWithRotation.mov -t 5.5 -filter_complex "[0:0]scale=iw/3:ih/3" logoWithRotation.gif
Итоговый скрипт для создания вращающегося логотипа:
logo=../../logo/Moto_Gymkhana_transparent.png Frames=15 width=842 height=595 mkdir tmp for (( n=0; n> list.txt echo file 'rotatingLogo.mov' >> list.txt done ffmpeg -f concat -i list.txt -c copy logoWithRotation.mov
Наложение на файл video.mov с уменьшением логотипа в три раза:
ffmpeg -i video.mov -i logoWithRotation.mov -filter_complex "[1:0]scale=iw/3:ih/3[logo];[0:0][logo]overlay=shortest=1:x=20:y=500" -vcodec libx264 -crf 18 overlay.mov
Вращаем изображение в Python через Pillow
Работа с изображением – необходимая составляющая любой программы. В этом нет ничего удивительного, поскольку в свое время именно графические интерфейсы стали ключевым этапом перехода от командной строки до операционных систем в том виде, котором мы их знаем. И картинки являются основополагающей составляющей таких интерфейсов.
Если вы хотите поворачивать изображение на определенный градус, необходимо воспользоваться методом rotate() из модуля Image . Сегодня рассмотрим такие важные аспекты его использования, как настройка угла вращения изображения, как осуществить полный поворот изображения, какие бывают фильтры и зачем они нужны, как изменять центр изображения в процессе его поворачивания, а также как смещать картинку при поворачивании.
Для работы с сегодняшним уроком нам понадобится следующая картинка:
Сохраните ее на свой компьютер. Она будет использоваться в приведенных ниже фрагментах кода.
Настройка угла вращения изображения
Для того, чтобы вращать картинку, необходимо сначала определиться с углом, на который будет осуществляться поворот. Для этого существует специальная функция, которую мы рассмотрим более подробно далее. Она является методом. Следовательно, вызывается из объекта image , через точку.
Но на данном этапе еще рано говорить об этом методе. Для начала необходимо сохранить картинку и открыть ее. Давайте теперь попробуем это сделать, для начала.. Для этого поместите его в тот каталог, в котором будет выполняться программа.
from PIL import Image im = Image.open('guido-van-rossum.jpg') im.show()
Если мы запустим этот код, будет показана скачанная на предыдущем этапе картинка.
Итак, что нам надо для настройки угла вращения изображения в Pillow? Прежде всего, воспользоваться методом rotate() , в качестве аргумента которого используется угол вращения картинки в градусах. Вращаться картинка будет против часовой стрелки.
Давайте для примера попробуем повернуть картинку на 90 градусов.
from PIL import Image im = Image.open('guido-van-rossum.jpg') im_rotate = im.rotate(90) im_rotate.save('guido_90.jpg', quality=95) im.close()
После того, как мы запустим этот фрагмент кода, мы получим изображение, которое будет повернуто на 90 градусов против часовой стрелки.
А теперь давайте повернем нашу картинку на 45 градусов. Для этого изменим код, который выше, таким образом, чтобы в качестве аргумента метода rotate() было число 45.
from PIL import Image im = Image.open('guido-van-rossum.jpg') im_rotate = im.rotate(45) im_rotate.save('guido_45.jpg', quality=95) im.close()
Как полностью повернуть изображение?
Обратите внимание, что стандартный размер готового изображения должен равняться размеру первоначального, а части повернутой картинки, которые попали за пределы изначального размера, отсекаются. А что же делать, если поставить параметр expand на True ? В этом случае картинка будет полностью помещаться в область видимости. По сторонам уже черных границ не будет.
Для того, чтобы убедиться в этом, попробуйте у себя запустить следующий код.
from PIL import Image im = Image.open('guido-van-rossum.jpg') im_rotate = im.rotate(90, expand=True) im_rotate.save('guido_expand_90.jpg', quality=95) im.close()
И наша картинка теперь будет такой. Обратите внимание, что действительно черных полос по бокам нет. Но так лишь в случае, если картинка расположена по одной из осей – абсцисс или ординат.
А вот если угол другой, например, если повернуть картинку на 45 градусов, то тогда избежать черных пространств за пределами картинки не получится. Это четко видно на картинке, которую мы привели выше.
Тем не менее, изображение все равно будет полностью помещаться в окне.
Попробуйте выполнить этот код, и вы убедитесь в этом самостоятельно.
Видим, что нет ничего сложного в том, чтобы повернуть изображение так, чтобы оно органично вписывалось в интерфейс программы.
Зачем нужны фильтры в Pillow?
При поворачивании изображения можно использовать фильтры, чтобы сделать получившуюся картинку более качественной. Для того, чтобы их задать, необходимо воспользоваться параметром resample . Фильтры, в свою очередь, могут быть следующими. Качество их работы зависит от картинки, которая используется. То есть, на одной картинке нет необходимости вообще использовать фильтр, отличный от того, который устанавливается по умолчанию. На другой же качество изображения можно значительно улучшить, если использовать его. Сами же фильтры, доступные для использования пользователем Python, следующие.
- Image.NEAREST – этот фильтр используется по умолчанию. Касается ближайшего соседа.
- Image.BILINEAR. Делает детали изображения более четкими при повороте по сравнению с предыдущим фильтром.
- Image.BICUBIC.
from PIL import Image im = Image.open('guido-van-rossum.jpg') im_rotate = im.rotate(45, expand=True, resample=Image.BICUBIC) im_rotate.save('guido_resample_bicubic.jpg', quality=95) im.close()
Давайте наглядно покажем разницу между этими фильтрами.
В случае с этой картинкой различия не так заметны, но они есть. Тем не менее, обратите, например, внимание на фильтр Image.BILINEAR . Картинка с его помощью стала более гладкой.
Изменение центра картинки при переворачивании
А что нужно делать, чтобы уточнить позицию центра изображения, которое добавляется в приложение? Для этого необходимо использовать параметр center в методе rotate() . Приведем для наглядности код, где это наглядно изображено.
from PIL import Image im = Image.open('guido-van-rossum.jpg') im_rotate = im.rotate(45, center=(0, 100)) im_rotate.save('guido_new_center.jpg', quality=95) im.close()
Здесь мы видим, что после того, как мы запустили этот код, позиция изображения изменилась по сравнению с той, которая была ранее. Попробуйте выполнить этот код, используя скачанную ранее картинку, и убедитесь в этом сами. Также можете потренироваться на любом другом изображении, разницы здесь особой нет для того, чтобы эффективно обучаться.
Если мы используем значение True для параметра expand , то область выходящего изображения определяется предположением, что изображение обращается, ориентируясь на свой изначальный центр.
from PIL import Image im = Image.open('guido-van-rossum.jpg') im_rotate = im.rotate(45, expand=True, center=(0, 100)) im_rotate.save('guido_new_center_expand.jpg', quality=95) im.close()
Смещение картинки во время поворота
Также человек, разрабатывающий приложение, может указать определенное смещение перед тем, как картинка будет поворачиваться. Для этого используется параметр translate . С его помощью можно добиться того, например, чтобы картинка после поворота оказалась в определенной части экрана. Таким образом можно добиться двух целей: повернуть изображение на определенный градус и переместить его. Нет необходимости отдельно прописывать две строчки кода, можно обойтись одной. Согласитесь, это удобно, не так ли?
Давайте теперь попробуем показать, как работает этот параметр, на практике. Для этого мы просто покажем то, какое смещение нам требуется. Да, функцию rotate() можно использовать и для обычного перемещения изображения в пределах экрана. Мы так и сделаем.
from PIL import Image im = Image.open('guido-van-rossum.jpg') im_rotate = im.rotate(0, translate=(100, 50)) im_rotate.save('guido_translate_0.jpg', quality=95) im.close()
В результате, наша программа будет выглядеть таким образом, как на этом изображении.
Если же нам нужно повернуть картинку на 45 градусов со смещением, то для этого необходимо просто задать нужный градус в качестве первого аргумента метода rotate() .
from PIL import Image im = Image.open('guido-van-rossum.jpg') im_rotate = im.rotate(45, translate=(100, 50)) im_rotate.save('guido_translate_45.jpg', quality=95) im.close()
Получим такой результат. Выглядит привлекательно, не так ли?
Если мы используем установим значение параметра expand на True , то для определения итоговой области картинки интерпретатор будет считать, что смещения нет.
Для демонстрации этого эффекта давайте приведем такой фрагмент кода.
from PIL import Image im = Image.open('guido-van-rossum.jpg') im_rotate = im.rotate(45, translate=(100, 50), expand=True) im_rotate.save('guido_translate_expand_45.jpg', quality=95) im.close()
В результате выполнения этих инструкций появится такая картинка. Вы можете самостоятельно в этом убедиться.
В этом примере, в отличие от предыдущего, черный фон находится как в верхнем левом углу, так и в правом нижнем. В прошлом же случае картинка размещалась от одного края окна до другого.
Выводы
Мы разобрали, как поворачивать изображения в Python, как использовать фильтры, перемещать картинку, каким образом можно полностью вписать изображение в окно, даже после поворачивания. Все это можно сделать с помощью метода rotate() . Он может использоваться как для поворота картинки, так и для ее смещения, и это очень удобно.
Попробуйте потренироваться с приведенным выше кодом таким образом. Поставьте себе задачу применительно к теме этой статьи. После этого подумайте, как сегодняшний материал может использоваться, применительно к вашей задаче. Тренировка – это важная составляющая обучения, поскольку именно во время нее совершение тех или иных действий доводится до автоматизма. В дальнейшем все будет делаться как бы само собой, без активных размышлений с вашей стороны.