Скажімо, ви працюєте з кольорами 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 або гамма-корекцію взагалі.