Які практичні відмінності при роботі з кольорами в лінійному та нелінійному просторі RGB?


88

Яка основна властивість лінійного простору RGB, а яка основна властивість нелінійного? Що говорять про значення всередині кожного каналу в цих 8 (або більше) бітах, що змінюється?

У OpenGL кольори мають значення 3 + 1, і я маю на увазі RGB + alpha, з 8 бітами, зарезервованими для кожного каналу, і це частина, яку я чітко отримую.

Але що стосується гамма-корекції, я не розумію, який ефект від роботи в нелінійному просторі RGB.

Оскільки я знаю, як використовувати криву в графічному програмному забезпеченні для редагування фотографій, моє пояснення полягає в тому, що в лінійному просторі RGB ви приймаєте значення такими, якими вони є, без жодних маніпуляцій та математичної функції, замість цього, коли вони нелінійні канал, як правило, розвивається відповідно до класичної поведінки функції потужності.

Навіть якщо я сприймаю це пояснення як реальне, я все одно не розумію, що таке справжній лінійний простір, тому що після обчислення всі нелінійні простори RGB стають лінійними і найголовніше з усіх, я не отримую ту частину, де не -лінійний колірний простір більше підходить для людського ока, оскільки врешті-решт усі RGB-простори є лінійними для того, що я розумію.


З практичної ноти ви можете вказати як лінійний, чи стандартний RGB як ваш колірний простір у SVG, і я не уявляю, який це ефект, крім того, що це здається важливим :-)
Майкл Муллані,

@MichaelMullany ця лінійна штука виглядає скоріше натяком для користувача, ніж справжньою відмінною якістю.
Ken

Щось, що мені допомогло: я думаю, це був учитель математики, який сказав мені "думати про лінію, коли чуєш лінійне". Не впевнений, чи допомагає це комусь, але для мене це було "О так!" момент
Джо Планте

Пов’язане читання про гамму
legends2k

Відповіді:


229

Скажімо, ви працюєте з кольорами RGB: кожен колір представлений трьома інтенсивностями або яскравістю. Ви повинні вибрати між "лінійним RGB" та "sRGB". На даний момент ми спростимо ситуацію, ігноруючи три різні інтенсивності, і припустимо, що у вас одна інтенсивність: тобто ви маєте справу лише з відтінками сірого.

У лінійному колірному просторі зв'язок між числами, які ви зберігаєте, та інтенсивністю, яку вони представляють, є лінійною. Практично це означає, що якщо подвоїти число, подвоїти інтенсивність (світлоту сірого). Якщо ви хочете скласти дві інтенсивності разом (оскільки ви обчислюєте інтенсивність на основі внесків двох джерел світла або тому, що ви додаєте прозорий об'єкт поверх непрозорого об'єкта), ви можете зробити це, просто додавши два числа разом. Якщо ви робите будь-яке двовимірне накладання або 3D-затінення, або майже будь-яку обробку зображень, тоді вам потрібні ваші інтенсивності в лінійному колірному просторі, тож ви можете просто додавати, віднімати, множити та ділити числа, щоб мати однаковий вплив на інтенсивності. Більшість алгоритмів обробки кольорів та візуалізації дають правильні результати лише за допомогою лінійного RGB, якщо ви не додаєте додаткових ваг до всього.

Це звучить дуже просто, але є проблема. Чутливість людського ока до світла є більш тонкою при низькій інтенсивності, ніж висока інтенсивність. Тобто якщо скласти список усіх інтенсивностей, які можна відрізнити, темних тем більше, ніж світлих. Іншими словами, ви можете розрізнити темні відтінки сірого краще, ніж зі світлими відтінками сірого. Зокрема, якщо ви використовуєте 8 бітів для відображення своєї інтенсивності, і ви робите це в лінійному колірному просторі, у вас вийде занадто багато світлих відтінків і недостатньо темних відтінків. Ви отримуєте смуги на темних ділянках, тоді як на світлих ділянках ви витрачаєте шматочки на різні відтінки майже білого, які користувач не може розрізнити.

Щоб уникнути цієї проблеми та найкраще використати ці 8 бітів, ми, як правило, використовуємо sRGB . Стандарт sRGB підказує вам криву, щоб зробити ваші кольори нелінійними. Знизу крива більш дрібна, тому у вас може бути більше темних сірих, а крутіша вгорі, тому у вас буде менше світлих сірих. Якщо подвоїти число, ви збільшите інтенсивність більш ніж удвічі. Це означає, що якщо ви додасте кольори sRGB разом, ви отримаєте результат, який буде світлішим, ніж повинен бути. У наш час більшість моніторів інтерпретують вхідні кольори як sRGB. Отже, коли ви розміщуєте колір на екрані або зберігаєте його у текстурі з 8 бітами на канал, зберігайте його як sRGB , щоб найкраще використовувати ці 8 бітів.

Ви помітите, що зараз у нас проблема: ми хочемо, щоб наші кольори оброблялись у лінійному просторі, але зберігались у sRGB. Це означає, що ви в кінцевому підсумку робите перетворення sRGB в лінійне під час читання та перетворення в лінійне в sRGB під час запису. Як ми вже говорили, що для лінійних 8-бітових інтенсивностей недостатньо темних кольорів, це може спричинити проблеми, тому є ще одне практичне правило: не використовуйте 8-бітові лінійні кольори, якщо ви можете цього уникнути. Стає звичним дотримуватися правила, згідно з яким 8-бітові кольори - це завжди sRGB, тому ви перетворюєте sRGB в лінійне одночасно з розширенням інтенсивності з 8 до 16 бітів, або з цілого числа в плаваючу крапку; так само, закінчивши обробку з плаваючою точкою, ви звужуєте до 8 бітів одночасно з перетворенням на sRGB. Якщо ви дотримуєтесь цих правил,

Коли ви читаєте зображення sRGB і хочете лінійну інтенсивність, застосуйте цю формулу до кожної інтенсивності:

float s = read_channel();
float linear;
if (s <= 0.04045) linear = s / 12.92;
else linear = pow((s + 0.055) / 1.055, 2.4);

Якщо ви хочете написати зображення у форматі sRGB, застосуйте цю формулу до кожної лінійної інтенсивності:

float linear = do_processing();
float s;
if (linear <= 0.0031308) s = linear * 12.92;
else s = 1.055 * pow(linear, 1.0/2.4) - 0.055; ( Edited: The previous version is -0.55 )

В обох випадках значення s з плаваючою комою коливається від 0 до 1, тому, якщо ви читаєте 8-бітові цілі числа, спочатку потрібно розділити на 255, а якщо ви пишете 8-бітові цілі числа, то їх потрібно помножити на 255 останнє, так само, як зазвичай. Це все, що вам потрібно знати для роботи з sRGB.

Дотепер я мав справу лише з однією інтенсивністю, але з квітами є щось розумніше. Людське око може розрізняти різні яскравості краще, ніж різні відтінки (більш технічно, воно має кращу роздільну здатність яскравості, ніж кольоровість), тому ви можете ще краще використовувати свої 24 біти, зберігаючи яскравість окремо від відтінку. Це те, що намагаються робити представництва YUV, YCrCb тощо. Канал Y - це загальна легкість кольору і використовує більше бітів (або має більшу просторову роздільну здатність), ніж інші два канали. Таким чином, вам (завжди) не потрібно застосовувати криву, як це робиться з інтенсивністю RGB. YUV - це лінійний кольоровий простір, тому, якщо ви подвоїте число в Y-каналі, ви подвоїте світлість кольору, але ви не можете додавати або множити кольори YUV разом, як це можливо з кольорами RGB, так що '

Думаю, це відповідає на ваше запитання, тому закінчу короткою історичною запискою. До sRGB у старі ЕПТ раніше вбудовували нелінійність. Якщо ви подвоїли напругу для пікселя, ви збільшили б інтенсивність більш ніж удвічі. Наскільки більше було різного для кожного монітора, і цей параметр називали гаммою . Така поведінка була корисною, оскільки означала, що ви можете отримати більше темних кольорів, ніж вогнів, але також означало, що ви не можете сказати, наскільки яскравими будуть ваші кольори на ЕЛТ користувача, якщо ви не відкалібрували її спочатку. Гамма-корекціяозначає трансформувати кольори, з яких ви починаєте (можливо, лінійні), і трансформувати їх для гами ЕПТ користувача. OpenGL походить з цієї ери, тому його поведінка sRGB іноді трохи заплутана. Але постачальники графічних процесорів зараз, як правило, працюють за домовленістю, яку я описав вище: коли ви зберігаєте 8-бітову інтенсивність у текстурі або буфері кадрів, це sRGB, а при обробці кольорів - лінійно. Наприклад, OpenGL ES 3.0, кожен буфер кадрів і текстура має "прапорець sRGB", який ви можете ввімкнути для автоматичного перетворення під час читання та запису. Вам не потрібно явно робити перетворення sRGB або гамма-корекцію взагалі.


6
дивовижна відповідь, дякую, завжди дивовижно бачити пояснення речей, я б попросив лише книгу чи ресурс, який, на вашу думку, буде достатньо хорошим для цієї теми, кольорових просторів та яких формул використовується для перетворення sRGB <-> лінійна або яка функція може наблизити цю поведінку.
Ken

Боюсь, я не знаю жодної хорошої книги чи ресурсу. Сторінка Вікіпедії є вичерпною і включає всі матеріали про білу точку та наскільки мала гамма (про що я не згадував, оскільки більшості людей не потрібно про це знати), але це робить її трохи непроникною .
Dan Hulme,



1

Я не "фахівець з виявлення людських кольорів", але я зустрічав подібні речі при перетворенні YUV-> RGB. Для каналів R / G / B існують різні ваги, тому, якщо ви зміните колір джерела на x, значення RGB змінять різну кількість.

Як вже було сказано, я не є експертом, у будь-якому випадку, я думаю, якщо ви хочете виконати якусь корекцію кольорів, вам слід зробити це в просторі YUV, а потім перетворити її на RGB (або зробити математично еквівалентну операцію на RGB, будьте обережні втрати даних). Крім того, я не впевнений, що YUV є найкращим природним представленням кольорів, але відеокамери забезпечують такий формат, саме тут я вирішив цю проблему.

Ось чарівна формула YUV-> RGB із включеними секретними номерами: http://www.fourcc.org/fccyvrgb.php


1
Будьте обережні щодо перетворення RGB <-> YUV і назад. Я не впевнений, чи так це в кожному випадку, але кольоровий простір YUV іноді перетворюється на діапазон 16-235 замість 0-255 у 24-бітному RGB. Отже, ви можете втратити дані кожного разу, коли виконуєте перетворення кольорового простору. Більшість людей схильні дотримуватися одного кольорового простору, якщо ви можете йому допомогти.
Джо Планте,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.