【问题标题】:How do I deal with color spaces and gamma in the PNG file format?如何处理 PNG 文件格式的色彩空间和伽玛?
【发布时间】:2013-12-16 23:24:18
【问题描述】:

这是我的问题:

我正在使用光谱样本进行一些渲染,并希望保存显示结果的图像。我通过 CIE XYZ 颜色匹配函数对我的光谱功率函数进行加权以获得 XYZ 颜色空间结果。我将此 XYZ 颜色元组乘以 this page 给出的矩阵以转换为 sRGB,并将结果钳制为 (0,1)

为了保存图像,我将转换后的元组缩放 255 并将其转换为字节,然后将数组传递给 libpng 的png_write_image()。当我查看以这种方式渲染的均匀强度、纯色谱时,它看起来是错误的;颜色之间的过渡中有暗带。这可能并不令人惊讶,因为要从 XYZ 转换为 sRGB,矩阵之后的颜色分量 must be raised to 2.4 会相乘(或者如果它们足够小,则进行线性缩放)。但如果我这样做,它看起来更糟!只有在加注到 1/2.2 之后,它才开始看起来正确。看起来,在我没有做任何事情的情况下,解码图像的伽马值约为 2.2,两次

这是我期望它工作的方式:我将矩阵应用于 XYZ,并且我有一个大致能量线性的 RGB 元组。我将它提高到 2.2,现在有一个感知线性颜色元组。我按原样对这些数字进行编码(从而有效利用文件精度),并在文件中存储一个字段,说明“这些字节已使用 gamma 2.2 编码”。然后在图像加载时,解码系统取消应用编码的伽玛,然后在显示之前应用系统伽玛。 (因此从创作的角度来看,我不必关心观众的系统伽玛是什么)。但我得到的结果表明它不能以这种方式工作。

更糟糕的是,我尝试使用 2.2 和 1/2.2 调用 png_set_gAMA(),但在图像中看不到任何差异。我用png_set_sRGB() 得到了类似的结果(我相信这应该迫使伽马为1/2.2)。 关于我应该如何转换我的颜色值,或者 PNG 如何处理伽马和颜色空间,我一定有一些倒退或不理解的东西。将其分解为几个明确的问题:

  • 我希望传递给write_png() 的字节值的颜色空间是什么?
  • 我必须对 libpng 进行哪些调用(如果有),以指定传递字节的色彩空间和 gamma,以确保正确显示?为什么他们会失败?
  • png 文件中的 gamma 字段与我应用于传递的颜色通道值(如果有)的指数有什么关系?
  • 如果希望我在发送图像数据之前反转 gamma 曲线(我对此表示怀疑,但现在似乎有必要),那么该反转是否应该包括 sRGB 曲线的线性部分?

此外,我发现“白点”在 XYZ 和 sRGB 之间的转换中很重要。我不清楚上面给出的站点中的矩阵是否包括对 D65 的重整化(它与 Wikipedia 的矩阵不匹配) - 甚至何时需要进行这种转换。我发现的大多数文献都掩盖了细节。维基文章中没有提到转换中的另一个步骤,还是会自动处理?

【问题讨论】:

标签: graphics colors png libpng color-space


【解决方案1】:

这几乎是您所期望的方式。 png_set_gAMA() 使 libpng 编写一个 gAMA 输出PNG文件中的块。它不会改变像素本身。符合 png 的 查看器应该使用块中的伽马值,结合显示器的伽马,在显示器上正确写入像素强度值。大多数解码器实际上不会执行您描述的两步(取消应用图像伽玛,然后应用系统伽玛)方法,尽管结果在概念上是相同的:它将图像伽玛与系统伽玛结合以创建查找表,然后使用该表格一步转换像素。

根据您的观察结果(gamma=2.2 和 gamma=1/2.2 的行为相同),您使用的查看器似乎对 PNG gAMA 块数据没有任何作用。

【讨论】:

    【解决方案2】:

    您写道:“看起来,在我没有做任何事情的情况下,解码后的图像应用了两次 ~2.2 的 gamma。”

    我认为您的显示器(硬件或系统 icc 配置文件)本身已经设置了 gamma。

    【讨论】:

      【解决方案3】:

      你说:

      因为要从 XYZ 转换为 sRGB,矩阵乘法后颜色分量必须提升到 2.4...

      不,这是不正确的。从线性 (XYZ) sRGB,您确实提升到 2.4 或 2.2,即从 sRGB 到线性。 p>

      从线性到 sRGB,您提高到 ^(1/2.2),或者如果分段使用 sRGB,您将看到 1/2.4 — 您应用的有效伽马为 ^0.45455

      在您链接的维基百科页面上,这是 FORWARD 转换。

      从 XYZ 到 sRGB:

      那当然是在应用正确的矩阵之后。假设一切都在 D65 中,那么:

      直说线性

      现实世界中的光是线性的。如果你将 100 个光子增加三倍,那么你就有 300 个光子。但是人眼看不到三倍,相比之下,我们只看到了适度的增长。

      这就是为什么要使用传输曲线或“伽玛”的部分原因,以充分利用 8 位图像中的可用代码空间(我知道这过于简单化了)。

      为此,将线性光值提高到 0.455 的幂,并将 sRGB 值返回到线性空间,然后我们将其提高到逆,即 ^1/0.455 也称为 ^2.2

      矩阵的使用必须在线性空间中完成。但是在转换矩阵之后,您需要应用 trc 或“gamma”编码。根据您的陈述,不,事情没有两次添加 2.2,您只是走错了路。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-10-28
        • 2018-12-04
        • 2018-09-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-07
        相关资源
        最近更新 更多