Comments 130
Слева старая «неправильная» формула, справа новая «правильная». Справа однородность действительно заметно выше.
Объясните тогда, почему в grayscale, слева как раз более однородно?

Нужно выяснять чем и как конвертировали в grayscale, какие настройки и т.д.
Случайно не функцией Desaturate в ФШ? Она работает иначе — в модели HSB (т.е. совершенно не перцептивно).
Исходная:
/>
Со старыми коэффициентами
/>
С новыми коэффициентами
/>
Вот статейка, где можно посмотреть результаты:
www.cgm.computergraphics.ru/files/cgm/rgb2gray_article.pdf
У Вас (псевдокод):
var ethalonY := 0.5, count := 100;
for (var n := 0; n!=count; ++n) {
var r := random(), b := random();
var g1 := getGreenFromRedBlueY(r, b, ethalonY, [0.299, 0.587, 0.114]);
var g2 := getGreenFromRedBlueY(r, b, ethalonY, [0.2126, 0.7152, 0.0722]);
putLeft(r, g1, b); putRight(r, g2, b);
}
Надо:
var ethalonY := 0.5, count := 100;
for (var n := 0; n!=count; ++n) {
var h := n / count * 360°;
var (r, g, b) := hslToRgb(h, 100%, 50%);
var (r1, g1, b1) := normalizeToY(r, g, b, ethalonY, [0.299, 0.587, 0.114]);
var (r2, g2, b2) := normalizeToY(r, g, b, ethalonY, [0.2126, 0.7152, 0.0722]);
putLeft(r1, g1, b1); putRight(r2, g2, b2);
}
Т.е.:
1. Не подбирать зелёный по красному и синему, а подбирать все 3 канала по hue.
2. Меньше рандома, просто перебрать все значения hue подряд с каким-то шагом.
□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ (YIQ)
□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ (sRGB)
Какой ряд равномернее по яркости — тот и лучше.
Но нам ведь важнее смотреть на однородность группы, т.е. как раз лучше показать её сбитой в кучу, а не вытянутой колбасой.
function stringify (r, g, b) {
return 'rgb(' + Math.round(255 * Math.pow(r, 0.45)) + ',' +
Math.round(255 * Math.pow(g, 0.45)) + ',' +
Math.round(255 * Math.pow(b, 0.45)) + ')';
}
Пусть у нас есть два цвета — красный {1, 0, 0} и темно зеленый {0, 0.5, 0} в нелинейном цветовом пространстве с гаммой 2.2. Забив на гамму и применяя формулу напрямую, получим яркости 0.2126 и 0.3576. Если же корректно преобразовать цвета в линейное пространство, рассчитать яркость и вернуть в нелинейное, то получится 0.4947 и 0.4293. Налицо принципиальное изменение отношения.
Вообще, если пытаться приближать правильную формулу без степеней, то стоит хотя бы возвести в степень 1/2.2 сами коэффициенты, т. е. использовать Y = 0.4948R + 0.8587B + 0.3028G. Будет работать правильно хотя бы для чистых цветов. Для смешанных, в том числе белого, будет врать, поэтому надо заново нормировать на единицу. В общем, как я и говорил, «рядовой программист» будет врать независимо от выбранных магических чисел.
Метод В лоб С учетом гаммы
Rec.601 92.6% 94.3%
Rec.709 94.1% 100%
Результаты вполне устойчивые, разные эксперименты дают разброс <0.1%.
Выводы в общем-то капитанские: влияет и то, другое. Разница лишь в том, что гамма просаживает производительность, а коэффициенты достаются бесплатно.
В какой пропорции смешивать — зависит от конкретного RGB-пространства, а оно в свою очередь зависит от контекста задачи.
Если вы вдруг действительно работаете с NTSC-видеосигналом — исходная формула верна. Но только для него. Для других пространств — нет.
Если это sRGB (подавляющее большинство случаев), то верна формула, которую я привёл (вторая). Если вдруг вы используете что-то иное (Adobe RGB, ProPhoto RGB и так далее) — там будут свои коэффициенты, их можно вывести из таблички Линдблума.
Изменения формулы rgb_to_gray аналогичны изменению контраста изображения.
Но это палка о двух концах — увеличим контраст, усилим границы, но получим больше шума. И обратно.
Проблема в том, что rgb_to_gray преобразование и последующий оператор Собеля это все линейные преобразования. Изменяя коэффициент в формуле rgb_to_gray мы лишь получаем масштабирование, т.е: Sobel(Rgb2Gray(I*A)) = Sobel(Rgb2Gray(I))*B
Более продвинутым способом можно считать нелинейные преобразования, например те же нейронные сети, обученные на выделение границ.
если увидите в чьем-то действующем коде последовательность 299/587/114 — кидайте автору ссылку на эту заметку.Основная проблема в том, что эта заметка на русском. Куда лучше всего всего давать ссылку англоязычным разработчикам (хочу попроваить формулу в Pillow)?
коэффициенты привязаны к технологии воспроизведения цвета
Именно так и было, но наоборот: привязка изначально была к Ч/Б телевизорам и их особенностям. В целях обратной совместимости. Ну а после… Эти костыли кочуют из руководства в руководство прям аки мировые константы.
А разве коэффициенты не зависят от того, в каком цветовом пространстве у нас картинка? Конечно, sRGB сейчас стандарт де-факто, но ведь теоретически изображение может быть и в AdobeRGB, и в ProPhoto, и в чём то еще.
Просто создается впечатление, что посыл поста — "это неправильные магические числа, замените их другими". По моему лучше было бы проверять цветовое пространство и делать соответствующий перевод, такой код даже после замены стандарта не будет работать неправильно, а максимум выдаст ошибку об отсутствие соответствующего преобразования..
Что касается разных пространств. Да, конечно, лучше и точнее считать всё по-взрослому. Но это сразу забросит нас в пучину нетривиальной и громоздкой колориметрической математики. Вот так быстро и сходу в ней разобраться сложно — да и не особо нужно, откровенно говоря. В 99% случаев, с которыми сталкивается рядовой программист, это себя не оправдает. Достаточно, чтобы он не использовал заведомо неправильные формулы, которые ему случайно нагуглились.
Ну а если кто-то решает более серьезные задачи — там, конечно, не обойтись. Но это отдельная и настолько большая тема, по ней пишут толстенные книжки, а не заметки на Хабр.
В 99% случаев визуальной разницей между двумя формулами можно пренебречь. Конечно, лучше и точнее считать по правильной формуле, но принципиальной разницы увидеть не удалось.
Вообще, тут ещё от монитора зависит восприятие. Я тестировал на макбуке и внешнем монике Dell, на встроенном мониторе разница заметна слабее.
Но зачем использовать заведомо неверные коэффициенты, если можно взять верные, и дополнительные трудозатраты для этого равны нулю? :)
А тут, вдруг, «координаты цветов». О чём речь, вообще? (Я понимаю, что это айтишные условности по перекладыванию байтиков из системы в систему, но, всё-таки).
Если коротко, то длина волны однозначно соответствует цвету (и то с некоторыми оговорками) только в том случае, когда она одна — то есть имеем чистый спектральный свет. Если же имеем смесь волн (а на практике так почти всегда), ситуация резко становится намного сложнее.
Поэтому пришлось придумать свои особые, цветовые системы координат. Причем их много разных и у каждой свои плюсы и минусы.
Если на пальцах:
На глаз падет электромагнитная волна, зависящая от времени. Это не синусоида!
Глаз не ловит конкретных отклонений волны, и он не спектроанализатор (это было бы слишком накладно).
Глаз делает две вещи: режет сигнал по типичному времени (времени реакции) и каждый интервал раскладывает в сумму ряда из всего трёх членов. У этих собственных членов есть собственные функции — это примерно (но не точно!) гауссианы с центрами в длинах волн, которые мы называем «красным», «синим» и «зелёным».
Очень много функций можно разложить так, что их скалярные произведения с гауссианами одинаковы. И спектроанализатор покажет разницу, а глаз — нет.
Ещё удивило, что gimp «поворачивает», кажется, вообще, без учёта коэффициентов. По крайней мере, в нём результат поворота получался совсем удручающий.
Цветовой поворот удобно делать в HSV, HSL и подобных.
Да и вообще, зачем мне HSL/HSV, если у меня поворот ровно на 120° и 240° — достаточно поменять местами каналы (ну, с поправками, учитывая, что разные каналы имеют разную «мощность»).
Вот для этих поправок и нужны коэфициенты. Прикол в том, что более древние (и по логике неправильные) SDTV-коэфициенты на моём мониторе давали более правильный результат, чем более новые, рекомендуемые в т.ч. автором этой статьи.
Вероятно, судя по статье, это YIQ и sRGB (накрайняк — NTSC и HDTV).
Но у меня в коде переменные почему-то были названы так.
Ну так у чисто зеленого и чисто синего одинаковая lightness. Менять надо hue, который в градусах и измеряется.
Поэтому и нужны эти коэфициенты.
А если просто менять hue, то получится та же херня, что и в gimp'е.
Эта характеристика называется «светлота».
Если светлота (lightness?) — это то, какой цвет визуально выглядит светлее…
… то как тогда называется третий параметр (L) в HSL?
Ну так в том-то и дело, что #0000FF — это синий (не голубой), а #00FF00 — это салатовый (не зеленый). Т.е. #00FF00 визуально намного ярче, чем #0000FF.
Эта характеристика называется «светлота».
Тогда Вы сами себе противоречите. Я говорил о том, что #0000FF (синий) и #00FF00 (салатовый) в HSL имеют одинаковое L (50%) — несмотря на то, что #00FF00 визуально выглядит светлее #0000FF'а.
P.S.: Т.е. меня интересует «субъективная светлота» (не знаю как называется), а не параметр L в HSL.
Не противоречу. Я лишь дал вам название термина.
> Я говорил о том, что #0000FF (синий) и #00FF00 (салатовый) в HSL имеют одинаковое L (50%) — несмотря на то, что #00FF00 визуально выглядит светлее #0000FF'а.
Именно это и называется «светлотой» (2).
> Т.е. меня интересует «субъективная светлота» (не знаю как называется), а не параметр L в HSL.
Объясню по другому. L в HSL отвечает за субъективную светлоту, но HSL не подразумевает что при одинаковом L она всегда будет одинаковой. В Lab эта же светлота, но формула устроена так что результативная светлота полностью определяется L.
Про Lab надо почитать, это интересно; просто для той задачи это было явно излишне.
Тут я просто отвечал человеку, который зачем-то настойчиво советовал HSL/HSV; и я ему пытался объяснить, что HSL/HSV мне не помог бы (HSL/HSV мне нужен был бы, если бы у меня был поворот не на 120° или 240° ровно, а на другое число; но поворот hue на 120° или 240° это и есть обмен каналов); так как проблему неравноценности RGB каналов сам по себе HSL/HSV бы никак не решал (потому что при стандартных формулах перевода RGB <-> HSL/HSV каналы как раз считаются равноценными), просто была бы лишняя арифметика.
Ну, формулы RGB<->Lab я как раз нашёл, там (вроде) всё просто:
RGB<->sRGB<->«CIE XYZ»<->Lab
(1) RGB<->sRGB и sRGB<->«CIE XYZ»
(2) «CIE XYZ»<->Lab
(Но не знаю насколько просто всё остальное, потому что суть Lab я пока не понимаю.)
А какого рода софтину Вы собираетесь делать? Т.е. какой у неё должен быть функционал? (Условно говоря: просто преобразовать 1 цвет типа такого но сложнее или именно работа с изображениями?)
Софтина именно для обработки изображений, конкретная задача, где нужен (ну или желателен) Lab — составление функции визуальной похожести цветов.
Например, при гамме 2.2 смешение пикселей с интенсивностями 0 и 255 будет равно 186, а не 127.
Эксперименты склонят меня к мысли, что для конвертаций (из пространства в пространство и в частности из rgb в grayscale) — гамму конечно же нужно учитывать.
Но для обработки изображений (например, регулировки яркости, контрастности, фильтры, смешивание и пр.) гамму лучше не трогать. Она же не просто так придумана — она нужна, чтобы сделать шкалу перцептивной. И гамма sRGB и L* делают это с разной степенью точности. Цвета нужно смешивать по перцептивной шкале, а не физической.
Я пока поостерегусь назвать эти выводы окончательными. Но похоже, что ФШ именно так и поступает.
И похоже, что мой апдейт 2 нужно проапдейтить, рассуждения в нём были частично ошибочные.
CIE Lab и любое гамма-корректированное RGB-пространство очень нелинейны (типичный показатель степени от 1.8 до 3) относительно CIE XYZ. Но относительно человеческого восприятия всё наоборот — они более линейны (для того гамма и придумана!), Lab получше, RGB похуже. Но оба они превосходят в этом смысле XYZ, которое очень сильно нелинейно (эллипсы МакАдама).
XYZ это такая математическая абстракция, которую придумали для удобства математики в докомпьютерную эпоху — считали все на логарифмических линейках, и отрицательные числа доставляли большие неудобства. Но оно вообще не перцептивное. Так почему же обработка в нём (или в его линейных преобразованиях, которыми являются RGB-пространства без гамма-коррекции) должна быть более корректна?
Ошибка ваших рассуждений в том, что Y — это не физическое количество света. Потому что XYZ это тоже пространство «цветовых ощущений», а не физического количества фотонов.
В контексте обсуждения важно, что это подпространство линейное, т. е. подчиняется принципу суперпозиции. Соответственно, если взять два источника света и посветить на одно место, то итоговой цвет будет суммой цветов источников в любом линейном пространстве (а уже конкретно ли это XYZ, RGB, или, вообще, функция от длины волны, не важно).
В общем, лучше один раз увидеть. Тонкие линии на разном сабпиксельном смещении
без учета гаммы:


Невооруженным глазом видны колебания яркости в первом случае.
(Картинки из темы на геймдеве, посвященной антиалиасингу.)
Если объект размером 1px нужно размазать на 2px, но при чтобы он выглядел так же — вполне ожидаемо, что потребуются какие-то компенсирующие ухищрения.
А в более простом случае, когда каждый пиксель это пиксель — получается как-то спорно.

А субъективные вопросы они на то и субъективные, чтобы не иметь однозначного ответа. Например, моя тренированная физическая интуиция говорит за нижний квадрат. Поэтому я предпочитаю обсуждать только объективные вопросы.

Или вот мой прошлый пример с яркостью цветов

Без учета гаммы зеленый должен быть ярче красного в полтора раза, с учетом — красный немного ярче зеленого.
Мой пример.
Мое мнение — самый верхний. Но это моё, оно теоретически может быть предвзято. Я ещё опросил 4-х человек (никто их них не понимает значения букв на картинке). Двое сказали что средний квадратик, один что верхний, а еще один, что он бы еще немного затемнил верхний.
Шахматка.
На десктопе совпадает с верхним. На планшете и телефоне где-то посередине, но чуть ближе к нижнему. Сторонние мнения: у одного ближе к нижнему, у одного ближе к верхнему, у одного точно совпал с нижним.
И можно было бы списать разброс на разные калибровки разных экранов, но… два последних человека (с противоположным виденьем) смотрели на одном компьютере :)
Но, вообще, все это лирика и законы физики предполагают только один ответ. Получение другого говорит о неправильной калибровке монитора и/или неправильной постановке эксперимента.
Теория требует тщательной работы, но на практике результаты будут мало отличимы. Например в одном издательстве, где я работал, было потрачено много усилий на то, что бы в кабинете допечатной подготовки у всего был правильный цвет, специальные лампы, тщательная калибровка принтера и мониторов, стены чистого серого цвета и тд тп. Я открывал картинку на эйзо, клал рядом с монитором цветопробу и журнал из тиражом — в идеале все картинки были одного цвета, некоторые отличия могли быть только в яркости. И эти усилия были оправданы.
Но в мире ноутов и смартов — это все не имеет смысла, даже гамма плавает в пределах ± хз сколько
Например, черный провод на белом фоне после размытия должен пропать, а белая нить на чёрном фоне — стать толще, почти не потеряв в яркости. Без преобразования гаммы оба объекта бы стали серыми.
Добью вас про линейность цветового пространства. Вообще говоря перевод sRGB → RGB не ограничивается выправлением гаммы. Формула чуть сложнее.
(3r+6g+1b)/10
. Визуально разницы почти не заметно, особенно в динамике.По хорошему там везде надо issue открыть или кинуть pull request, но как аргументировать?
использовать BT.601 — для старых не-HD источников (DVD и т. п.)
использовать BT.709 — для HD-видео
Не помню уже, откуда инфа, и на сколько она верна, но в памяти отложилось именно так.
Для всего остального BT.709 будет лучше — более свежие версии NTSC/PAL/SECAM хоть и не соответствуют им в точности, но очень близки.
The weights used in this conversion are calibrated for contemporary CRT phosphors
Ссылаются на этот документ.
Все у кого есть под руками фотошоп, могут проверить два метода:
1) Создать RGB-изображение, залить фон градиентом радуги, применить к нему корректирующий слой Hue/Saturation в режиме наложения Normal и сдвинуть ползунок насыщенности в крайнее левое положение. Получится эффект команды Desaturate, аналогичный большинству аналогичных алгоритмов. Но картинка выйдет серая и плоская
2) Повторить все шаги, но корректирующему слою сделать режим наложения Color. Получается Ч/Б картинка совсем другого характера, даже без цвета она остается яркой и контрастной, все цвета максимально разделяются один от другого
Я не могу проверить описываемые в статье алгоритмы на своей картинке, но вот результат получающийся в фотошопе (прошу прощения, но полноценная работа с тегами мне недоступна, потому длинные текстовые ссылки):
Цветной исходник: www.dropbox.com/s/mxbr7fpos67xme6/rainbow-color.jpg?dl=0
Ч/б результат в режиме Normal: www.dropbox.com/s/oeky5jgi3wtncmh/rainbow-bw-normal.jpg?dl=0
Ч/б результат в режиме Normal: www.dropbox.com/s/j90vgvi77c9n79k/rainbow-bw-color.jpg?dl=0
Будет здорово, если кто нибудь десатурнет цветной исходник по обсуждаемым алгоритмам и покажет результат, для сравнения с фотошопным
Самый точный и правильный (с инженерной точки зрения) вариант обесцвечивания — это перевести картинку в Lab и взять канал L (lightness).
Mode > Grayscale по качеству где-то посередине (не идеально, но для большинства случаев достаточно).
Я рассуждаю не как программист, а как ретушер-цветокорретор. Картинка должна быть не просто «правильная» с точки зрения математики, она должна быть яркой и контрастной, с минимальными потерями в деталях – то есть она должна быть красивой. А это не алгоритмизируется так просто
Вот примеры той же радуги:
L-канал из режима Lab: rainbow-Lab.jpg
Командой Grayscale: rainbow-gray.jpg
Если сравнить все варианты – то самый детализированный, то есть тот, у которого цвета максимально разделены друг от друга – десатурнутый с режимом наложения колор. У изображения есть не только детализация по пикселям, но и цветовая, я сейчас о ней и говорю. Пока обсуждаются абстрактные цветные квадратики, все это не наглядно, но когда приходится работать с реальной фотографией, то разница становится заметна и понятна
На самом деле все еще сложнее, грамотно перевести картинку в чб можно только с помощью команды Calculation, пробуя накладывать разные каналы друг на друга, в разных режимах и пропорциях, это сложная задача и после нее все равно придется доводить картинку корректирующими кривыми, но двухкликовый способ лучше всего тот, который я описал, Я плохо представляю, как его запрограммировать, хотя предполагаю, что это возможно, потому что наблюдал подобные задачи и их решения программными методами как на сервере, так и в браузере. Я не вспомню навскидку, но мне кажется, что в CSS есть возможность сделать подобную обработку не простым обесцвечиванием, а с наложением в разных режимах.
Я всего лишь добавил в чисто математический разговор, рассуждения о цвете профессионала-полиграфиста, который почти 20 лет занимается цветокоррекцией. Может это кому то окажется полезным, потому что, как показывает практика, мало кто представляет себе реальный процесс обработки изображений для глянцевых журналов, в инете этому уделяется куда меньше внимания, хотя бы потому, что разброс экранов по качеству и искажениям несравнимо больше, чем в полиграфии и многое прощается
Color Creates a result color with the luminance of the base color and the hue and saturation of the blend color. This preserves the gray levels in the image and is useful for coloring monochrome images and for tinting color images.
При смешивании берется яркость от нижнего слоя и тон с насыщенностью от верхнего. Насыщенность равна нулю, тон в этих услових не определен и потерял смысл. То есть способ действительно достает из картинки яркостный канал, хотя и окольным путем. Фактически, обходится врожденный порок функции desaturate, которая работает в не-перцептивных координатах и потому полностью всё корёжит (когда я писал, что не советую её использовать — я имел в виду в чистом виде).
Вопрос только, что в точности они подразумевают под luminance. Скорее всего это нечто похожее на формулу, описанную в посте, но остается вопрос настроек (конкретные коэффициенты, учет гаммы и т.п.)
И более того, продукты Adobe никогда не были замечены в связях с моделью HSL, они предпочитают HSB/HSV.
грамотно перевести картинку в чб можно только с помощью команды Calculation
Почему не корректирующий Black&White предназначенный именно для этого? Через калькуляции это же совсем не удобно.
Кстати Алексей Шадрин советовал мне делать так
переход RGB to Gray Gamma 2,2 через команду Convert To Profile в режиме Perceptual лучше всего вгоняет изображение в ч-б.
Фильтр B/W и перевод Gray, плохи тем, что очень не гибкие, с минимумом настроек, а все картинки разные, очень разные. Качественный перевод изображения в градации серого, это сложная и очень индивидуальная работа, связано это с тем, что цвета и цветовой контраст всех изображений сильно отличается. Например можно одинаково хорошо перевести в серый фото, на котором нет явно преобладающих цветов, но если на фото главным является небо с множеством его оттенков, или яркое красное платье, то тут нужно тщательно работать с каналами Calculation, что бы сохранить максимум деталей и контраста. Даже в обычной фотографам может потребоваться контрастно выделить один конкретный объект, который при простом переводе в серый — потеряется
У Алексея есть проблемы в том, что он теоретик и идеалист. Например, он считает, что если фото поделено в нужный профиль, то на этом работа закончена, но есть нюансы, которые требуют локальной коррекции и проблемы с конкретной печатной машиной, которые приходится учитывать заранее, более того, если хочется качественного результата, то надо и в цеху постоять на пресс-контроле

Если ваша задача художественная, и результат вы оцениваете вкусом, его вам и нужно использовать.
Все в итоге сводится к контрастам цветов, не понимаю, зачем нужно использовать для этого совершенно не удобные обходные пути)
Результатом работы калька — является канал в градациях серого, что нам и нужно в итоге.
В итоге все таки нужен результат. В канале или в слое с маской где он появится — не важно.
Б/В это упощенный кальк без многих инструментов и для большинства случаев сойдёт.
Разработчики программы Photoshop и lightroom с вами не согласны и встраивают в оба продукта Black&White. Не профессионалы же. Не понимают, что если вы работаете контрастами цветов, то вам и нужно дать контроль непосредственно над контрастами цветов.
Если профессионалу нужен изощренный инструмент для максимального качества, он такими вещами пользоваться не станет
Максимального качества? Всмысле меньше артфактов? Или мы говорим о качестве, профессионализм которого постоянно перетекает из области фотографического языка, в битие о книжки, где можно упрекнуть обывателя в необразованности, зачем то пользуясь интсрументом 15 летней давности никак не обоснованным математчиески перед более современным фильром предназначенным для этого.
Готов поспорить, что повторю любой результат любого профессионала перевода в чб через Black&White + Curve в десять раз быстрее без каких то там заметных отличий в «качестве».
Как раз строго математическим инструментом является кальк, но не все имеют достаточно терпения для того, что бы изучить математику работы в фотошоп, потому пользуются инструментами, в которых много удобных движков и их можно долго крутить без очевидной связи с логикой. Потому и появляются такие фильтры, как автоконтраст, изучив которые — очень много народу начинает думать, что они умеют работать в фотошоп
И поосторожнее с кривыми в чб, там цвет не будет маскировать огрехи, все на виду
Ссори, перенесла свои презентации в папку, теперь она по ссылке
https://vasilika.ru/presentations/webgl-texture/?full#39
Об относительной яркости, или насколько живучим бывает легаси