Графика и аудио
Фильтры
Когда-то Instagram превратился из заурядной социальной сети в очень популярный феномен именно из-за удачной реализации встроенных фильтров. Фильтры можно было накладывать на фотографии, которые после этого обычно становились красивыми, похожими на профессиональные.
Фильтры очень широко применяются в киноиндустрии. Сравните цветовую гамму молодежных комедий или современных блокбастеров, например, с классическим «Шерлоком Холмсом».
Иначе говоря, фильтры невероятно востребованы — начиная от самых простых и заканчивая работами с привлечением искусственного интеллекта: например, в проекте Prisma.
Фильтр можно воспринимать как любое преобразование заданного изображения.
Чтобы добиться лучшего эффекта, их можно накладывать последовательно.
В библиотеке PIL реализовано много встроенных фильтров и инструментов (вырезание, изменение размеров и т. д.). Фактически это такой программируемый мини-Photoshop, но мы попытаемся поработать с фильтрами самостоятельно, чтобы поучиться восприятию цветовой палитры и алгоритмизации.
Для начала попробуем превратить изображение в черно-белое.
Черно-белое
Черно-белое изображение содержит только информацию о яркости, но не о цветах. У таких изображений все три компоненты имеют одинаковое значение, поэтому мы можем просто «размазать» суммарную яркость пикселя поровну по трем компонентам.

Можно сказать, что мы слили содержимое контейнеров R, G, B в одну емкость, а затем разлили обратно, но уже поровну в каждый контейнер. Суммарная яркость пикселя осталась прежней, но информация о цвете не сохранилась. Фотография же стала более «задумчивой». Попробуем поменять местами зеленый и синий каналы:
Смена цветов

Негатив
Давайте подумаем над тем, как получить негатив. Если в позитиве белое изображение (255), в негативе должно быть черное (0) и наоборот. То есть для значения х негативом будет 255 — x.

Как видим, в негативе можно рассмотреть некоторые детали, которые не видны в позитиве.
Кривые
Во многих редакторах, включая Photoshop, есть инструмент «Кривые» (Curves).
Он позволяет задать функцию, меняющую яркость всего пикселя или отдельной компоненты в зависимости от исходной яркости. Изначально эта функция представляет собой прямую y = x.
В Python можно написать функцию, которая работает как инструмент Curves. Например, мы можем высветлить темные участки в изображении, не трогая светлые. Это очень частая операция: например, когда на снимке светлое небо и очень темное здание, потому что фотоаппарат подстроился под яркость неба.

«Высветлить» означает увеличить значения всех цветовых компонентов на какой-то коэффициент. Важно помнить, что эти значения не могут быть больше 255.

Готовые функции PIL
Как мы уже говорили раньше, в PIL есть большое число встроенных инструментов для изменения изображений. Продолжим эксперименты над нашим изображением совы.
resize — изменение размера
Мы можем изменить размер изображения с помощью функции resize, в которую кортежем передается новый размер изображения. Обратите внимание: все подобные функции не изменяют исходное изображение, а возвращают его измененную копию.

crop — обрезка
С помощью функции crop вырезать прямоугольный кусочек из изображения. В функцию передаются координаты верхнего левого и правого нижнего угла вырезаемого прямоугольника одним кортежем.

quantize — квантование цвета
Функция quantizeиспользуется для сокращения цветов в палитре изображения и используется для создания миниатюр для предпросмотра. Принимает на вход число меньшее 256 — количество цветов. Обратите внимание: эта функция также преобразовывает изображение в формат bmp.

transpose — отражение и поворот
В задачах прошлого урока вы пробовали вращать и отражать изображения, манипулируя пикселями напрямую, однако PIL содержит уже готовые реализации данных алгоритмов. Повороты и отражения изображения можно выполнить с помощью функции transpose, в которую передается тип преобразования. Это может быть отражение слева направо, или сверху вниз, или повороты на 90, 180 или 270 градусов.

Благодаря тому, что преобразование возвращает измененное изображение, можно создавать цепочки преобразований.
GaussianBlur — размытие по Гауссу
Библиотека PIL содержит в себе много любопытного: например, в модуле ImageOps есть встроенные реализации превращения изображения в негатив (функция invert) и в черно-белое изображение (функция grayscale), а в модуле ImageFilter находятся встроенные интересные фильтры изображений, один из которых мы рассмотрим. Этот фильтр называется размытие Гаусса и принимает на вход радиус размытия.
Модуль wave
Фильтры можно накладывать не только на изображения, но и на звуковые файлы. Для манипуляции с «сырыми», необработанными аудиоданными предназначен модуль wave. В ОС Windows такие данные хранятся в файлах с расширением .wav.
«Сырые» аудиоданные представляют собой зависимость амплитуды звукового сигнала от времени. Посмотрите на график этой зависимости. Вы часто видели его в фильмах, репортажах журналистов и т. д.
Вдоль оси абсцисс откладывается время, вдоль оси ординат — амплитуда (интенсивность, громкость) звукового сигнала.
Этот график строится по точкам, причем вместо пар (t, y) хранятся только значения y, а ось абсцисс задана частотой дискретизации (количеством отсчетов в секунду) — как правило, она составляет 44 100 Гц. Такой частоты достаточно, чтобы человек мог прослушать оцифрованный звук и не заметить его отличия от реального.

Получается, что представление звукового файла для программиста очень простое. Это список целых чисел (положительных и отрицательных) — значений амплитуды звукового сигнала.
В следующем примере мы рассмотрим основные этапы работы со звуковым файлом. Наша программа будет разворачивать звуковой файл в обратную сторону, то есть проигрывать музыкальное произведение задом наперед.
Файл для примера можно скачать по ссылке
Мы открываем два файла: исходный source и формируемый dest.
Одно значение амплитуды в терминах библиотеки wave называется фреймом.
Наибольшую трудность здесь представляют строки с использованием встроенного модуля struct. Пока договоримся, что функции этого модуля могут на лету распаковывать и запаковывать данные разной природы.
Модуль struct позволяет паковать и извлекать несколько значений в бинарные структуры. Это чем-то похоже на структуры в С. В примере со звуковыми волнами значение y хранится как знаковое двухбайтное число. Поэтому извлечение выглядит так странно.
Интересно, что палиндромы в аудиофайлах сохраняют свою «палиндромность» (например, «А роза упала на лапу Азора»).
Что еще можно сделать?
-
Если мы уберем, например, каждый второй фрейм, ускорим воспроизведение вдвое. При этом частота тоже вырастет в два раза (и вы услышите голоса Чипа и Дейла). Кстати, на телевидении и радио часто ускоряют видео и аудио на 5-10%: это незаметно для уха, но позволяет разместить больше рекламы в эфире
-
Если мы увеличим все фреймы в какое-то количество раз, сделаем произведение громче, а если уменьшим — тише.
-
Копируя каждый фрейм два раза, мы замедлим воспроизведение и понизим частоту
-
Если вы заинтересовались обработкой аудиофайлов, обратите свое внимание на библиотеки pydub и librosa.
Задачи
Задача 1
Напишите программу, которая открывает изображение и переводит его в оттенки серого, усредняя значения R, G и B. Сохраните результат в файл result.jpg.
Тест 1:
Ввод:
Вывод:Тест 2:
Ввод:
Вывод:Задача 2
Напишите программу, которая создаёт негатив изображения (каждый пиксель заменяется на 255 - значение по каждому каналу). Сохраните результат.
Тест 1:
Ввод:
Вывод:Тест 2:
Ввод:
Вывод:Задача 3
Напишите программу, которая меняет местами красный и синий каналы каждого пикселя изображения. Сохраните результат в swapped.jpg.
Тест 1:
Ввод:
Вывод:Тест 2:
Ввод:
Вывод:Задача 4
Напишите функцию make_thumbnail(filename, max_size), которая открывает изображение и уменьшает его так, чтобы большая сторона не превышала max_size пикселей (сохраняя пропорции). Сохраните результат в thumb.jpg.
Тест 1:
Ввод:
Вывод:Тест 2:
Ввод:
Вывод:Задача 5
Напишите программу, которая вырезает центральный квадратный фрагмент изображения со стороной, равной меньшей стороне изображения. Сохраните результат в cropped.jpg.
Тест 1:
Ввод:
Вывод:Тест 2:
Ввод:
Вывод:Задача 6
Напишите функцию apply_blur(filename, radius), которая применяет размытие по Гауссу с указанным радиусом и сохраняет результат в blurred.jpg.
Тест 1:
Ввод:
Вывод:Тест 2:
Ввод:
Вывод:Задача 7
Напишите программу, которая делает изображение «ярче»: увеличивает каждый цветовой канал каждого пикселя на 50, не превышая значения 255.
Тест 1:
Ввод:
Вывод:Тест 2:
Ввод:
Вывод:Задача 8
Напишите функцию count_frames(filename), которая открывает WAV-файл и возвращает количество кадров, частоту дискретизации и длительность (в секундах, округлённую до 2 знаков).
Тест 1:
Ввод:
Вывод:Тест 2:
Ввод:
Вывод:Задача 9
Напишите программу, которая изменяет громкость WAV-файла в factor раз (аргумент задаётся в коде). Значения амплитуды должны оставаться в диапазоне от −32767 до 32767.
Тест 1:
Ввод:
Вывод:Тест 2:
Ввод:
Вывод:Задача 10
Напишите программу, которая применяет к изображению последовательность из трёх фильтров: сначала переводит в чёрно-белое, затем создаёт негатив, и наконец применяет размытие по Гауссу с радиусом 2. Каждый промежуточный результат сохраняется в отдельный файл (step1.jpg, step2.jpg, step3.jpg).
Тест 1:
Ввод:
Вывод:Шаг 1 (ч/б): сохранено step1.jpg
Шаг 2 (негатив): сохранено step2.jpg
Шаг 3 (размытие): сохранено step3.jpg
Тест 2:
Ввод:
Вывод: