什么是伽马校正的必要性?

9

我有困难完全理解伽马校正的必要性,希望你们能帮助我。

假设我们想显示256个相邻像素,这些像素应该是从黑色到白色的平滑渐变。为了表示它们的颜色,我们使用线性灰度值从0..255。由于人眼的非线性,显示器不能只将这些值转换为线性亮度值。如果相邻像素具有亮度值(1/256)*I_max, (2/256)*I_max等,我们会感觉在较暗的区域中两个像素之间的亮度差异过大(渐变不平滑)。

幸运的是,显示器与人眼的非线性是相反的。也就是说,如果我们将线性灰度值0..255放入帧缓冲区,那么显示器会将它们转换为非线性亮度值x^gamma。然而,由于我们的眼睛是相反非线性的,我们会感知到平滑的线性渐变。显示器和我们眼睛的非线性互相抵消了。

那么,我们为什么需要伽马校正呢?我读过一些书,其中提到我们总是希望显示器产生线性亮度值。根据他们的说法,在将灰度值写入帧缓冲区之前,必须补偿显示器的非线性。这是通过伽马校正来完成的。然而,我的问题在于 - 就我所理解的而言 - 当显示器产生线性亮度值时,我们不会感知到线性亮度值(即我们不会感知到平滑、稳定的渐变)。

就我所看到的,如果我们将线性灰度值放入帧缓冲区,那么它们会被显示器转换为非线性亮度值,我们的眼睛会再次感知到线性亮度值,因为眼睛是相反非线性的。没有必要对帧缓冲区中的灰度值进行伽马校正,也没有必要强制显示器产生线性亮度值。

我的理解是否正确?谢谢

3个回答

6
让我“复活”这个问题,因为我现在也在疑惑类似的问题,我认为我已经找到了答案 - 这可能对其他人有用。或者我可能是错的,希望有人能告诉我 :)
我认为你的思考方式没有问题。问题是,如果你知道你在做什么,你不需要一直进行伽马校正。这取决于你想要实现什么目标。让我们看看两种不同的情况。
A) 光线模拟(又称渲染)。您有一个漫反射表面,上面有一盏指向它的灯光。然后,将增加灯光的强度。
好吧。让我们看看在这种情况下真实世界会发生什么。假设有一个纯粹的漫反射表面,则反射光的强度将是表面反照率乘以入射光强度和入射光角度及法线的余弦值。无论如何,当入射光强度加倍时,反射光强度也会加倍。这就是为什么光线传输被称为线性过程的原因。有趣的是,您不会感觉到表面的亮度增加了一倍,因为我们的感知是非线性的(这是由所谓的史蒂文斯幂定律建模的)。再说一遍:在真实世界中,反射光加倍了,但您不会感知它增加了两倍亮度。
那么,我们该如何模拟这种情况呢?好吧,如果我们有一个带有表面反照率的sRGB纹理,我们需要将其线性化(通过去校正来解除伽马校正,这意味着应用2.2伽马)。现在它是线性的,并且我们有光强度,我们可以使用我之前提到的公式来计算反射光强度。由于我们处于线性空间中,通过加倍强度,我们将加倍输出,就像在真实世界中一样。现在我们对结果进行伽马校正。因此,当屏幕显示渲染图像时,它将应用伽马,并且具有线性响应,这意味着模拟两倍强光时屏幕发出的光强度将是原始光的两倍。因此,从屏幕到您的眼睛到达的光的强度将增加一倍。当然,您不会感知第二次渲染的亮度加倍,但是,正如我们之前所说,这恰恰是在真实情况下会发生的。在真实世界和模拟中具有相同的行为意味着模拟(渲染)是正确的 :)
B) 另一种情况恰恰是如果您想要一个渐变,您希望它“看起来”(也就是被感知)是线性的。
由于您想要屏幕的非线性响应取消我们的非线性视觉感知,因此可以完全跳过伽马校正(正如您所建议的那样)。或者更准确地说,保持在线性空间中并进行伽马校正,但是不使用连续值(1、2、3...255)创建渐变,因为这些值会由于Steven's而被视为非线性,而使用通过我们的感知亮度响应的倒数转换的值(即将归一化的值应用1/0.5=2的指数。这是应用于亮度的Steven的倒数指数)。
事实上,如果您看到像http://scanline.ca/gradients/网站上的经过伽马校正的线性渐变,您根本无法将其视为线性:您会看到低强度的变化比高强度的变化多得多(正如预期的那样)。
好吧,至少这是我目前对该主题的理解。我希望它可以帮助任何人。再次强调,请,如果有错误,请指出,我将不胜感激…

我理解的方式和你一样。 - v.oddou

3
问题实际上出在进行颜色计算时。举个例子,如果你要混合两种颜色,你需要使用线性强度来进行计算。为了显示正确的结果,你需要将线性强度转换回伽马校正强度。
你的眼睛感知强度并不重要。为了正确地进行颜色计算,必须基于光学的物理原理,依赖于线性亮度值进行计算。一旦你计算出一种颜色,你希望这些亮度值由你的显示器输出,无论它如何被感知,因此你必须补偿监视器不能直接产生你想要的颜色的事实。

为了实际显示正确的结果,您需要将线性强度转换回伽马校正强度。为什么?我为什么要计算伽马校正强度呢?正如我试图解释的那样,如果我只将普通的线性值放入帧缓冲区,那不就可以了吗?显示器会将它们转换为非线性亮度值(因为其非线性),是的。但是由于我们的眼睛具有倒数非线性,因此我们应该感知线性梯度。我的错误在哪里? - user1494080
1
@user1494080:你的眼睛如何感知颜色并不相关。颜色计算不是基于感知强度完成的。你已经计算出一种颜色,这就是你希望显示器显示的颜色,无论它被感知为何种颜色。你必须补偿这样一个事实:显示器不能直接产生所需的强度。 - Vaughn Cato
1
@user1494080,如果显示器被设计为输入线性值,那么你是正确的。但它们并没有,这一点的起源可以追溯到电视历史的早期。 - Mark Ransom
@user1494080,有一份我非常喜欢的文档:“Gamma FAQ” http://www.poynton.com/PDFs/GammaFAQ.pdf Gamma就像大/小端一样,我们经常会过度处理而出错。让我们都花时间来充分消化它。Vaughn所说的是关键。你计算一个物理值(线性),显示器以2.2次方升高显示它,因此在写入帧缓冲之前需要抬高到1/2.2次方。当然,这只适用于您真正在线性空间中工作的情况。要注意您的数据源。大多数情况下,数据源都在伽马空间中(纹理、照片)。 - v.oddou

0

实际上回答这个问题,你的看法并没有错。拥有一个线性帧缓冲区肯定是很好的,但正如你所说,拥有一个8位线性帧缓冲区肯定不是很好。

8位非常容易处理,这就是伽马压缩帧缓冲区和颜色标记(比如HTML的#888 - 使用#333代替中灰色不是很酷)的唯一理由。

关于显示器 - 你想要能够预测它对你的输入的响应,并且你知道从sRGB中它应该是什么样子的。通常这就是你需要知道的全部。有些人认为如果显示器产生“线性”输出,那么就是“正确”的或者其他什么东西,如果你补偿了显示器的伽马,就可以模拟出来。我建议避免这种设置,因为这会破坏所有应用程序,这些应用程序(正确地和合理地)假设标准伽马,而不是假设错误的线性。不要这样做。相反,修复应用程序或者放弃它们。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接