Комментарии 33
sRGB - это и есть тот стандарт, которому следуют большинство производителей камер и дисплеев. Гамма-коррекция включена по умолчанию и таки работает более-менее правильно на большинстве устройств. Исключением можно считать только RGB-светодиоды, управляемые ШИМом (а также линейки и панели из них), где передаточная функция по умолчанию линейна.
Автор привёл ссылку на статью, где есть хорошая тестовая картинка. Если монитор правильно передаёт гамму sRGB, то все 8 квадратов должны выглядеть одинаково серыми (для лучшей оценки можно прищурить или расфокусировать глаза).
Также с её помощью можно проверить, правильно ли реализован ресайз в вашем браузере или графическом редакторе (при уменьшении изображения все квадраты также должны оставаться одинаково серыми).
Данное изображение корректно отображается только при 100% масштабе (или при целочисленном увеличении). При дробном коэффициенте воспринимаемая интенсивность меняется, т.к. алгоритмы ресайза не являются gamma-aware. На практике это не нужно, т.к. это вычислительно затратно, а эффект можно увидеть только на синтетических изображениях.
Гамма-коррекция - это костыль, оставшийся со времён ЭЛТ, и о ней нужно помнить при любой работе с графикой, когда в вычислениях участвует более одного пикселя. Учитывать её или нет, пользователь должен решать сам, но ПО должно её поддерживать, в этом заключается позиция автора.
Если изображение содержит множество мелких контрастных деталей, то при уменьшении или размытии без учёта гаммы оно получится не просто "мутным", но и тёмным. У Eric Brasseur есть хороший пример (нажимаем switch pictures - изображения Correct scaling и Incorrect scaling меняются местами). Гамма-коррекция имеет значение и при рендеринге текста (пример), и просто нужна для хорошего визуального результата алгоритма Ву.
Слева - линии, нарисованные в paint.net без коррекции; справа - то же изображение, но с применённой гаммой 0.45 и яркостью 216/255.
Этот костыль и сейчас актуален. Без гамма-корреции в 8битах градиенты в темных областях будут коцаные
Да, само устройство отображения передаёт цвет нелинейно. Связано это с тем, что человек воспринимает интенсивность света нелинейно, и градации яркости [0, 255] подобраны так, чтобы субъективное отличие между соседними градациями было одинаковым.
Стандартное значение гаммы = 2.2, то есть реальная яркость получается возведением значения пикселя в степень 2.2. При фотографировании, соответственно, делается обратное преобразование (возведение линейной яркости в степень 1/2.2).
Проблемы возможны, если цветовое пространство монитора отличается от sRGB. В этом случае программа извлекает профиль монитора и производит преобразование цветовых пространств, чтобы корректно отобразить изображение.
гамма это некая кривая которая точно определена. если не ошибаюсь это что то вроде степенной функции. я хочу сказать, что это гладкая кривая, причем точно математически определенная. в таком случае нет разницы в каком цветовом пространстве работать. просто добавьте "гамма коррекцию" в свои расчёты. эта задача решается всеми софтами для работы с видео или изображениями. и у всех всё нормально, а вам почему то это не нравится. нет, вы можете считать что весь мир не прав и все в мире считают цвет не корректно - тогда работайте как описали. но в целом я вижу проблему на пустом месте. Если вы пишите математику - то пишите уж правильно, с гаммой и всеми прочими методами. Добавьте distortion grid, не по математике, а снятый с реальных камер которыми пользуетесь. Если вы всё это делаете уже - так почему бы и с гаммой не работать? математика с гаммой такая же как и без гаммы - просто формула другая. Это не какая то хаотичная формула с разными коэффициентами для каждого из 256 значений 8ми битного пространства. это гладкая функция применение которой даёт одинаковый результат при одинаковых входящих параметрах. сама кривулька не является секретной или запатентованной - пользуйтесь на здоровье как и все в мире. зачем строить велосипед если просто надо изучить матчасть?
Мне не очень понятен язвительный тон вашего комментария. Проблема заключается в том, что люди действительно не знают матчасть. Существующие фреймворки позволяют работать с изображениями по принципу "тяп-ляп и в продакшн", и чаще всего получается хорошо. А автор статьи просто указал на важный момент, как сделать ещё лучше.
Статьи на которые ссылается автор однозначно показывают, что проблема актуальна даже для таких авторитетных программ как фотошоп и прочих, даже при простых операциях, как уменьшение/увеличение и учитывать гамму в инструментах программ не получится.
Если вы пишите математику - то пишите уж правильно, с гаммой и всеми прочими методами.
Вы предлагаете фотошоп и прочих переписать? Автор поднял общую проблему и указал общий алгоритм для её решения, а в конце показал - как успешно применил это решение в своем частном случае. А ваш алгоритм (который ещё не проверен), может быть актуален для случаев когда софт ещё создается, но в 99% случаев разные библиотеки прочее для изображений и видео уже написаны. Да и логика вашего алгоритма странновата- для примера берем видео которое нужно обработать 5 алгоритмами-эффектами - то нужно модифицировать 5 алгоритмов? Не проще ли перевести в линейный формат, обработать и перевести в нужный нам цветовой профиль?
даже Google Chrome неверно выполняет resize изображения
Ну как бы да, но тут не баг, а сознательное упрощение.
Во-первых, в вебе вообще многие вещи оптимизированы с перекосом в перфоманс и в ущерб качеству. Ресайз в том числе, причем игнор гаммы там - лишь одна из проблем. Зато быстро.
Во-вторых, возникает вопрос консистентности - почему при ресайзе гамму надо учитывать, а например при композинге нет? И ещё в куче мест. А учитывать вообще везде - тяжело, о-очень много чего цепляется. И провоцирует тонны багрепортов в духе "а я вот наложил салатовый div на розовый и на экране получилось не то, что я ожидал".
В-третьих, требует перехода на флоаты, потому что в 8-битных каналах ошибки округлений могут быть большими.
ФШ (если ничего не путаю) при ресайзе гамму учитывает, а для блендинга может учитывать - для этого есть специальная настройка, но по умолчанию она отключена.
Когда хочется красивого результата, но важна и скорость (игры) - бывает пересчитывают гамму функциями sqrt(x) и x**2. Это грубое приближение настоящей гамма-кривой, но такой результат всё равно намного лучше, чем если не учитывать никак. И гораздо быстрее чем pow.
В каком-то смысле, все эти web-упрощения очень ироничны в контексте того, что проблема существует десятки лет, а маркетинговые лозунги про "ускорение интернета" средствами специальных функций процессора стали звучать ещё во времена появления Intel MMX.
В-третьих, требует перехода на флоаты, потому что в 8-битных каналах ошибки округлений могут быть большими.
Не обязательно прям во флоты, можно fixed point 8.8 использовать, тогда можно продолжать работать с целыми числами и более эффективно векторизовать.
Мы делаем графический редактор, и у нас те же проблемы, что и в браузере.
Есть полупрозрачные кисти, есть эффекты, есть композитинг, есть ресайз, и прочее и прочее. Нужно либо всё это делать линейно, либо всё это делать нелинейно (например, в sRGB). Нельзя сделать что-то так, а что-то эдак, — это приведёт к неконсистентности. Например, пользователь рисует кистью на пустом слое, а потом сливает этот слой с нижележащим. Другой вариант — рисует сразу на нижележащем. Пользователь ожидает получить один и тот же результат.
Допустим, при проектировании архитектуры графического редактора принято решение выполнять всё в линейном цвете. Цветовое пространство документа при этом произвольное — мы не можем использовать какие-то математические формулы для линеаризации. Только таблицы (не только, но это оффтопик). Садятся программисты и создают всякие алгоритмы (blur, resize, композитинг, кисти…). Ввиду того, что каждый программист не знает, куда пойдут результаты работы его алгоритма (на экран или на вход другого алгоритма), то реализации получаются такие: вначале цвет линеаризуется, потом, например, блюрится, потом обратно «де-линеаризуется». Всё это в совокупности медленно работает, и накапливаются погрешности от многократной линеаризации-делинеаризации на стыке алгоритмов.
Оптимизируем архитектуру: снабжаем каждое изображение флагом, линейно ли оно. Если нелинейно, то линеаризуем и устанавливаем флаг. Далее прокручиваем цепочку алгоритмов, далее делинеаризуем, и выводим на экран. Вроде всё логично, но это уже давно придумано, и называется цветовым профилем. Мы можем просто выполнить все вычисления в линейном цветовом профиле, и прямо в нём вывести на экран (сообщив операционной системе характеристики профиля). Операционная система знает про цветовые профили, она сама превратит линейный цвет в нужный для отображения.
А раз всё можно сделать с помощью цветового профиля (да ещё и с оптимизациями на уровне операционной системы), то зачем вообще заморачиваться с линейным цветом? пусть пользователь, для которого критически важна линейность цвета, сам, своими руками, выбирает в меню «16 бит на канал» (вместо 8-ми бит, которых для линейного цвета не хватит), и какой-нибудь линейный цветовой профиль (например, ACES).
Все счастливы: программисты пишут простой и быстрый код, а пользователь получает контроль над тем, с каким представлением цвета работать. Более того, в этом плане у графических редакторов поведение одинаково, что облегчает их освоение.
Я не проверял, но могу предположить (по аналогии с графическим редакторами), что если в Web вы поместите изображение 16-бит на канал в линейном цветовом профиле, то и resize таких изображений браузер начнёт выполнять в линейном цвете. Так что всё под контролем; что ещё надо? (Но есть нюанс: 16-битные изображения очень плохо сжимаются)
Ошибка часто не заметна, но она есть.
Так хорошо же? Ошибка не заметна, а лишних ресурсов на конвертацию в линейное пространство и обратно тратить не нужно.
Рекомендуем к прочтению две статьи (первая, вторая) — в них приведены примеры изображений, для которых эта ошибка визуально заметна.
Разница бесспорно визуально заметна. Но возможно ли сказать, что с изображением что-то не то, смотря только на одно изображение, а не на два? Особенно, если вы не читали статьи и не видели второй вариант.
Пример: photometric stereo
У вас есть какой-то алгоритм, о котором ничего не известно (по крайней мере после прочтения статьи). Вы подаете ему данные в одном формате и в другом формате. Со вторым формате алгоритм работает лучше (из статьи не понятно, почему более темная карта это лучший результат и почему нельзя просто затемнить первый результат, но раз вы говорите, значит так оно и есть). Какой из этого можно сделать вывод? Что вам для вашего алгоритма следует подавать данные во втором формате. Всё. Мы же не знаем, что внутри вашего алгоритма. Может быть там нейросеть, которая натренирована именно на втором формате.
Да, ошибка не заметна, но полезно знать, что она есть.
Алгоритм, который я использовал в статье, не опирается на нейросети и не содержит каких-либо элементов обучения. Решается система линейных уравнений (почти такая же, как описано здесь), в которой известные параметры — это RGB цвета пикселей и векторы направления вспышек, а неизвестные параметры — векторы нормалей лица человека.
Если просто затемнить исходные sRGB фотографии, то результат работы алгоритма не изменится: векторы нормалей изменят свою длину, но не направления.
Надеюсь, что в будущих статьях мы осветим этот алгоритм подробнее.
Не понимаю наездов на автора, алё народ, вам показали один из типичнейших косяков, и попытались в силу таланта и/или щедрости объяснить что с ним не так. Да, это можно сделать лучше и конкретней, но тогда придётся рассказывать о многом другом. Лично я в математику пришел именно через работу со звуком и изображением, а полученное понимание использую вообще в других областях. И профильное образование не давало готовых ответов, но именно оно способствовало постановке правильных вопросов, которыми типичный инженер-программист не задаётся, вроде решая свои задачи, вроде... :-)
Я знаю, чтобы не огрести тухлых помидоров нужно говорить о лишь вещах общеизвестных, и не много намекну, ведь про garbage in/out все слышали, но о том сколько этого garbage-a возникает в процессе, ну короче вы поняли...
По-моему, проблема этой статьи в том, что вывод ("не следует использовать нелинейные цветовые пространства") изложен в самом начале, а контекст, в котором он верен ("... на входе алгоритмов, предназначенных для обработки линейных данных") упоминается только ближе к концу. В результате больше половины статьи читается с ощущением "автор считает, что нелинейные цветовые пространства не нужны вообще, и пытается это доказать".
Мораль истории: нужно учитывать цветовой профиль изображения, и не только при манипуляциях, но и при выводе из на екран. Здесь ещё и профиль монитора нужно учитывать, но винда не делает этого до сих пор (фотошоп делает это сам), на маках ситуация лучше.
И ещё мониторы, в большинстве случаев, один хуже другого, цветовой охват 50-80% от sRGB
но винда не делает этого до сих пор
А почему вы считаете, что эта задача именно для операционной системы?
И ещё мониторы, в большинстве случаев, один хуже другого, цветовой охват 50-80% от sRGB
При этом монитор ещё и не откалиброван. То есть при всём своём желании корректно отобразить цвет не представляется возможным.
Кстати, на подобных мониторах лучше выводить изображения как есть, без попыток коррекции. Человек абсолютно нормально воспринимает изображения с немного искажёнными цветами или контрастностью. Это лучше, чем потерять информацию в цветах, которые не могут быть отображены монитором.
Как раз на плохих мониторах калибровку видно больше всего, цвета внутри охвата монитора компенсируются и это хорошо видно.
А должна должна ли ОС заниматся этим? Конечно, макос показала что это, как минимум, удобно. Вся графика на экране с правильными цветами, даже не в графических редакторах
Как раз на плохих мониторах калибровку видно больше всего, цвета внутри охвата монитора компенсируются и это хорошо видно.
Зато пропадают цвета вне охвата. И это зачастую больше раздражает.
А должна должна ли ОС заниматся этим? Конечно, макос показала что это, как минимум, удобно. Вся графика на экране с правильными цветами, даже не в графических редакторах
Маки изначально позиционировались как продукты для дизайнеров и издателей. Неудивительно, что правильная работа с цветами — это обязательное условие.
Нее, мораль в том, что производя арифметические операции стоит удостовериться в корректности оных. А то получается, что пытаясь узнать среднее количество воды, люди вычисляют количество тары, а она разная, от ведра до стопки, всё вместе сложить и поделить, и ничего работает, разница на вид не заметна :-)
Уточню некоторые моменты.
Я работаю в Pixelmator Team. Мы делаем графический редактор, которым пользуются миллионы. И я многое знаю про линейность и нелинейность цвета. Хотелось бы написать целую статью, но уложусь в комментарий, причём постараюсь обойтись без формул.
Во-первых, в статье не объяснена суть термина «линейный цвет». Восполню это. Простыми словами, линейный цвет — это такое численное представление цвета, при котором уменьшение (или увеличение) количества фотонов в k раз приведёт к изменению значения численного представления в k раз. То есть линейный цвет близок к «физике».
Во-вторых, человеческое зрение нелинейно. Восприятие больших яркостей близко к логарифмическому, а при малых яркостях в глазах чего только не творится (но это оффтопик). Откуда взялся логарифм? Дело в том, что окружающий мир в плане света мультипликативен. Когда свет от чего-то отражается, при отражении остаётся сколько-то процентов от исходного света. Для «борьбы» с мультипликативностью мира у нас эволюционно выработалась контрмера — логарифм. При этом восприятие оттенка света (не яркости) у нас линейное. Это нужно для того, чтобы цвета объектов в тени казались примерно такими же, как на ярком свету.
Из того, что написано выше, следует, что при кодировании изображений линейный цвет лучше не использовать. Например, если закодировать чёрно-белое изображение одним байтом на пиксель, то мы получим 256 градаций. Чтобы не тратить эти градации впустую, нам нужно расположить их максимально равномерно с точки зрения человеческого глаза — ближе к логарифму в яркой части, ближе к квадратному корню в тёмной части. Подобным свойством обладает передаточная кривая sRGB — самого популярного цветового пространства (цветовое пространство определяет правила кодирования цветов). Да, sRGB родилось из свойств электронно-лучевых трубок. Но к свойствам глаза оно тоже очень близко.
Теперь первый пункт, по которому я не согласен со статьёй: утверждается, что если взять среднестатистическое фото из Интернета (или из фотоаппарата), и обратить sRGB, то мы получим линейный цвет. Не получим. Дело в том, что фотографии берутся из HDR-мира (высокий динамический диапазон), но отображаются на LDR мониторе. Если камера возьмёт линейный цвет с сенсора и тупо закодирует его в sRGB, то фотография будет казаться блеклой и тёмной. Производители фотоаппаратов и мобильных телефонов давно смекнули, что для красивого упихивания среднестатистической фотки в среднестатистический дисплей нужно добавить «яркости» и добавить «контраста». В общем, применяется некая функция (которая называется «тоновая кривая»), нам неизвестная, которая делает картинку «красивой». Поэтому для получения линейного цвета нужно 1) отменить кривую кодирования sRGB, и 2) отменить тоновую кривую.
Тоновую кривую мы обычно не знаем, но, к счастью, тоновые кривые современных фотоаппаратов и мобильников похожи как браться близнецы, и можно ошибиться в линейности цвета не более, чем на несколько процентов, если предположить некую среднюю тоновую кривую. Исключение составляют всякие режимы HDR на мобильниках, при которых тонов кривая подбирается индивидуально для каждого участка изображения. «Линеаризовать» такие изображения не получится.
Второй пункт, в котором я не согласен со статьёй: утверждается, что линейный цвет — единственное «правильное» представление цвета, при котором над ним можно проводить математические операции. Это не так. Приведу два примера.
Пример 1: свёрточная нейронная сеть. По моему опыту, для нейросетей лучше всего подходит логарифмический цвет, а не линейный. Причина проста: логарифм превращает умножение в сложение, поэтому при логарифмическом представлении текстуры, находящиеся в тени, будут отличаться от таких же текстур, находящихся на свету, на аддитивную константу. Свёртки в нейросети могут иметь нулевую сумму коэффициентов, и тогда они будут к этой константе инвариантны. Таким образом, логарифмический цвет позволяет нейросети быть инвариантной к освещению. Мы проверяли: подача линейного цвета на вход свёрточной сети ухудшает её точность, даже если сеть на таком представлении училась изначально.
Пример 2: фильтрация шума. Шум современных фотоаппаратов по большей части состоит из дробового шума фотонов, и потому подчиняется распределению Пуассона. Стабилизирующим преобразованием (преобразованием, делающим дисперсию константной, а распределение нормальным) для распределения Пуассона является квадратный корень. Таким образом, шум лучше всего фильтровать в «квадратных корнях из линейного цвета».
Спасибо за очень интересное дополнение!
Согласен со всеми утверждениями, уточню только про «линейный цвет». Вы говорите про линейность цвета, который упал на сенсор камеры. Все правильно, это бывает важно в профессиональной фото/киноиндустрии.
Но в статье я говорю о другой линейности, которая чаще всего нас интересует на практике — линейности относительно человеческого восприятия цвета, излучаемого монитором. Не важно, как было получено и обработано изображение до того, как оно попало к нам в руки (применялась ли к нему тоновая кривая или может быть это вообще не фотография, а искусственно сгенерированная картинка) — важно то, как оно будет отображаться на дисплеях. И для sRGB картинки достаточно отменить кривую кодирования sRGB, как я описал в статье, чтобы получить нужную нам линейность. Эту линейность можно понаблюдать визуально, если посмотреть на равномерно расположенные полосы серого цвета в этой статье.
Да, действительно. Есть задачи, для которых способ получения картинки не важен, а важно её представление на дисплее. Соответственно, обратить кривую sRGB достаточно.
Навскидку могу сказать, что в линейном цвете лучше смотрится resize картинки, antialiasing, blur небольшого радиуса, некоторые алгоритмы повышения чёткости (прошу прощения, не знаю русских аналогов для некоторых слов).
Но и тут есть тонкости. Мы занимаемся в том числе pixel art и многомасштабной обработкой изображений, и оказывается, что когда пиксели действительно крупные (или обрабатываемые участки изображения крупные), то вместо линейного цвета лучше работает гамма-корректированный цвет. Видимо, это связано с тем, на каком уровне зрительной системы обрабатывается эта информация («на уровне глаза», или «на уровне мозга»). Pixel art с крупными пикселями — это уже не «низкое разрешение», это уже стилизация, и там от «физики» надо отходить в сторону «мозга».
Получается интересная ситуация: линейность/нелинейность восприятия цвета деталей изображения зависит от отношения размера деталей к расстоянию, с которого человек смотрит на изображение.
Интересно. Но меня больше волнует необходимость переводить изображения в CMYK (открытки и постеры для печати нужно делать). С цветами сразу твориться нечто ужасное, особенно с красным цветом.
Как нужно обрабатывать изображения, чтобы не расстраивать математику?