【问题标题】:Color spaces, gamma and image enhancement色彩空间、伽玛和图像增强
【发布时间】:2011-06-18 17:52:35
【问题描述】:

色彩空间。好了,大家都知道RGB了:在[0.0,1.0]范围内归一化的三个值,分别代表颜色分量Red Green Blue的强度;这个强度是线性的,不是吗?

伽玛。据我所知,gamma 是将 RGB 颜色分量映射到另一个值的函数。谷歌搜索,我看到了线性函数和非线性函数...... 线性函数似乎可以缩放 RGB 分量,因此似乎可以调整图像亮度;非线性函数似乎可以“解压缩”较暗/较亮的组件。

现在,我开始实现一个图像查看器,它将不同的图像格式显示为纹理。我想修改这些图像的伽玛,所以我应该建立一个片段着色器并在纹理四边形上运行。很好,但是如何确定正确的伽马校正?

OpenGL 使用线性 RGB 颜色空间,使用浮点组件。实际上,我可以从这些值(具有特殊的浮点精度)开始计算伽玛校正值,因此它们在钳制伽玛校正值后显示。

首先,我将确定伽马斜坡。我怎么能确定呢? (分析或使用查找表)

然后,我开始研究OpenGL扩展EXT_framebuffer_sRGB,它似乎与扩展EXT_texture_sRGB非常相关。

EXT_texture_sRGB 引入了一种新的纹理格式,用于将文本值线性化到 RGB 线性空间中。 (脚注1)通过这种方式,我知道sRGB色彩空间并将其用作线性RGB色彩空间。

相反,EXT_framebuffer_sRGB 扩展允许我将线性 RGB 值编码到 sRGB 帧缓冲区,而无需担心。

...

等等,所有这些信息是为了什么?如果我可以使用 sRGB 帧缓冲区并加载 sRGB 纹理,则无需 sRGB 转换即可处理该纹理...为什么要更正伽玛?

即使在 sRGB 缓冲区上,我也可以同样校正伽玛吗?或者我最好不要?以及亮度和对比度:它们应该在伽马校正之前还是之后应用?

这是很多信息,我现在感到困惑。希望你们中的某个人能更多地向我解释所有这些概念!谢谢。

...

还有一个问题。如果设备伽玛不同于“标准”2.2,我如何“累积”不同的伽玛校正?我不知道是否清楚:如果图像 RGB 值已经针对 gamma 值为 2.2 的显示器进行了校正,但显示器的 gamma 值为 2.8,我该如何校正 gamma?


(1) 这里有一些摘录来强调我的意思:

sRGB 色彩空间基于典型(非线性)显示器 在光线昏暗的办公室中预期的特征。它一直 由国际电工委员会 (IEC) 标准化 为 IEC 61966-2-1。 sRGB色彩空间大致对应2.2 伽玛校正。


此扩展是否提供任何类型的 sRGB 帧缓冲格式 或保证使用 sRGB 纹理渲染的图像“看起来不错” 何时输出到支持 sRGB 颜色空间的设备?

   RESOLVED:  No.

  Whether the displayed framebuffer is displayed to a monitor that
    faithfully reproduces the sRGB color space is beyond the scope
    of this extension.  This involves the gamma correction and color
    calibration of the physical display device.

    With this extension, artists can author content in an sRGB color
    space and provide that sRGB content for use as texture imagery
    that can be properly converted to linear RGB and filtered as part
    of texturing in a way that preserves the sRGB distribution of
    precision, but that does NOT mean sRGB pixels are output
    to the framebuffer.  Indeed, this extension provides texture
    formats that convert sRGB to linear RGB as part of filtering.

    With programmable shading, an application could perform a
    linear RGB to sRGB conversion just prior to emitting color
    values from the shader.  Even so, OpenGL blending (other than
    simple modulation) will perform linear math operations on values
    stored in a non-linear space which is technically incorrect for
    sRGB-encoded colors.

    One way to think about these sRGB texture formats is that they
    simply provide color components with a distribution of values
    distributed to favor precision towards 0 rather than evenly
    distributing the precision with conventional non-sRGB formats
    such as GL_RGB8.

【问题讨论】:

  • 我会说我将在不适合消费者的显示器上渲染,但它实际上专门用于 HDR 图像处理。目前我没有显示器规格,但我怀疑我应该在渲染期间应用伽马校正。

标签: opengl rgb gamma srgb gamma-distribution


【解决方案1】:

不幸的是,OpenGL 本身并没有定义颜色空间。只是定义了传递给 OpenGL 的 RGB 值形成一个线性向量空间。然后将渲染帧缓冲区的值原样发送到显示设备。 OpenGL只是传递值。

Gamma 有两个用途:

  • 感官知觉是非线性的
  • 在过去,显示设备具有非线性响应

伽马校正用于对两者进行补偿。

转换只是“线性值 V 到某个幂 Gamma”,即 y(v) = v^gamma

色彩空间转换涉及从输入值到发送到显示器的完整链,因此这包括伽马校正。这也意味着您不应该自己操纵伽马斜坡。

很长一段时间以来,典型的 Gamma 值曾经是 2.2。然而,这导致了一些不希望的低值量化,因此 Adob​​e 引入了一个新的色彩空间,称为 sRGB,它具有低值的线性部分和较高值的指数约 2.3 的幂函数。如今,大多数显示设备都使用 sRGB。此外,如今大多数图像文件都是 sRGB。

因此,如果您有 sRGB 图像,并在 sRGB 显示设备上按原样显示,并在设备上配置了线性伽马斜坡(即视频驱动程序 gamma=1),那么您只需使用 sRGB 纹理和帧缓冲区即可并且不做任何其他事情。

由于 cmets 而编辑

总结一下:

如果您的系统不支持 sRGB 帧缓冲区:

【讨论】:

  • 在我交换它之后,OpenGL 驱动程序确实正确的帧缓冲 RGB 值吗?在这种情况下,如果我想在我的着色器中应用 gamma 校正,仅针对我的应用程序,我将检测当前系统设置,不是吗?
  • @Luca:作为一般规则,您应该坚持线性颜色转换;不仅在 OpenGL 中,而且在所有情况下。如果您知道驱动程序和显示设备应用的确切转换,您可以将其考虑在内。此外,一些显示驱动程序(专业显卡的驱动程序)提供特殊的像素格式配置,其中来自应用程序的值直接馈送到设备而无需中间校正。只有在这种情况下,您才能安全地应用非线性变换,但当然必须自己进行所有校正。
  • @Luca:忘记输出端的伽马校正。而是应用逆伽马校正,在将图像数据传递给 OpenGL 之前将其线性化。如果您的图像有一个 2.6 的 gamma,则应用 1/2.6 的 gamma,然后将其传递给 OpenGL。幸运的是,sRGB 使用起来有点麻烦,简单的伽马校正并不能解决问题。这就是 EXT_texture_sRGB 的用武之地。
  • @datenwolf 你能验证我是否正确吗?使用 sRGB 帧缓冲区时,值存储在 sRGB 空间本身中,而所有涉及的操作将自动转换为在线性空间中执行。这比使用常规线性颜色缓冲区然后在后期处理中进行伽马校正(使用着色器)的手动方法产生更高的质量。因为 sRGB 帧缓冲区线性操作将在硬件中以全精度执行,而手动方法在每次传递时将值截断为 8 个线性位。
  • @StevenLu:不,质量没有下降,因为在着色器中,所有值都可以保存并计算为超过 8 位的浮点值。但由于驱动程序内置了优化,使用 sRGB 纹理和帧缓冲区可能会带来更好的性能。但你是对的,颜色留在 sRGB 空间中,只有在采样和混合时才会线性化,而当片段转移到屏幕上时会去线性化。
【解决方案2】:

等等,所有这些信息是为了什么?如果我可以使用 sRGB 帧缓冲区并加载 sRGB 纹理,则无需 sRGB 转换即可处理该纹理...为什么要更正伽玛?

一般来说,你不会。 sRGB 纹理和帧缓冲区的目的是让您不必手动进行伽马校正。来自 sRGB 纹理的读取被转换为线性色彩空间,写入 sRGB 帧缓冲区采用线性 RGB 值并将它们转换为 sRGB 值。这完全是自动的,而且在性能方面免费

您需要进行伽玛校正的唯一情况是显示器的伽玛与 2.2 伽玛的 sRGB 伽玛近似值不匹配。很少有显示器能做到这一点。

您的纹理必须在 sRGB 颜色空间中。但是,大多数图像创建应用程序会将图像保存在 sRGB 中并使用 sRGB 中的颜色,因此无论您是否希望它们存在,您的大多数纹理都已经在 sRGB 中。 sRGB 纹理功能只是让您真正获得正确的颜色值,而不是您到现在为止一直得到的颜色值。

以及亮度和对比度:它们应该在伽马校正之前还是之后应用?

我不知道你所说的亮度和对比度是什么意思。这应该由监视器设置,而不是您的应用程序。但几乎所有您想要对图像数据执行的数学运算都应该在线性色彩空间中完成。因此,如果给定 sRGB 颜色空间中的图像,则需要对其进行线性化,然后才能对其进行任何数学运算。 sRGB 纹理功能让这一切变得免费,而无需进行复杂的着色器数学运算。

【讨论】:

  • 我如何知道图像加载器函数实际上给了我 sRGB 值还是已经校正的 RGB 值? (是的,声明太宽泛了;即将 jpeglib 和 openexr 设置为图像加载器)。
  • @Luca OpenEXR 用于浮点图像。那些应该在线性色彩空间中,无论如何浮点图像都不允许使用 sRGB。 JPEG 格式有颜色配置文件,可以告诉数据是什么颜色空间,但 sRGB 在那里很常见。同样,PNG 可以嵌入颜色配置文件信息。
  • 没错,OpenEXR 应该是线性的。不幸的是,有些程序会发出非线性 OpenEXR。因此,如有疑问,请仔细检查。
【解决方案3】:

RGB

RGB:在[0.0,1.0]范围内归一化的三个值,表示颜色分量Red Green Blue的强度; 这个强度是线性的,不是

没有。除非定义了与特定空间/编码的相关性,否则 RGB 值是无意义的数字。它们可能是线性的、伽马编码的或对数编码的,或者使用像 Rec709 和 sRGB 规范这样的复合传输曲线。

此外,它们与颜色空间中定义的原色和白点相关,例如,sRGB 中的#00FF00 与 DCI-P3 中的#00FF00 是不同的颜色。

要定义 RGB 像素值的显示方式,您不仅需要 RGB 三元组,还需要知道它所针对的色彩空间,其中需要包括主坐标、白点和传输曲线。

sRGB 是 Web 和通用计算的默认“标准”RGB 颜色空间。它与 HDTV 的标准色彩空间 Rec709相关

伽玛又名转移曲线

伽玛。据我所知,gamma 是将 RGB 颜色分量映射到另一个值的函数。

图像伽玛利用人类感知的非线性来充分利用每通道图像 8 位的有限数据大小。人眼对较暗颜色的变化更敏感,因此在伽马编码图像中使用更多位 ae 来定义较暗颜色。

在数字之前,伽马也用于 NTSC 广播系统,它可以抑制信号中的明显噪声,其方式类似于图像伽马如何防止每通道 8 位图像出现“条带”伪影。

首先,我将确定伽马斜坡。我怎么能确定呢? (分析或使用查找表)

伽玛 曲线。 sRGB 伽玛曲线很容易访问。这是从 sRGB 到线性的 Wikipedia link。您还可以使用简单地使用 2.2 指数曲线的“简化”方法:

linearVideo = sRGBvideo^2.2 和简化的逆,回到 sRGB:

sRGBvideo = linearVideo^0.4545

使用简化版会引入一些轻微的 gamma 错误,建议在关键操作或图像会多次“往返”的情况下使用“正确”曲线。

还有一个问题。如果设备伽玛不同于“标准”2.2,我如何“累积”不同的伽玛校正?我不知道是否清楚:如果图像 RGB 值已经针对 gamma 值为 2.2 的显示器进行了校正,但显示器的 gamma 值为 2.8,我该如何校正 gamma?

2.8 ???那是什么显示器?朋友?这很不寻常——虽然 PAL 规范这么说,但 2.8 并不“实用”。监视器通常在 2.3 到 2.5 左右,具体取决于它们的设置方式。当您调整黑电平和对比度(白电平)时,您实际上是在调整感知伽马以匹配观看环境(房间照明)。

仅供参考,虽然 sRGB“信号”的编码伽马为 1/2.2,但显示器通常会增加约 1.1 的指数

对于 Rec709,编码信号的有效伽马约为 1/1.9 ish,但参考观看环境中的监视器约为 2.4

在这两种情况下,都有一个有意的系统伽马增益。

如果您想使用 2.8 显示器的 gamma 编码图像并且不希望系统 gamma 增益,则指数为 1/2.8

通常使用的“最高”伽马用于数字电影(以及 Rec2020),为 2.6 对于那些认为 PAL 和 2.8 的人,我鼓励您阅读有关该主题的 Poynton:

强烈推荐阅读

Charles Poynton's Gamma FAQ 易于阅读并完整地描述了这些问题以及它们在图像管道中的重要性。还可以在同一链接阅读他的颜色常见问题解答。

关于 LINEAR 与 sRGB 的几句话

在线性工作空间中处理图像通常是理想的,因为它不仅可以简化数学运算,而且可以模拟现实世界中的光线。世界上的光以线性方式(加法)工作。但如果是线性工作,则需要足够的位深度,8位是不够的。

人类的感知是非线性的。图像伽玛编码利用非线性来充分利用 8 位图像容器。当您转换为线性时,您需要更多的位。每个通道 12 位被认为是最低要求,但 16 位浮点数是线性工作空间的最低“推荐最佳实践”。

如果在线性渲染环境中使用纹理,则需要将这些纹理转换为线性空间(通常是更深的位深度)。虽然添加的位数增加了数据带宽,但简化的数学运算通常允许更快的计算。

sRGB 是一个 DISPLAY REFERRED 空间,它用于显示目的,并用于将图像存储在紧凑的“显示就绪”状态。黑为0,白为255,传递曲线接近1/2.2

sRGB 基于 Rec709 (HDTV),使用相同的原色和白点。但传输曲线和数据编码不同。 Rec709 旨在在黑暗的客厅中显示在更高伽马监视器上,并在 16 和 235 处编码黑色。

【讨论】:

    猜你喜欢
    • 2013-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-24
    • 1970-01-01
    • 2013-03-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多