Настал небольшой отпуск и я решил посмотреть наконец несколько фильмов. В процессе просмотра меня посетило ощущение, что в современных фильмах что-то не так, что раньше трава была зеленее и тому подобное. Больше всего выделялось то, что на экране большую часть времени очень мало цветов (как правило, вообще два, оранжевый и голубовато-зелёный).
Я в таких своих наблюдениях оказался совсем не одинок, вот, например, критическая статья о злоупотреблении этими вашими Голливудами оранжевым и голубовато-зелёным. Однако, одиночные кадры - это не серьёзно для доказательства. Тут нужен научный подход. Как астроном-любитель я знаю, что информацию о цвете чего-либо принято сравнивать в виде спектра.
Хочется получить такой вот примерно "спектр" для целого видео. Осталось придумать, как это сделать.
Идея
Упрощённо, видео есть последовательность изображений. Каждое изображение - массив RGB значений цветов пикселей. Можно заметить, что в спектре есть две оси: цвет (или длина волны) по горизонтали и уровень сигнала по вертикали. Значит, необходимо превратить трёхмерный (RGB) цвет в одномерный. И тут на помощь приходит цветовая модель HSL, где для цвета есть только одно измерение - Hue, в дополнение к Saturation и Lightness.
Теперь, для каждого пикселя видео и соответствующего ему значения "чистого цвета" (Hue) нужно определить вес чистого цвета на основе значений Saturation и Lightness. В случае с Saturation всё понятно и просто - вес должен быть пропорционален насыщенности цвета. С Lightness немножко сложнее: начения 0% и 100% будут соответствовать чёрному и белому цветам вне зависимости от значения Hue, поэтому максимальный вес (1) должен быть для значения Lightness = 50%, снижаясь "по краям" до 0, так как совсем светлые и совсем тёмные оттенки должны иметь меньший вес. Таким образом, можно вывести формулу уровня цветового сигнала:
W (S, L) = S * (0.52 - (0.5 - L)2) / 0.52
Это значение W (weight) будет численной мерой, показывающей, насколько данный цвет выглядит ярким и выраженным. Далее, для получения спектра достаточно сложить все полученные из пикселей веса (W). Стоит отдельно заметить то, что полученный "вес выразительности" цвета всё-таки субъективен, так как зависимость от яркости (L) может быть иной, например линейной. Или какой-нибудь ещё. Но я считаю свой вариант довольно честным.
Реализация
Осталось реализовать всё это в коде и я решил сделать это на Golang. К счастью, все необходимые биндинги для превращения видео в отдельные кадры, конвертации RGB в HSL и прочего уже доступны. Исходное видео конвертируется в кадры с разрешением 256х144, то есть ~37 килопикселей. Чтобы избежать слишком задумчивого переваривания при скармливании больших видеофайлов код может пропускать промежуточные кадры, чтобы не превысить лимит количества обрабатываемых кадров (хард код 2712 на данный момент). То есть любое видео будет ограничено более-менее равномерной выборкой из 100 миллионов пикселей. Для цветовой статистики вроде бы должно быть достаточно. Есть небольшая проблема, что не все промежуточные кадры одинаково полезны могут быть успешно сконвертированы. Судя по всему это происходит при попадании на не-ключевые кадры. Это может немного уменьшать выборку из-за ошибок.
Изначально это была консольная утилита, получающая на вход имя видеофайла и сохраняющая файл спектра в файл с тем же именем плюс разрешение ".svg". Позже я также добавил простейший web-cервис и форму для upload видео файла в газоанализатор для получения "спектра". Сервис раздеплоен временно-бесплатно в первом попавшемся облаке, так что желающие могут попробовать немножко поэкспериментировать: https://moviespectrum.azurewebsites.net/.
На размер загружаемого видеофайла стоит ограничение 128 Мб, поэтому рекомендуется использовать не самое лучшее разрешение, тем более что оно слабо влияет на цветовую статистику и видео всё равно конвертируется в кадры 256х144 перед обработкой.
В облаке сервис работает на минимальных ресурсах и никак не приспособлен для масштабирования, так что если он вдруг приляжет вследствие хабраэффекта или по какой другой причине, то вы всегда можете собрать его из безисходников и запустить локально, например в докере: https://github.com/akurilov/moviespectrum
Также сначала была идея прикрутить это всё к тытубу, чтобы пользователь мог просто кинуть ссылку на видео, однако из-за инцидента с youtube-dl я решил не рисковать и отпилить всю подобную функциональность. Даже вспомнилось Unix-заклинание "один инструмент = одна функция" в качестве оправдания. Так что теперь придётся сначала скачать видео, а потом уже скармливать его.
Результаты
Возьмём в качестве baseline пару олдскульных фильмов и посмотрим на их "спектры".
1991 - Терминатор 2:
1994 - Форрест Гамп:
Теперь возьмём фильмы посвежее и сравним:
1999 - Матрица aka 50 оттенков зелёного, если не считать фиолетового артефакта:
2003 - Властелин колец:
2005 - Город грехов. В качестве малоцветного baseline:
2007 - Трансформеры. Очень малоцветный фильм, не считая фиолетового артефакта:
2009 - Аватар:
2013 - Обливион:
2019 - Джокер. Всё почти в красном цвете, но есть немножно зеленовато-голубого.
Выводы вы можете сделать самостоятельно. На мой взгляд, есть тенденция к обеднению цветов со временем.
Комментариев нет:
Отправить комментарий