【问题标题】:How I can display in OpenGL an image using the system color profile?如何使用系统颜色配置文件在 OpenGL 中显示图像?
【发布时间】:2021-10-08 14:46:01
【问题描述】:

我正在像这样使用 OpenGL 加载纹理

glTexImage2D(
  GL_TEXTURE_2D,
  0,
  GL_RGBA,
  texture.width,
  texture.height,
  0,
  GL_RGBA,
  GL_UNSIGNED_BYTE,
  texture.pixels.data());

问题是图像的颜色与我在系统图像查看器上打开文件时看到的颜色不同。

在屏幕截图中,您可以看到系统图像查看器上显示的面部黄色颜色为 #FEDE57,但在 OpenGL 窗口中显示的是 #FEE262强>

我可以使用任何标志或格式来匹配相同的颜色校准吗?

将相同的图像显示为 Vulkan 纹理看起来不错,因此我可以放弃加载图像数据的方式没有问题。

【问题讨论】:

  • 可能是gamma
  • 我在纹理的内部格式中尝试了glEnable(GL_FRAMEBUFFER_SRGB); GL_SRGB8_ALPHA8,得到了相同的结果
  • 伽玛校正不会自动完成。您需要在读取图像时或在着色器中根据图像信息中存储的伽马值进行校正。
  • @t.niese 我该怎么做?
  • 在不知道您如何将数据读取到texture.pixels'(从文件中检索图像数据的整个过程)的情况下,无法判断您是否在那里做错了。并且 GL_SRGB8_ALPHA8 仅应在您从图像中读取的数据位于 SRGB 颜色空间中时使用。使用glEnable(GL_FRAMEBUFFER_SRGB) 并不意味着您必须使用GL_SRGB8_ALPHA8。内部格式只是说明纹理数据的格式,以便 OpenGL 可以正确地将其从 sRGB 转换为着色器中的线性颜色空间。

标签: c++ opengl colors


【解决方案1】:

最后似乎 OpenGL 中的帧缓冲区没有得到颜色校正,所以你必须告诉操作系统为你做这件事

#include <Cocoa/Cocoa.h>

void prepareNativeWindow(SDL_Window *sdlWindow)
{
  SDL_SysWMinfo wmi;
  SDL_VERSION(&wmi.version);
  SDL_GetWindowWMInfo(sdlWindow, &wmi);
  NSWindow *win = wmi.info.cocoa.window;
  [win setColorSpace:[NSColorSpace sRGBColorSpace]];
}

我在这里找到了这个解决方案https://github.com/google/filament/blob/main/libs/filamentapp/src/NativeWindowHelperCocoa.mm

【讨论】:

    【解决方案2】:

    图像和显示器都有一个伽玛值。

    如果GL_FRAMEBUFFER_SRGB 未启用,则:

    系统假定片段着色器写入的颜色位于它正在写入的图像的任何颜色空间中。因此,不执行色彩空间校正。

    (khronos: Framebuffer - Colorspace)

    所以在这种情况下,你需要弄清楚你读入的图像的伽玛值是什么,输出介质是什么,并在它们之间进行相应的转换。

    然而,要获得其中一种输出媒体并不总是那么容易。

    因此最好启用GL_FRAMEBUFFER_SRGB

    如果启用了GL_FRAMEBUFFER_SRGB,那么如果目标图像在sRGB色彩空间[…]中,那么它将假定着色器的输出是线性的RGB 色彩空间。因此,它将输出从线性 RGB 转换为 sRGB。

    (khronos: Framebuffer - Colorspace)

    因此,在这种情况下,您只需要确保您在片段着色器中设置的颜色没有应用 Gamma 校正而是线性的。

    所以你通常做的是获取图像的伽马信息,这是通过你用来读取图像的库的某个函数来完成的。

    如果您读取的图像的伽玛是gamma,您可以计算该值以使用inverseGamme = 1. / gamma 反转它,然后您可以为每个颜色通道和每个像素使用pixelColor.channel = std::pow(pixelColor.channel, inverseGamme) 来制作颜色空间线性的。

    您将在线性颜色空间中将此值用作纹理数据。

    您也可以使用 GL_SRGB8 之类的东西作为纹理,但是您需要将从图像中读取的像素值转换为 sRGB 颜色空间,这大致通过首先线性化然后应用伽玛来完成2.2

    【讨论】:

    • 我的问题似乎是在 mac 中 OpenGL 没有经过颜色校正,所以我做什么来校正伽玛并不重要。重要的是显示器的颜色校准和图像中的颜色校准
    • @ellipticaldoor 如果启用GL_FRAMEBUFFER_SRGB(也在macOS上)并在线性颜色空间中输出片段着色器中的数据,那么这个颜色将由openGL转换为sRGB颜色,然后将根据 OS/Display 的设置显示。因此,如果您在确实遵循正确颜色校正的图像查看器中打开图像,并且在将图像颜色读入应用程序并将该线性化颜色用于纹理时对图像颜色进行了线性化,那么图像应该看起来相同。跨度>
    • 我已经在这样做了,但没有应用颜色校正
    • 但是即使我校正了图像的伽玛,也只能在一台显示器上工作,对吧?每个屏幕上的伽玛校正都会不同
    • @ellipticaldoor 如果您在一台 PC 上的图像查看器和 OpenGL 中打开图像,那么当它们显示在同一监视器上时,它们看起来应该相同。如果您在一台 PC 上的图像查看器中打开图像并将它们显示在不同的显示器上,那么它们看起来可能会有所不同。如果在不同的 PC 上查看也是如此。如果所有显示器都以相同的方式校准,并且您有理想的条件,那么这些图像在所有显示器上应该看起来相同,即使它们在不同的 PC 上。但这适用于任何图像处理程序、软件、游戏,并且与 openGL 无关。
    【解决方案3】:

    @Tokenyet 和@t.niese 非常正确。

    您需要将最终颜色的rgb 值近似为1.0/2.2。有点像这样:

    FragColor.rgb = pow(fragColor.rgb, vec3(1.0/gamma)); //gamma --&gt; float = 2.2

    注意:这应该是片段着色器中的final/last 语句。在此之前进行所有光照和颜色计算,否则结果会很奇怪,因为您将混合 linearnon-linear 光照(计算)。

    您需要进行伽马校正的原因是人眼对颜色的感知与计算机输出的不同。

    如果光强度(勒克斯)增加两倍,您的眼睛确实会看到两倍的亮度。然而,当实际亮度增加两倍时,会以对数(或指数?,请在此纠正我)关系增加。两个照明空间之间的比例常数为^2.2(或^(1.0/2.2),如果你想反其道而行之(这就是你要找的)。

    欲了解更多信息:看看这个伟大的tutorial 伽马校正!

    注意 2:这是一个近似值。每台计算机、程序、API 都有自己的自动伽马校正方法。与 OpenGL 相比,您的系统图像查看器可能有不同的 gamma 校正方法(或者甚至没有任何方法)

    注意 3:顺便说一句,如果这不起作用,如果您知道的话,可以手动调整片段着色器中的颜色。

    #FEDE57 = RGB(254, 222, 87)

    转换成OpenGL颜色坐标的是,

    (254, 222, 87) / 255 = vec3(0.9961, 0.8706, 0.3412)

    【讨论】:

    • 似乎如果我将图像的配置文件更改为与我的显示器相同,那么图像看起来不错。如果我在着色器中进行伽马校正,输出将根据加载图像的颜色配置文件而有所不同
    • 没错,在我的回答中再次提到Note 2。如果您对结果仍然不满意,请查看Note 3,这可能会有所帮助,祝您好运!
    • 但是在着色器中调整会不正确,这取决于图像的颜色配置文件对吧?
    • @t.niese 你知道如何进行这种转换吗?我真的找不到任何关于这个的东西
    • @ellipticaldoor 抱歉回复晚了,可能有办法。您想要颜色#FEDE57,即vec3(0.9961, 0.8706, 0.3412),对吗?首先你必须找到伽玛校正之间的比例常数:所以把你的颜色,vec3(0.9961, 0.8706, 0.3412)放入片段着色器--&gt;OpenGL Gamma Corrects in its own way --&gt;OpenGL输出颜色--&gt;检查颜色的@987654339 @ 值并找到与原始颜色的比较(比例常数)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-24
    • 2011-08-06
    • 2011-05-18
    • 1970-01-01
    • 1970-01-01
    • 2016-01-20
    相关资源
    最近更新 更多