欢迎光临散文网 会员登陆 & 注册

色彩空间、HDR和ACES

2023-03-06 21:35 作者:朵格子Dolag  | 我要投稿

原文是我用Markdown来写的,复制到B站然后改了一下,但还是丢掉了例如引用链接之类的东西,md原文和pdf在此https://driver.dolag.work/Share/Misc

色彩模型(Color Model)

色彩模型规定了颜色能够被哪些分量(也就是原色)进行表示。举例来说RGB色彩模型下的颜色就可以用RGB三原色的数值来进行表示,比如存在一个颜色可以表示为[Red = 0.2, Green = 0.75, Blue = 0.13]。

常见的色彩模型有RGB、CMYK、HSV、HSL等。

色彩空间(Color Space)

色彩空间如其名,是颜色的空间。由于我们是进行设计、创作、游戏等,最终都会使用显示器、屏幕等进行显示,而这些设备一般都是使用RGB色彩模型,因此此文章只讨论RGB色彩模型相关的问题。

CIE XYZ色彩空间

CIE XYZ色彩空间之前有一个CIE RGB色彩空间,CIE XYZ色彩空间中的XYZ是对之前CIE RGB色彩空间的一个修改,因为之前CIE RGB色彩空间不能表达出人眼可见的所有颜色(因为此时的三原色刺激值中的红色部分有负值)。XYZ近似对应红绿蓝。[1]

下图为CIE xy 色度图(Chromaticity Diagram),之所以只用xy是因为,任何可见光颜色都可以通过XYZ三个分量进行一定比例混合,且x + y + z = 1,因此z = 1 - x - y。下图三角形区域表示原来的CIE RGB颜色空间。



CIE XYZ颜色空间可以表达所有的可见颜色(上图的奇怪蹄状三角区域就是人眼可见光区域,但是XYZ能够表达式的范围显然不至于此),是绝对颜色空间,因此常常用这个CIE xy色度图来度量其他颜色空间的色域(Gamut),这种表示方法也叫三色刺激值(Tristimulus Value)表示,也称为色度(Chromaticity)表示。

然后这个CIE XYZ颜色空间和CIE xy色度图很哈人的一点就是,色度图上两点之间的中间位置,完全符合人眼感知的,两颜色的中间值。毕竟是根据人眼感知特性来创造的颜色空间。

RGB色彩空间

RGB色彩模型下有很多色彩空间,常见的有sRGB、Adobe RGB、ProPhoto RGB、DCI-P3、Rec.2020、Rec.709、ACES2065-1、ACEScc/ACEScct、ACEScg。

白点(White Point)和原色(Primaries)

白点是一个色彩空间里设定为白色的点,用开尔文或者色度来表示。原色就是一个色彩空间的基本颜色,其他颜色都可以通过这些基本颜色进行表示,也用色度表示。每个色彩空间有不同的原色、白点。[2]

以DCI-P3 D65色彩空间为例(D65表示其白点为6500开尔文色温的颜色),其白点为(0.3127, 0.3290),原色为R = (0.68, 0.32),G = (0.265, 0.650),B = (0.15, 0.06)。

另外,RGB色彩模式下的色彩空间,在CIE xy色度图上的表示显然都是三角形区域,每一个顶点表示了一个原色,因此其能够表达的颜色区域自然只能是三原色围起来的三角形区域。

伽马(Gamma)空间和伽马校正

以sRGB为例,由于sRGB色彩空间提出的时代,流行的CRT显示器显示图片时,实际发出的亮度和电信号(也就是颜色数据)表示的亮度不是线性的,而是有一个2.2次幂的非线性关系,因此需要提前对图像数据进行一个1 / 2.2 = 0.4545的一个幂次变换,此过程称为伽马校正,校正过后的图像数据处在伽马空间中。但是其实sRGB并不只是一个单纯的伽马校正,是个接近1 / 2.2的分段函数。

现代的显示器其电压亮度响应函数其实是可调的,但是现代显示器一般都支持这个2.2次幂的传统,因此现在sRGB还是非常的常用。

然后Rec.709色彩空间也是一个伽马空间,通常认为它的伽马值为2.4,但实际上也是个分段函数。Rec.709和sRGB其实色域差不多。

显而易见的,对一个颜色空间应用伽马校正,会变成另一个颜色空间,但是这两个颜色空间的色域是不变的,因为应用幂次变换后显然原色和白点都不会变。

经典色彩空间

sRGB

sRGB(Standard RGB)是目前最常用的色彩空间,它是一个带有伽马的色彩空间。sRGB在色度图上的面积现在来看其实是比较小的。

sRGB最初设计的目的是作为生成在因特网以及万维网上浏览的图像的通用色彩空间,最后选择的是使用Gamma校准系数为2.2的色彩空间,即CRT显示器在这种情况下的平均线性电压响应。[3]

我们现在,一般的贴图、图片、照片等一般都是处在sRGB空间下。

DCI-P3

DCI-P3蛮怪的,它的色温是6300开尔文,但不是在CIE Standard Illuminant下的,所以不能称为63D,而且白点稍微有点发绿,好怪。然后它是一个系数为2.6的伽马空间,这是为了能适当兼容sRGB。但是DCI-P3色域比sRGB大了有30%,因此许多HDR设备都用这个色彩空间,比如你的手机。

Display-P3

Display-P3是苹果创造的色彩空间,要正常一点。它使用65D的白点,系数为2.2的伽马空间,非常兼容sRGB,感觉还不错。

Rec.2020及P3-D65

Rec.2020又比上面两个P3的色域大上一圈,色域相当不错,但是显然造价更高,在激光影院可能会使用。

实际上几个HDR格式HDR10、HDR10+、Dolby Vision、HLG的技术极限都是Rec.2020,普遍的色彩空间都是P3-D65(一个和DCI-P3与Display-P3都不同的P3色域)。

Adobe RGB和DCI-P3的色域面积是差不多的,然而是两个差别不小的色彩空间,所以说在选购显示器的时候不要只关注色域的面积,主要看它的色度图以及和你想要的色彩空间的覆盖率。

HDR(High Dynamic Range)

sRGB和Rec. 709色域蛮窄,覆盖了色度图35.9%左右区域[4],使用它作为色彩空间的OO称为SDR(Standard Dynamic Range)。相对的HDR的色域就蛮高。下面是一些HDR格式的参数[5]

HDR10、HDR10+、Dolby Vision都是使用PQ传输函数(Transfer Function)。

这些HDR格式,由于色域比sRGB提高了不少,因此也需要用更多的比特来精确地表示颜色(说实话,Rec.2020的色域覆盖了75.8%[5]的CIE 1931色彩空间,感觉用16bit的bpc才勉强能行),因此HDR都是10比特起步的。

传输函数(Transfer Function)

也有人翻译为转换函数,实际上就是起到一个转换的作用。

传输函数分为OETF(opto-electronic transfer function,光电传输函数)、EOTF(electro-optical transfer function,电光传输函数)、OOTF(opto-optical transfer function,光光传输函数)

OOTF说是OETF除以EOTF的结果,可能是用来衡量看到的和拍摄的之间失真度的东西。

OETF是从摄像机等输入设备到图像数据的转换函数,在摄像机内完成,我不太想研究这部分。

EOTF是从图像数据到光信号的转换函数,这是在显示器内完成的,例如前面说到的sRGB和Rec.709,就需要先进行一次伽马校正,这样在经过EOTF之后才是显示的正常的光。大家都喜欢的HDR10、HDR10+、Dolby Vision在设备上会进行PQ转换,所以应该要在此之前进行反PQ编码,HLG同理,不过是HLG转换和反HLG编码。 SDR的色彩范围始终是0到1的,这样在不同亮度峰值的显示器上的亮度是不同的[7]。而HDR的这些EOTF,以PQ为例,实现了0到10000尼特的转换,因此在不同显示器上的亮度也应该是一样的如果显示器支持的话。

HDR和SDR之间的转换及显示过程中的颜色变换

微软有在文档里写普通的颜色变换管线和Windows实现任意两个色彩空间转换的过程[6]

颜色变换管线

首先0是原本的色彩空间,首先如果这个色彩空间不是线性空间,则需要先进行反伽马变换1,变换完后就到了线性空间,线性空间的颜色就可以通过颜色矩阵2这种线性变换来变换到其他颜色空间,如果目标颜色空间也是一个伽马空间,则要施加一个对应的伽马校正3,然后就得到了转换后的颜色空间。


Windows的颜色变换管线

Windows使用单独的管线。其实这个例子都不太像是颜色变换管线而是图像显示管线了


介绍一下各个步骤:

  1. 其实还有第0步,那就是Framebuffer里面渲染得到的颜色数据,它们都是RGB伽马空间的,可以是sRGB, sYCC, HDR10, 或者scRGB颜色空间。

  2. 反伽马,转换到线性空间。

  3. 2a、2b、2c是颜色空间转换的三个变换,它们乘在一起就是颜色空间的转换矩阵。

    2a:从线性空间转换到CIE XYZ的绝对颜色空间。 2b:做一些例如校准的调整,可编程。 2c:从CIE XYZ转换到目标的线性的RGB色彩空间上。 2a和Framebuffer相关,2c和显示器相关,普通应用可以控制2b这个矩阵。 然后上面的1、2都是在显示器驱动控制下完成的。

  4. 也分两步。 3a:使用EOTF来伽马校正,由显示器驱动完成。 3b:做一些例如校准的调整,又是可编程的那种。 3a的转换由wire format color space(实在搜不到)来指定,但应该就是显示器的颜色空间,例如SDR显示器就需要做一次伽马校正,HDR10显示器就需要做一次逆PQ(或称ST.2084)电光传输函数的变换。

完成上述步骤后,Framebuffer(没错,还是在Framebuffer里)里的数据就会扫描到你GPU连接显示器的那条线里,然后显示。

Windows的色彩显示流程

上面其实还不是完整的显示过程,第0步显然也是需要输入的,这部分说明了上文第0步是怎么来的[8]

HDR

先说说Windows的HDR显示,首先HDR是在Windows10 1703才支持的,其步骤如下:


  • APP就是每个窗体应用的Framebuffer,可以是任何色彩空间,最高支持32位浮点精度。

  • DWM(Desktop Window Manager)是用来混合窗体的,简单来说就是把各个应用的窗体给合成成一个Framebuffer,这一步会将各种窗体不管什么颜色空间都给转换到scRGB颜色空间下——scRGB是一个色域宽到离谱的线性颜色空间,其色域感觉是就是把sRGB放大了一倍,所以精度也使用了16位浮点。 16位浮点精度的scRGB也称为CCCS(canonical composition color space),是为了把各种窗体各种不同的色彩空间都统一转换到CCCS方便管理。


  • Display Kernel是将CCCS转换到 wire format color space的(例如BT.2100 ST.2084),然后可选的,Windows会使用前文所述的Windows的颜色变换管线进行处理。

  • System Color Management还没研究。

SDR

SDR显示就是一坨,不管应用渲染得多精细,SDR显示都会Clip到8bpc。

Apps using graphics APIs such as DirectX could perform internal rendering using high bit-depths and extended color spaces; however, the OS supported only 8-bit integer with implicit sRGB and no system color management

然而......

SDR since Windows 11 22H2

喜大普奔,Windows 11 22H2及之后,SDR的显示流程也和HDR的类似了,至少来说支持超过8bpc的应用的数据了,超过8bpc的颜转换到CCCS之后会得到正确的结果,这样在10bpc的SDR显示器上能够显示更加丰富的颜色了。


泪目。

把游戏引擎渲染纳入考虑......

如果把游戏引擎的渲染流程纳入考虑,那么Windows的,线性工作流下的游戏引擎渲染流程就是:


色调映射发生在渲染这个过程。

关于帧缓冲(Framebuffer)

帧缓冲就是用来存需要显示在显示器上数据的显存。在Vulkan API下[9]

对于SDR屏幕,Buffer主要有:

R8G8B8A8_UNORM:首先屏幕的EOTF曲线是始终存在的,这种格式输入的颜色,图像接口不会进行任何处理,需要我们自己在shader中进行sRGB编码。

R8G8B8A8_SNORM:这种格式输入的颜色在显示之前会自动编码到SRGB空间(自动Gamma矫正),所以我们不需要进行处理,也就是说shader当中直接写出线性颜色即可。A通道是线性的。

对于HDR屏幕,Buffer主要有:

R16G16B16_Float:这种格式输出的是线性浮点数颜色,数据可以超过1,1对应的是80nits。使用的是scRGB。

DX的参考:

https://docs.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range

R10G10B10A2_UNORM:这种格式不会进行任何处理,直接结合EOFT曲线进行显示, 所以需要我们自己在Shader中进行PQ编码。(在我的显示器上Vulkan不支持,暂时没有测试过,但是GL和DX是支持这个格式的)

VK_COLOR_SPACE_HDR10_ST2084_EXT:说明colorSpace,表示使用BT2020颜色空间,使用ST2048的EOTF。

这些图形API输出的帧缓冲应该都是上文Windows的色彩显示流程中APP的输入,由于Windows的色彩显示流程阶段会将图形API输出的帧缓冲根据其色彩空间转换到scRGB或说CCCS,因此我们只需要保证在渲染时,渲染出的图像数据和色彩空间匹配即可,按Vulkan来说就是要让Color Attachment是正确的。

此外,感觉和我一样搞游戏技术的,都会觉得图像API输出的帧缓冲就是天,实际上其他所有窗口都会输出帧缓冲数据,然后交由DWM来合成,合成后的内容也是储存在帧缓冲里,甚至由显示器驱动进行的处理也是存在帧缓冲的——帧缓冲不是什么特别的东西。

色调映射(Tone Mapping)

上文其实已经解释过了如何从HDR的颜色空间(如P3-D65)转换到SDR的颜色空间(如sRGB),但是简单地从色域较大的空间转换到色域较小的空间,一定会产生SDR中无法表现的颜色,如果直接将超出范围的颜色进行截断,就会出现如大片相同颜色,因此需要在转换之前先进行色调映射。此外HDR图像是浮点表示的,可能会产生值超过1的部分,但SDR是归一化的色彩空间,所以数据上来说,其归一化后的数值只能从0到1,要将HDR图像转换到SDR,就需要色调映射。(个人理解,不知道对不对)

色调映射的算法蛮多,比较常用的有CE Tone Mapping、Filmic Tone Mapping,但现在基本都被ACES色调映射统一了[10]。这篇文章说ACES色调映射是ACES提出的,但是我找不到任何证据(比如ACES官网上查不到任何色调映射相关的文字)说明这是ACES提出,而应该是Epic Games的图程Krzysztof Narkowicz基于ACES的ODT提出的,他在他的博客中有提到[11],在研究出来之后称为了UE的默认色调映射函数,UE的文档[12]可以看到。


ACES色调映射不仅比较符合感知,细节损失较少,而且代码很简单,开销蛮小,很适合用在游戏里,比如UE4.8及之后就全面支持了ACES色调映射。下面是Krzysztof Narkowicz写的最初版的HLSL代码。

float3 ACESToneMapping(float3 color, float adapted_lum)
{
const float A = 2.51f;
const float B = 0.03f;
const float C = 2.43f;
const float D = 0.59f;
const float E = 0.14f;

color *= adapted_lum;
return (color * (A * color + B)) / (color * (C * color + D) + E);
}

B站不让插入代码块我超。

据称,ACES色调映射不仅可以用于HDR到SDR的转换,在你的HDR显示器峰值亮度不够时,还可以进行HDR到HDR的转换。

建议称其为ACES色调映射或者ACES Filmic Tone Mapping,而不是简单的ACES,不然很容易和真正的ACES(学院颜色编码系统)弄混。

ACES(Academy Color Encoding System)流程

中文是学院颜色编码系统,大家都简称为ACES。它的优势在于,给影片制作的全部流程,都提供了一个统一的色彩管理,且由于其较大的色域,并参与了影片从拍摄到放映的全过程,相比传统流程来说质量更好[13]


ACES其实是包含了很多部分的[14]

  • ACES Input Transform(IDT或输入设备转换):它将摄影机独有的拍摄参考数据转换为线性场景的ACES色彩空间。目前,摄影机厂商会为自己的摄影机系统来开发IDT转换算法,然后ACES学院对其进行测试和验证,未来ACES学院会拥有更多的控制权。IDT转换和其它ACES转换一样也是用CTL(色彩转换语言)编程语言来编写的。IDT并不是完全与摄影机系统一对一的关系,有时也会将不同的IDT应用于同一个摄影机系统来补偿一些摄影机系统中因不同设置所带来的差别。

  • ACES Look Transform(LMT或外观修改转换):它是ACES观看转换(它由LMT、RRT和ODT系统组成)的一部分,它提供一种类似于将LUT应用于镜头的方法。不同的是,LMT位于ACES色彩的调色流程之后,且并非所有工作都支持它。

  • Reference Rendering Transform(RRT或参考渲染转换):你可以将其理解为ACES的渲染引擎组件,RRT将场景参考的线性数据转换为超宽的显示参考数据集。RRT与ODT一起为显示创建可视化的数据。

  • ACES Output Transform(ODT或输出设备转换):这是ACES流程的最后一步,它从RRT获得超宽和高动态范围的数据后,转换为不同显示设备所对应的色彩空间,比如P3、Rec.709、Rec.2020等。

ACES的野心不小,它囊括了拍摄、调色、特效、显示、归档各个阶段,流程可以归纳为如下图[15]



其中摄像机部分的流程应当如下图,不管是真实的摄像机还是各种渲染器/渲染引擎的摄像机,都会经过IDT变换变换到ACES2065-1色彩空间:


ACES Central举的一个ACES流程的例子[16]为下图:


可以看到,在摄像期间,摄像机捕获到的自然界的光线会经过OETF先转换成电信号(现在是在摄像机自己的log颜色空间下),然后再经过IDT(Input Device Transform)后转换到ACES2065-1色彩空间

其实IDT是ACES第一版的称呼,现在改名为Input Transform了[17],但好像还是简称IDT。

ACES的色彩空间

ACES中规定和使用了几个色彩空间:

  1. AP0(ACES Color Primaries 0)规定了一组原色,这组原色的色域包含了整个CIE色度图,好牛。然后AP1(ACES Color Primaries 1)也规定了一组原色,这组原色的色域就要小不少。 AP0和AP1的色域[16]如下:


  1. ACES2065-1使用AP0的原色,是一个线性空间,主要是为了存储、归档素材[18]而设计的,

  2. 也是在ACES中用于进行色彩交换的中间空间,例如说在进行ACEScc转换到P3-D65的过程中,就要先转换到ACES2065-1再转到P3-D65,就类似Windows上使用的scRGB。

  3. ACEScc使用AP1原色,是一个log空间,这个空间可以用于分级调色(Color Grading)中,说是因为有些调色师喜欢在log空间下调色。

  4. ACEScct和ACEScc差不多,只是在趾(Toe)部会有一些抬升。

    A variant of ACEScc color space, except that it adds a “toe” to make it more akin to traditional “log” curves to generate a distinct “milking” or “fogging” of shadows under lift operations, which is typical of some film looks. This comes from requests to provide colorists with a grading environment more similar to that of traditional legacy log film scan encodings when grading using a working space from the “ACES” family of color spaces.

  5. ACEScg也是使用AP1原色,是一个线性空间,一般在这个空间里进行合成、特效、绘画和其他CG相关的工作。

可能读者会有些疑惑,这个ACEScg是一个线性空间,那岂不是说我们在进行合成时看到的色彩竟然是处在线性空间的,置显示器EOTF于何处!

其实ACES这些色彩空间,都是需要先转换到sRGB、VP-D65等显示器的色彩空间之后再显示的——目前还没有ACES的显示器——上面流程图中的RRT&ODT就是进行了这些处理,以我们用sRGB屏幕来显示ACEScg的内容来说,会有一个ACEScg->ACES2065->sRGB的过程,第一步称为RRT(Reference Rendering Transform),第二步称为ODT(Out Device Transform),这两个过程合称为Output Transform(wikipedia说的,感觉有点怪)。

LMT(Look Modification Transform)是用在ACES色彩空间之间进行转换的步骤,例如在分级调色之前就需要将ACES的某种色彩空间转换到ACEScc或者ACEScct色彩空间中去。

wikipedia上说LMT + RRT + ODT才组成Academy Viewing Transform,但我还不太懂LMT在这里的作用是什么。

注意,读者如果要去阅读ACES的文档,需要理解文档中提到的scene-referred或者说scene-linear是指ACES2065-1,猜测因为它的色彩空间足够大所以称之为“referred”。

ACES工作流

伽马、色彩空间、位深度在ACES的每个过程中如下图[17]所示:


  1. 摄像机。在摄像机拍摄的流程中,摄像机拍摄后的图像应该是在摄像机自身的log空间下的,然后现在摄像机厂商一般会提供IDT转换的方法,将图像转换为ACES2065-1色彩空间的,16位浮点精度的图像。例如索尼的Raw Viewer[19]就能根据不同的相机型号转换到ACES2065-1色彩空间。

  2. 视觉特效。视觉特效不需要输入,直接就在ACEScg色彩空间下工作。各种VFX软件应当要或将要支持ACEScg色彩空间,因为在VFX Reference Platform[19]这里规定了OpenColorIO和ACES的支持以及版本。OpenColorIO(简称OPIO)就是那个帮助我们在各种颜色空间,甚至于不同型号的相机的颜色空间进行转换的工具。 对于VFX工作者需要注意的是:

    • 反照率/基本色、发光之类的表示颜色的贴图需要转换到ACEScg空间再赋予到材质上。一般的贴图都是在sRGB色彩空间下的,因此需要先进行一个sRGB到ACEScg的变换。可以使用OPIO从 "Utility - sRGB - Texture"转换到“ACES - ACEScg”,我想一般在渲染引擎/渲染器里都会有集成。

    • 其他的法线、置换、金属度/高光度、粗糙度/光滑度等贴图,还是需要处在线性空间。

    • 渲染的影片仍然在ACEScg色彩空间中。

  3. 剪辑、合成等都是在ACEScg下进行的。

  4. 调色是在ACEScc下进行的,需要先从ACEScg或者ACES2065-1经过LMT转换。

  5. Output Transform,也就是RRT和ODT会将最后的成片进行输出,输出到显示器或者银幕。我没有查到是在什么阶段进行的交付,我猜测是看你流程最后一步是在ACEScc/ACEScct还是ACEScg,然后就在这个颜色空间交付,因为显然经过RRT转换会有精度损失(虽然迟早都会发生),还有一个猜测是在RRT之后转换到ACES2065-1交付,这样比较统一。我倾向于认为是后者。

本来想再写一点线性工作流和伽马工作流的,不过这个前人应该都叙述比较详细了,就偷懒了,可以参考这篇文章[20]

色彩空间、HDR和ACES的评论 (共 条)

分享到微博请遵守国家法律