色彩模型解析:人类视觉与设备渲染的技术原理
图像在屏幕上的呈现
从屏幕开始分析,图像是由屏幕像素发光区域组成的集合。每个屏幕像素以不同的强度和波长发射光线。这种波长差异被人类(以及猫,但那是另一个话题)感知为颜色差异。
注意: 光可以被视为微小粒子(光子)集合或不可见的电磁波。需要注意的是,只有少数设备能发射"纯"(单色)颜色——即单一波长的颜色。大多数时候,我们感知到的是不同波长混合而成的颜色,而非单一波长。我们显示器中的二极管不发射"纯"颜色。
人类眼睛和大脑中的图像处理
屏幕上图像的光线通过瞳孔,经晶状体折射,聚焦在视网膜上。视网膜包含特殊的细胞,称为视杆细胞和视锥细胞。视杆细胞帮助我们在弱光下视物,但它们不检测不同波长——这就是为什么在黑暗中一切看起来都是灰色阴影的原因。然而,在日光条件下,视杆细胞不活跃。我们感兴趣的大多数模型都是为日光条件构建的。
视锥细胞负责色彩视觉。有三种类型,每种类型对略微不同的波长谱敏感。S-视锥细胞对蓝色最敏感,M-视锥细胞对绿色最敏感,L-视锥细胞对红色最敏感。这些细胞的信号会考虑光敏感性。视网膜处理所有这些细胞的信号,然后将信号发送到大脑。
本质上,光信号可以分解为来自不同细胞类型的三种响应,每种覆盖一个宽谱。我们的大脑和神经系统无法直接处理这个谱,因此它们使用机制来解释它。基本上,红色、绿色和蓝色信息被映射到另外三个参数:亮度、红-绿和蓝-黄。这种映射使我们能够区分一种颜色与另一种颜色。实际上,颜色并不存在——它们只是我们人类感知电磁波的方式。
注意: 亮度和亮度是不同的概念。亮度是以坎德拉每平方米测量的物理量,而亮度基于人类感知并与光照条件相关(例如,灯是开还是关)。
大脑在检测图案和边缘方面比缓慢变化的梯度要好得多。还有专门负责边缘检测的机制。然而,人类对高频空间成分不太敏感。
原始图像在左侧,右侧图像是边缘检测算法的输出。尽管原始图像的大部分信息被移除,你仍然可以感知到长凳上的乌鸦。
人们对图像的感知方式极大地影响了图像数据的存储和处理方式。图像格式不仅仅是关于以最有效的方式保存像素——它们需要在考虑人类感知和显示设备特性的同时压缩信息。
研究和纸张上的颜色
CIE(国际照明委员会)进行了大量实验,创建了代表平均观察者感知光线的色彩模型。
第一个例子显示了平均观察者如何感知不同波长(即不同颜色):
从图中可以明显看出,我们对绿光敏感得多。
眼睛中视锥细胞的机制导致了您可能熟悉的第一个颜色表示:RGB,分别对应每种视锥细胞类型的红色、绿色和蓝色。我们有CIE图表——颜色匹配函数。这些函数代表不同类型视锥细胞的不同响应。
我们可以使用此图获取颜色的RGB表示。要获得三个数字,我们需要对光包含的每个波长的响应求和。这些数字将代表我们的信号。是的,不同的光信号可以具有相同的RGB分量。
您可能还注意到上一个图表的问题:红色敏感性变为负值,当然,没有负颜色。为了解决这个问题,CIE提出了另一种称为XYZ的颜色表示,它是RGB的简单变换,没有负值。
结果,我们得到了这样的图表:
让我们看看它是如何从RGB推导出来的:
|
|
注意绿色的大系数。人眼对绿光最敏感,因此绿色的系数应该相当高。Y代表感知亮度,这至关重要,因为人类可以快速注意到亮度的变化。这就是为什么这些信息需要尽可能准确地存储和表示。X和Z负责颜色。这使我们能够将颜色信息与亮度分开,这与大脑处理信号的方式相关。
色彩空间
现在我们有了三个数字来表示光信号。所有这些数字的三元组构成了一个色彩空间。我们也可以将其表示为3D形状。如果您有Mac,可以使用ColorSync Utility应用程序查看其外观。
然而,3D并不总是方便。让我们通过丢弃亮度(Y)来展平图片。我们将得到一个著名的色度图。
注意: 在绘制色度之前,我们需要通过除以X + Y + Z来归一化X和Z值。
鞍形图代表了标准CIE观察者可以感知的所有颜色。此图和XYZ色彩空间的问题是,它不代表观察者感知的颜色差异。它对于编码像素值效率低下,因为许多XYZ值不对应可感知的颜色,这会导致比特浪费。
然而,XYZ是构建设备特定色彩空间的非常有用的工具。每个设备都有其独特的颜色渲染特性。例如,两个红色物体在两个设备上可能看起来略有不同。为了解决这个问题,引入了设备特定的色彩空间。
以下是一个大致的工作原理:我们取对应于(1, 0, 0)的红色信号,测量设备发射的光,计算该点的XYZ。然后我们对绿色、蓝色和白色(白色是当所有RGB值都最大时)执行相同的操作。这些XYZ点称为RGB颜色原色。
瞧,我们得到了一组系数,用于将设备特定的RGB原色转换为设备无关的XYZ值,反之亦然。我们通常在网络上使用的RGB称为sRGB或标准RGB。它是针对"标准"设备的一组特定系数。这里是它们:
|
|
|
|
sRGB无法代表人眼可以感知的所有可能颜色。让我们回到我们的图表。这里是所有可能的颜色:
这里是用于获取sRGB的RGB系数的点。我们受sRGB三角形的限制,因此无法表示更多颜色:
Lab* 中的颜色
为了解决颜色距离的问题,CIE引入了另一个色彩空间——CIE Lab*,可以从XYZ推导出来。为了使其表示类似于人类感知的颜色接近度,XYZ中的所有坐标都以特定方式转换。这些转换不是线性的(仅用线性变换表示颜色接近度是不可能的)。L* 表示亮度并从Y推导,a* 和 b* 表示颜色维度并从X和Z推导。
Lab色彩空间使用两个轴表示颜色:a* 和 b*。a* 编码红-绿分量,而 b* 编码蓝-黄分量。在 Lab* 色彩空间中,无法表示同时具有强绿色和红色分量的光信号。然而,a* 和 b* 可以是负值。对于RGB,这也是不可能的:如果我们做类似(1, 1, 0)的事情,我们会得到黄色。
让我们看看在将RGB转换为Lab的示例中它是如何工作的。
| 颜色 | sRGB | Lab (L*, a*, b*) | 解释 |
|---|---|---|---|
| 红色 | 1, 0, 0 | 53.23, 80.11, 67.22 | +a* (强红), +b* (偏黄) |
| 绿色 | 0, 1, 0 | 87.74, -86.18, 83.19 | -a* (强绿), +b* (偏黄) |
| 蓝色 | 0, 0, 1 | 32.30, 79.20, -107.85 | +a* (偏红), -b* (强蓝) |
| 黄色 | 1, 1, 0 | 97.14, -21.55, 94.49 | -a* (轻微绿), +b* (强黄) |
这些类型的色彩空间称为基于对立色的。大脑处理信号的方式被编码到色彩空间中。Lab空间中的两种颜色之间的距离被设计为映射到感知距离。看例子:第一行中两种颜色之间的距离是7.5,第二行中是148.09。
如果两种颜色对人来说看起来相似,它们在Lab空间中的距离会更小。
还有更多!CIE Lab* 不依赖于任何设备,因为它是从XYZ推导出来的。然而,这种推导考虑了光照条件以适应另一种人类感知特征:色适应。要计算Lab值,我们需要提供"正常日光条件"的XYZ坐标,这通常被称为白点(或"D65")。最终公式可以在维基百科上找到。
更直观的 Lab 转换
如果您此时感到不知所措或困惑,让我们尝试用其他例子来理解。
看以下两种Lab颜色,尝试猜测它们是如何相关的:
|
|
如果您不确定,请看一个称为LCH(亮度、色度、色调)的 Lab* 空间变换。亮度保持不变,C 是 a² + b² 的平方根,H 是以度为单位的角度。这种表示对大多数人来说更直观。让我们将之前的颜色转换为LCH,看看我们得到了什么:
|
|
所以现在我们有了相同的亮度,相同的强度,但不同的色调!
现代 Lab*
CIE Lab* 空间早在1976年就开发了,它不是现在存在的唯一Lab。CSS Color Module Level 4 指定了两个lab。第一个是 CIE Lab*,另一个是 Oklab。
注意: CSS Color Module Level 4 还为前面讨论的色彩空间定义了额外的CSS映射。
Oklab 在2020年晚得多开发,旨在修复 CIE Lab* 的几个问题。
- Oklab 更均匀,特别是对于蓝色色调。
- Oklab 对机器更好,因为有更稳定的数值计算。
- Oklab 从sRGB推导,因此对开发人员更熟悉和直观。
Oklab 有自己的LCH表示,称为 Oklch。它的计算方式与LCH组件类似,旨在更加均匀和直观。
最常见的空间 sRGB 及其朋友 YUV
Lab* 和 XYZ 是丰富的色彩空间,可以代表人眼可以感知的每一种颜色。然而,由于它们的值范围很广,它们对于存储像素值不是很有效。而且,它们是现代的,设计用于与能够负担得起浪费一些比特来表示颜色和亮度的微小细节的设备一起工作。
图像和视频格式通常使用 sRGB 色彩空间,GPU硬件针对 sRGB 进行了优化(我们将在后面讨论)。RGB 的灵感来自人眼的工作方式(红色、绿色和蓝色);然而,它对于图像处理不是很方便。这就是为什么使用另一个色彩空间 - YUV。YUV 是一组三个值 Y(亮度)、U(蓝差)和 V(红差)。这个空间的主要好处是将颜色(U 和 V)与亮度(Y)分开。
注意: 关于亮度、红-绿和蓝-黄系统的命名存在一些混淆。您可以找到对 YUV、YCbCr 和 Y’CbCr 的引用。看起来 YUV 和 YCbCr 可以互换使用。然而,Y 和 Y’ 是不同的东西。请注意,与 Lab* 相比,YUV 不是感知均匀的。
如果您查看图像编解码器源代码,很可能会找到许多与转换到和从 YUV 相关的行。不要忘记 sRGB 是设备相关的。如果我们取一个填充了某种颜色的矩形,比如(0, 255, 0)(绿色),它在不同设备上看起来会不同。
让我们看看 YUV 坐标是如何从 RGB 推导出来的。我们之前看到了这个原理,首先我们分离亮度:
|
|
再次,我们看到绿光贡献最大。U 和 V 是蓝色和红色与 Y 的差值。 注意分母中的系数是为了将 U 和 V 缩放到 -0.5 到 0.5:
|
|
让我们尝试在松鼠上,并比较原始图像与分离的 Y、U 和 V 通道:
这种分离非常重要,因为人们对亮度比颜色更敏感。为了正确处理图像,通常仅对 Y 通道进行一些变换,或对 Y 和 UV 通道使用不同的变换是有意义的。这些通道通常被不同地压缩。
人类和设备感知事物的方式不同
让我们讨论我们感知的另一个特征——我们如何感知亮度,这与设备再现亮度的方式非常不同。我们以对数方式感知亮度,而设备以线性方式再现亮度。对数感知意味着我们可以区分广泛的亮度范围。例如,对数5尺度(1:100000)是可以的;如果我们的眼睛适应环境条件,它甚至可以更大。
如果您好奇想深入了解,这种效应由韦伯-费希纳定律描述。
这是一个问题,因为普通设备可以捕获和显示的亮度范围远小于我们可以感知的范围。
许多专业相机和显示器支持更宽的亮度范围,因此差异很大。
让我们考虑一个例子: 哪个渐变看起来更均匀?
对大多数人来说,第一个渐变看起来更平滑,而真正的"线性"渐变是第二个。
如果您更仔细地查看示例,可能会注意到一些小谎言。第一个渐变在中间有128(255 / 2)。它是完全线性的,对吗?实际上不是,因为我们在CSS中使用的RGB值是经过伽马校正的。伽马校正用于提供更好的感知图片并更有效地存储比特。
为了从线性值获得伽马校正值,我们将值缩放到 [0, 1],然后使用幂函数(如韦伯-费希纳定律所建议的)。我们使用2.2作为幂,因为它接近人类感知的工作方式。
sRGB中使用的真实公式稍微复杂一些,但非常接近上述。这是实际变换:每个通道 R、G、B 以相同的方式变换。
|
|
这也给暗阴影"更多比特"。“真实"平均值大约在180左右,而不是128。这与人类感知的工作方式一致——我们对暗阴影更敏感。
Y’ 是 Y 的伽马校正版本。它的计算方式与 Y 相同,但使用伽马校正的 R、G、B。用于伽马校正的特定公式取决于色彩空间。这称为传递函数。
从相机到屏幕
很多时候,我们想用手机拍照,并在我们最喜欢的社交网络上分享这张照片。当您的朋友在她的笔记本电脑上看这张照片时,如果颜色看起来相同,那就很好,对吗?
为了实现这一点,手机相机捕获的颜色应该正确映射到屏幕上的颜色。请记住,高效的色彩空间是设备相关的。这意味着,例如,(127, 0, 0)RGB值在不同设备上具有不同的颜色。为了对齐颜色,附加的信息通道被编码到图像中。设备色彩空间有三个特定内容:
- 三个颜色原色
- 一个白点
- 一个传递函数
让我们看看它如何用于AVIF图像。
像许多图像格式一样,AVIF尽力准确再现颜色。它使用两件事来做到这一点:颜色配置文件和 CICP(编码无关代码点)。颜色配置文件用于在创建图像的设备上生成的大多数图像格式,并允许正确重建颜色。它提供精确的颜色控制,并包含颜色原色、传递函数和白点的系数。它还可能存储带有预计算变换的查找表。
CICP 通常用于视频,它比 ICC 配置文件简单得多。
注意: 您可以在 GitHub 上的 libavif wiki 上找到很好的解释。
它由三个值组成。每个值引用公开可用的 H.273 标准中表中的行。
- MC:一组将 RGB 转换为您想要的任何色彩空间的系数。通常用于将 RGB 转换为 YUV。
- TC:考虑设备特定特性并执行伽马校正的非线性传递函数。
- CP:将 RGB 转换为 XYZ 的颜色原色。
例如,它可能是 1/13/6,这意味着从标准中特定表中取第1、13和6行。如果图像包含颜色配置文件,则 CP 和 TC 值取自配置文件,但 MC 仍取自 CICP。
让我们看看 AVIF 图像的过程如何工作。我们正在读取 CICP 并得到 2/2/6,这意味着:
- CP - 未指定
- TC - 未指定
- MC #6 定义了标准的 RGB 到 YUV 转换,与 JPEG 使用的相同。
为了获得更多信息,我们需要查看 ICC 配置文件。在这里我们找到颜色原色、传递函数和白点。
此信息用于将解码的字节流转换为设备色彩空间。在此过程中,图像可能会转换为 XYZ 和中间色彩空间,然后转换为设备色彩空间。
解码过程超出了本文的范围,但要提到的一点是使用了 MC 系数。结果被发送到 GPU 并显示在屏幕上。
如果我想要令人惊叹的照片怎么办?
当我看日落时,我既可以看到天空也可以看到建筑物的细节。然而,如果我以 JPEG 格式拍摄单张照片,我必须在捕捉天空或建筑物之间做出选择。在这种情况下,明亮的天空曝光良好,但建筑物合并成单一的暗模糊。
我们怎样才能做得更好?我们可以感知的颜色和亮度级别范围比低端设备可以捕获和再现的范围要宽得多。这种宽范围通常称为高动态范围(HDR)。
为了从图像中获得最佳效果,我们需要四件事:
- 能够捕获宽范围颜色和亮度级别的设备(例如专业相机或某些智能手机相机)
- 能够有效存储此范围的文件格式
- 能够正确解码图像的软件
- 能够准确再现此范围的显示器
如果所有这些条件都满足,我们会得到具有更详细阴影和高光以及鲜艳色彩的图像。然而,如果这些条件中的任何一个不满足,我们最终会得到 SDR(标准动态范围)图像。
专业相机擅长捕捉 HDR 照片。它们使用无损 RAW 格式,该格式明显大于标准图像文件。通过适当的后处理,可以通过对图像的不同部分应用不同的变换来显示细节。
至于软件 - 现代浏览器在某些操作系统上支持 HDR。
许多屏幕可以再现 HDR 图像,但如果设备无法显示 HDR,则必须将图像转换为 SDR。为了保留细节,可以使用不同的色调映射技术。这些技术可以由浏览器自动应用或由用户手动应用。没有色调映射,图像可能看起来太暗、太亮或单调。
让我们检查它在您的情况下的工作方式。比较两个图像:
如果第二张图像看起来更鲜艳,您的设备和浏览器可以渲染 HDR 图像。
色调映射的问题在于它统一应用于整个图像。更好的方法是使用增益图调整特定区域——甚至每个像素——的亮度。您可以将增益图视为图像的灰度版本,其中每个像素的实际亮度乘以增益图中的相应值。此增益图嵌入在图像文件中。虽然 JPEG 和 AVIF 支持增益图,但该功能仍未标准化且处于实验阶段。
即使显示器可以再现 HDR,存储和传输 RAW 文件也是昂贵且低效的。最直接的解决方案是使用具有更高位深度的现代图像格式——例如 AVIF。AVIF 可以存储每通道 10 或 12 位,允许更宽的颜色和亮度级别范围。
总结
在本文中,我们学习了人类感知如何影响设备中光信号的表示方式。
让我们总结一下我们涵盖的内容: 色彩空间用于表示光信号。有些色彩空间是设备特定的,而其他则是通用的且独立于设备。某些色彩空间,如 sRGB,针对在图像和视频中表示光信号进行了优化。其他,如 LCH(亮度、色度、色调),旨在以符合人类感知的方式表示颜色关系。
为了在设备之间保持一致的色彩,我们必须从设备特定的色彩空间转换为通用色彩空间(例如,sRGB 或 XYZ),然后再转换回来。此外,应用特殊变换,如伽马校正,以解释人类感知光和颜色的非线性方式。一些色彩空间允许将颜色与亮度分开,这对于图像压缩非常有益,我们将在下一篇文章中看到。