Подтвердить что ты не робот

Нужно ли гамма корректировать окончательный цвет на современном компьютере/мониторе

Я полагал, что мой гамма-корректур должен быть следующим:

  • Используйте sRGB-формат для всех загруженных текстур (GL_SRGB8_ALPHA8), так как все художественные программы pre-gamma исправляют свои файлы. Когда выборка из текстуры GL_SRGB8_ALPHA8 в шейдере OpenGL автоматически преобразуется в линейное пространство.
  • Выполняйте все вычисления освещения, постобработку и т.д. в линейном пространстве.
  • Преобразуйте обратно в пространство sRGB при записи окончательного цвета, который будет отображаться на экране.

Обратите внимание, что в моем случае окончательная запись цвета включает в себя запись из FBO (которая является линейной текстурой RGB) в задний буфер.

Мое предположение было поставлено под сомнение, как если бы я исправился на последней стадии, мои цвета ярче, чем они должны быть. Я установил для сплошного цвета мои ярлыки значения {255, 106, 0}, но когда я делаю рендеринг, я получаю {255, 171, 0} (как определено путем отпечатка и выбора цвета). Вместо оранжевого я становлюсь желтым. Если я не гамма корректировать на последнем шаге, я получаю точно правильное значение {255, 106, 0}.

В соответствии с некоторыми ресурсами современные ЖК-экраны имитируют CRT-гамму. Всегда ли они? Если нет, то как я могу сказать, правильно ли гамма? Я ошибаюсь где-то в другом месте?


Изменить 1

Теперь я заметил, что даже если цвет, который я пишу со светом, правильный, места, где я использую цвета из текстур, являются неправильными (но довольно темными, как я ожидал бы без гамма-коррекции). Я не знаю, откуда это неравенство.


Изменить 2

После использования GL_RGBA8 для моих текстур вместо GL_SRGB8_ALPHA8 все выглядит идеально, даже если вы используете значения текстуры при вычислениях освещения (если я половину интенсивности света, то значения выходного цвета являются половинными).

Мой код больше не учитывает гамма-коррекцию, и мой вывод выглядит правильно.

Это меня еще больше смущает, гамма-коррекция больше не нужна/используется?


Изменить 3 - В ответ на ответ datenwolf

После нескольких экспериментов я смущен на пару баллов.

1 - Большинство форматов изображений хранятся не линейно (в пространстве sRGB)

Я загрузил несколько изображений (в моем случае как изображения .png, так и .bmp) и проверил необработанные двоичные данные. Мне кажется, что изображения на самом деле находятся в цветовом пространстве RGB, как если бы я сравнивал значения пикселей с программой редактирования изображений с массивом байтов, которые я получаю в своей программе, они отлично сочетаются. Поскольку мой редактор изображений дает мне значения RGB, это указывает на изображение, сохраненное в RGB.

Я использую stb_image.h/.c для загрузки моих изображений и последовали за ним полностью, загрузив .png и не увидев нигде, что он гамма исправил изображение во время загрузки. Я также изучил .bmps в шестнадцатеричном редакторе и значения на диске, соответствующие им.

Если эти изображения фактически хранятся на диске в линейном пространстве RGB, как я должен (программно) знать, когда указывать изображение в пространстве sRGB? Есть ли способ запросить это, чтобы обеспечить более полнофункциональный загрузчик изображений? Или это зависит от создателей образа, чтобы сохранить их изображение в качестве гамма-коррекции (или нет), что означает установление соглашения и последующее за ним для данного проекта. Я спросил пару художников, и никто из них не знал, что такое гамма-коррекция.

Если я укажу, что мои изображения являются sRGB, они слишком темные, если я не исправим гамма в конце (что было бы понятно, если вывод монитора с использованием sRGB, но см. пункт № 2).

2 - "На большинстве компьютеров эффективный сканирование LUT является линейным! Что это значит?"

Я не уверен, что смогу найти, когда эта мысль будет завершена в вашем ответе.

Из того, что я могу сказать, экспериментируя, все мониторы, которые я тестировал на выходных линейных значениях. Если я нарисую полноэкранный квадрат и покрась его с жестко закодированным значением в шейдере с гамма-коррекцией нет, монитор отобразит правильное значение, которое я указал.

Какое предложение, которое я цитировал выше из вашего ответа и моих результатов, заставит меня поверить, что современные мониторы выводят линейные значения (т.е. не эмулируют ЭЛТ-гамма).

Целевая платформа для нашего приложения - ПК. Для этой платформы (исключая людей с ЭЛТ или действительно старых мониторов) было бы разумно делать все, что ваш ответ на # 1 есть, а для правильной гаммы # 2 до не (т.е. Не выполнять окончательный RGB → преобразование sRGB - либо вручную, либо используя GL_FRAMEBUFFER_SRGB)?

Если это так, каковы платформы, на которых подразумевается GL_FRAMEBUFFER_SRGB (или где он будет действителен для ее использования в настоящее время), или же мониторы, которые используют линейный RGB, действительно, что новый (учитывая, что GL_FRAMEBUFFER_SRGB был введен 2008)?

-

Я разговаривал с несколькими другими графическими разработчиками в своей школе и по звукам этого, ни один из них не учитывал гамма-коррекцию, и они не заметили ничего неправильного (некоторые даже не знали об этом). Один из разработчиков, в частности, сказал, что он получил неправильные результаты, принимая гамму, поэтому он решил не беспокоиться об гамме. Я не уверен, что делать в моем проекте для моей целевой платформы, учитывая противоречивую информацию, которую я получаю в сети/вижу с моим проектом.


Изменить 4 - В ответ на обновленный ответ datenwolf

Да, действительно. Если где-то в цепочке сигналов применяется нелинейное преобразование, но все значения пикселей не изменяются от изображения к дисплею, то эта нелинейность уже была предварительно применена к значениям пикселей изображения. Это означает, что изображение уже находится в нелинейном цветовом пространстве.

Ваш ответ имел бы смысл для меня, если бы я рассматривал изображение на моем дисплее. Чтобы быть уверенным, что я был ясен, когда я сказал, что изучаю массив байтов для изображения, я имею в виду, что я рассматривал числовое значение в памяти для текстуры, а не изображение, выводимое на экран (что я сделал сделать для точки # 2). Для меня единственным способом я мог видеть, что вы говорите, чтобы быть правдой тогда, является то, что редактор изображений давал мне значения в пространстве sRGB.

Также обратите внимание, что я попытался проверить вывод на мониторе, а также изменить цвет текстуры (например, разделив его на половину или удвоить), и результат оказался правильным (измеренный с использованием метода Я опишу ниже).

Как вы измерили реакцию сигнала?

К сожалению, мои методы измерения намного более грубые, чем ваши. Когда я сказал, что я экспериментировал на своих мониторах, я имел в виду, что я выводил сплошной цветной полноэкранный четырехъядерный цвет, чей цвет был жестко закодирован в шейдере для простого фреймбуфера OpenGL (который не делает никакого преобразования цветового пространства при написании). Когда я выводю белый, 75% серый, 50% серый, 25% серый и черный, отображаются правильные цвета. Теперь моя интерпретация правильных цветов, безусловно, может быть неправильной. Я беру скриншот, а затем использую программу редактирования изображений, чтобы увидеть, каковы значения пикселей (а также визуальная оценка, чтобы убедиться, что значения имеют смысл). Если я правильно понял, если бы мои мониторы были нелинейными, мне нужно было бы выполнить преобразование RGB- > sRGB, прежде чем представлять их на устройство отображения, чтобы они были правильными.

Я не собираюсь врать, я чувствую, что немного ухожу от своей глубины. Я думаю, что решение, которое я мог бы решить, для моей второй путаницы (окончательное преобразование RGB- > sRGB), будет настраиваемой настройкой яркости и по умолчанию соответствует тому, что выглядит правильно на моих устройствах (без гамма-коррекции).

4b9b3361

Ответ 1

Прежде всего, вы должны понимать, что нелинейное отображение, применяемое к цветным каналам, часто больше, чем просто простая функция мощности. sRGB нелинейность может быть аппроксимирована примерно на x ^ 2,4, но это не настоящая сделка. В любом случае ваши первичные предположения более или менее правильны.

Если ваши текстуры хранятся в более распространенных форматах файлов изображений, они будут содержать значения, как они представлены в графическом сканировании. Теперь есть два общих аппаратных сценария:

  • Интерфейс сканера выводит линейный сигнал, и устройство отображения затем внутренне применяет нелинейное отображение. Старые ЭЛТ-мониторы были нелинейны из-за своей физики: усилители могли вставлять только столько тока в электронный пучок, насыщение фосфора и т.д. - поэтому вся идея гамма была введена в первую очередь для моделирования нелинейностей ЭЛТ-дисплеев.

  • Современные ЖК-дисплеи и OLED-дисплеи используют либо резисторные лестницы в своих усилителях драйверов, либо имеют таблицы поиска гамма-рампы в своих процессорах изображений.

  • Некоторые устройства, однако, являются линейными, и попросите устройство, производящее изображение, предоставить надлежащее соответствие LUT для требуемого цветового профиля вывода при сканировании.

На большинстве компьютеров эффективное сканирование LUT является линейным! Что это значит? Небольшой объезд:


Для иллюстрации я быстро подключил свой аналоговый дисплей ноутбука (разъем VGA) к своему аналоговому осциллографу: синий канал по каналу видимости 1, зеленый канал - к каналу области 2, внешний запуск по сигналу синхронизации линии (HSync). Быстрая и грязная программа OpenGL, преднамеренно написанная с немедленным режимом, использовалась для создания линейной цветовой рампы:

#include <GL/glut.h>

void display()
{
    GLuint win_width = glutGet(GLUT_WINDOW_WIDTH);
    GLuint win_height = glutGet(GLUT_WINDOW_HEIGHT);

    glViewport(0,0, win_width, win_height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, 1, 0, 1, -1, 1);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glBegin(GL_QUAD_STRIP);
        glColor3f(0., 0., 0.);
        glVertex2f(0., 0.);
        glVertex2f(0., 1.);
        glColor3f(1., 1., 1.);
        glVertex2f(1., 0.);
        glVertex2f(1., 1.);
    glEnd();

    glutSwapBuffers();
}

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);

    glutCreateWindow("linear");
    glutFullScreen();
    glutDisplayFunc(display);

    glutMainLoop();

    return 0;
}

Графический выход был настроен с помощью Modeline

"1440x900_60.00"  106.50  1440 1528 1672 1904  900 903 909 934 -HSync +VSync

(потому что в том же режиме работает плоская панель, и я использую режим клонирования)

  • gamma = 2 LUT на зеленом канале.
  • linear (gamma = 1) LUT на синем канале

Вот как выглядят сигналы одной линии сканирования (верхняя кривая: Ch2 = зеленая, нижняя кривая: Ch1 ​​= синяя):

Analogue Video Signals Gamma=1 and Gamma=2

Вы можете четко видеть сопоставления x⟼x² и x⟼x (парабола и линейные формы кривых).


Теперь после этого небольшого объезда мы знаем, что значения пикселей, которые идут к основному фреймбуферу, идут туда, как они есть: линейный линейный выход OpenGL не претерпел никаких изменений, и только при применении нелинейного сканирования LUT он изменил переданный сигнал на дисплей.

В любом случае значения, которые вы представляете сканированию (что означает экранные фреймбуферы), будут подвергаться нелинейному отображению в некоторой точке цепочки сигналов. И для всех стандартных потребительских устройств это сопоставление будет соответствовать стандарту sRGB, потому что это наименьший общий коэффициент (то есть изображения, представленные в цветовом пространстве sRGB, могут воспроизводиться на большинстве выходных устройств).

Так как большинство программ, таких как веб-браузеры, предполагают, что вывод подвергается sRGB для отображения отображения цветового пространства, они просто копируют значения пикселей стандартных форматов файлов изображений в экранный кадр, как они есть, без выполнения преобразования цветового пространства, тем самым подразумевая, что значения цвета в этих изображениях находятся в цветовом пространстве sRGB (или они часто просто преобразуются в sRGB, если профиль цвета изображения не является sRGB); правильная вещь (если и только если значения цвета, записанные в фреймбуфер, будут отсканированы на дисплее без изменений, считая, что сканирование LUT является частью дисплея), будет преобразование в указанный цветовой профиль, который ожидает ожидание.

Но это означает, что сам экранный фреймбуфер находится в цветовом пространстве sRGB (я не хочу разделить волосы на то, как идиот, что позволяет, просто принять этот факт).

Как это сделать вместе с OpenGL? Прежде всего, OpenGL выполняет все операции по цвету линейно. Однако, поскольку ожидается, что сканирование будет в некотором нелинейном цветовом пространстве, это означает, что конечный результат операций рендеринга OpenGL каким-то образом должен быть включен в экранное пространство экранного фреймбуфера.

Здесь находится расширение ARB_framebuffer_sRGB (которое входит в основное ядро ​​с OpenGL-3), в котором введены новые флаги, используемые для конфигурация оконных пиксельных форматов:

New Tokens

    Accepted by the <attribList> parameter of glXChooseVisual, and by
    the <attrib> parameter of glXGetConfig:

        GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB             0x20B2

    Accepted by the <piAttributes> parameter of
    wglGetPixelFormatAttribivEXT, wglGetPixelFormatAttribfvEXT, and
    the <piAttribIList> and <pfAttribIList> of wglChoosePixelFormatEXT:

        WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB             0x20A9

    Accepted by the <cap> parameter of Enable, Disable, and IsEnabled,
    and by the <pname> parameter of GetBooleanv, GetIntegerv, GetFloatv,
    and GetDoublev:

        FRAMEBUFFER_SRGB                             0x8DB9

Итак, если у вас есть окно, настроенное с таким пиксельным форматом sRGB ивключить режим растрирования sRGB в OpenGL с помощью glEnable(GL_FRAMEBUFFER_SRGB); результат операций рендеринга линейного цветового пространства будет преобразован в цветовое пространство sRGB.

Другим способом было бы превратить все в внеблочное FBO и преобразование цвета в постобработке.

Но это только выходная сторона цепи сигнала рендеринга. Вы также получили входные сигналы в виде текстур. И это обычно изображения, причем их значения пикселей хранятся нелинейно. Поэтому, прежде чем они могут использоваться в операциях линейного изображения, такие изображения сначала должны быть представлены в линейное цветовое пространство. Пока просто игнорируем, что отображение нелинейных цветовых пространств в линейные цветовые пространства открывает несколько банок червей сам по себе - вот почему цветовое пространство sRGB настолько смехотворно мало, а именно, чтобы избежать этих проблем.

Итак, для решения этого вопроса было добавлено расширение EXT_texture_sRGB, которое оказалось настолько важным, что оно никогда не проходило через ARB, но пошел прямо в спецификацию OpenGL: вот внутренние форматы текстур GL_SRGB….

Текстура, загруженная этим форматом, претерпевает преобразование цветового пространства sRGB в линейное RGB, прежде чем использовать исходные образцы. Это дает линейные значения пикселей, подходящие для линейных операций рендеринга, и результат может быть затем корректно преобразован в sRGB при переходе на основной экранный фреймбуфер.



Личное примечание по всей проблеме: представление изображений на экранном фреймбуфере в цветовом пространстве целевого устройства. ИМХО - огромный недостаток дизайна. Нет никакого способа сделать все правильно в такой установке, не сойдя с ума.

Что действительно нужно, так это иметь экранный фреймбуфер в линейном, контактном цветовом пространстве; естественным выбором будет CIEXYZ. Операции рендеринга будут, естественно, происходить в том же цветовом пространстве контакта. Выполняя все графические операции в контактных цветовых пространствах, избегает открытия вышеупомянутых червяков, связанных с попыткой выталкивать квадратный привязку с именем linear RGB через нелинейное круглое отверстие с именем sRGB.

И хотя мне очень не нравится дизайн Weston/Wayland, по крайней мере, он предлагает возможность реально реализовать такую ​​систему отображения, предоставляя визуализацию клиентов, а композитор работает в цветном пространстве контакта и применяет вывод цветные профили устройства на последнем этапе последующей обработки.

Единственным недостатком контактных цветовых пространств является необходимость использования глубокого цвета (т.е. > 12 бит на цветной канал). На самом деле 8 бит полностью недостаточны даже при нелинейном RGB (нелинейность помогает немного скрыть отсутствие ощутимого разрешения).


Update

Я загрузил несколько изображений (в моем случае как изображения .png, так и .bmp) и проверил необработанные двоичные данные. Мне кажется, что изображения на самом деле находятся в цветовом пространстве RGB, как если бы я сравнивал значения пикселей с программой редактирования изображений с байт-массивом, который я получаю в своей программе, они отлично сочетаются. Поскольку мой редактор изображений дает мне значения RGB, это указывает на изображение, сохраненное в RGB.

Да, действительно. Если где-то в цепочке сигналов применяется нелинейное преобразование, но все значения пикселей не изменяются от изображения к дисплею, то эта нелинейность уже была предварительно применена к значениям пикселей изображения. Это означает, что изображение уже находится в нелинейном цветовом пространстве.

2 - "На большинстве компьютеров эффективный сканирование LUT является линейным! Что это значит?

Я не уверен, что смогу найти, когда эта мысль будет завершена в вашем ответе.

Эта мысль развивается в следующем разделе, где я показываю, как значения, которые вы помещаете в простой (OpenGL) фреймбуфер, идут прямо на монитор, не изменяемый. Идея sRGB заключается в том, чтобы "поместить значения в изображения точно так же, как они отправляются на монитор, и создавать потребительские дисплеи, чтобы следовать этому цветовому пространству sRGB".

Из того, что я могу сказать, поэкспериментировав, все мониторы, которые я тестировал на выходных линейных значениях.

Как вы измерили реакцию сигнала? Использовали ли вы калиброванный измеритель мощности или аналогичное устройство для измерения интенсивности света, излучаемого монитором в ответ на сигнал? Вы не можете доверять своим глазам, потому что, как и все наши чувства, наши глаза имеют логарифмический сигнал.


Обновление 2

Мне единственный способ понять, что вы говорите, чтобы быть правдой, - это то, что редактор изображений давал мне значения в пространстве sRGB.

Это действительно так. Поскольку управление цветом было добавлено ко всем широко распространенным графическим системам в качестве запоздалой мысли, большинство редакторов изображений редактируют значения пикселей в их цветовом пространстве назначения. Обратите внимание, что одним из параметров дизайна sRGB было то, что он должен просто ретроактивно указывать неуправляемые, прямые операции переноса цвета так, как они были (и в основном все еще сделаны), выполненные на потребительских устройствах. Поскольку никакого управления цветом вообще нет, значения, содержащиеся в изображениях и управляемые в редакторах, уже должны быть в sRGB. Это работает так долго, поскольку длинные изображения не синтетически создаются в процессе линейного рендеринга; в случае последующей системы визуализации необходимо учитывать цветовое пространство назначения.

Я беру снимок экрана, а затем использую программу редактирования изображений, чтобы увидеть, что значения пикселей

Это дает вам, конечно, только исходные значения в буфере сканирований без применения гамма-LUT и нелинейности отображения.