什么是“图像”
图像本质上是一个“矩阵”或者“数组”,比如说最常见的图像可能是形状(Height,Width,Channel)的数组,每个位置上的数是八位量化的,用整型或浮点表示的 256 个不同的等级。这里面存的东西一般叫做码值或像素值(Code Value)
编码
这个数组如果直接保存可能会很大,于是需要一些压缩的手段,即“编码”。编码的方式在不断更新,比如使用色度降采样、离散余弦变换(DCT)、霍夫曼编码等进行压缩的 JPG(JPEG)编码;又比如扩展性很强的 TIFF(*.tif)文件,它本身是一个容器格式,可以在内部调用 ZIP、LZW、PackBits 甚至 JPEG 等多种无损/有损编码;再比如比较先进的 HEIC(HEIF/HEVC)和 AV1 编码,它们具有灵活的分区结构、多模式帧内预测以及更高级的熵编码,能够实现非常高的编码效率。
编码这个过程可能会带来一定的损失,即有损压缩。平时最常用的 JPG 标准就包含无损和有损两种工作模式,只不过无损模式几乎没有人在用。后来出现的许多编码方式同样支持无损压缩——AV1 甚至提供真正的无损档位——只要不是刻意追求极限压缩率,有损压缩带来的质量损失其实很难被察觉。
不同编码方式的另一个区别是它们允许的量化位深。JPG 标准支持 8 位和 12 位量化,但 12 位模式同样很少见;更新的格式往往支持更高位深,例如 HEIC 和 AVIF 可以做到 10 位乃至 12 位,TIFF 容器内则可以存放每通道 16 位甚至 32 位(浮点)数据。这一点与 HDR 的需求密切相关:要在更宽的亮度范围内避免出现可见的色阶断层,就需要更高的量化精度。
附加信息
只有一堆数字是没有意义的,还需要知道他们定义在什么空间上,至少要标注出三基色、白点和传递函数(也就是 RGB 空间的定义)。
附加信息就需要告诉解码器和系统里的色彩管理,这些数字的具体含义,如果没有的话,一般会当成 sRGB 处理,颜色空间与实际不匹配的话就会出大问题。
解码软件解出像素值和附加信息之后,颜色管理系统会把这些已知色彩空间的像素值转换成显示器的驱动值然后正确显示,所以理论上,码值甚至可以是三刺激值和线性的,只要有对应的附加信息来标注它。下面的图是两个标识了 XYZ 空间和线性传递函数的 PMCC 色卡,图片中的像素值直接是三刺激值。
这是一个 D65 光源下的色卡三刺激值图像,其中超出 1 的部分进行裁切,实际上这是一种错误的处理,nclx 中的 CIEXYZ 需要以等能白为白点,可以选用 ICC 中的 Bradford CAT 来转换。
这是适应到等能白的图片(用的是直接替换白点),由于适应到等能白,所以不会出现超过 1 的值,显示的时候,由系统的颜色管理将其色适应到显示白点上,因此看起来的效果应当与浅色模式下的背景接近,浅色模式的页面背景码值是 245。
如果你在使用 iOS 或 iPadOS,可能看不到这两个图像,别的系统经测试基本都可以。
附加信息的具体形式有很多种,比如嵌入 ICC 配置文件,或者是保存在图像文件里的 xml 语句或是 nclx,还可以存在 EXIF 里。
这一步是实现 HDR 效果最关键的部分,标注了正确的传递函数之后,解码器就能把码值转换成能够超过 SDR 名义亮度的所谓“HDR”内容。
有一种比较特殊的 HDR 实现方法:Gain Map,一个文件中保存了两幅图像(一个 SDR 图和一个增益图)和一些对应的附加信息(具体的增益系数等),解码器能够将两幅图像运算出一个新的 HDR 图像。所以增益图也许也可以算一种附加信息。
显示参考的线性光
进行图像格式转换的时候,所有线性光空间指代的都应该是显示参考 Display referred 的。即计算出图像被显示之后在显示器上的光亮度(亮度或绝对三刺激值)。
解码的时候使用 EOTF,编码的时候使用逆向的 EOTF 而不是 OETF(PQ 一类的传递函数会有区别)。
PQ 或 HLG 传递函数
与 HDR 视频类似,将传递函数从 Gamma 或 709 换成 PQ 或 HLG,就能实现 SDR 向 HDR 的转变,对静态图像来说,已有国际标准 ISO-22028-5。
佳能最早在微单引入了 10bit 的 HEIC 编码,使用 PQ 作为传递函数,索尼有 HLG 静态图像,在新版本的 ACR 中,启用 HDR 输出但不启用最大兼容得到的 AVIF 和 16 位 TIF 就是 PQ 编码的。
对这种 HDR 图片,只需要应用正确的传递函数转换到线性光或从线性光编码即可。
Gainmap
Gainmap 是专用于静态图像的一种实现 HDR 的方法,优点是非常好的兼容性,它可以同时保存 SDR 和 HDR 的内容(而不是依赖动态元数据及 TMO),并且对显示驱动非常友好。
JPG,JXL,AVIF 都可以保存这种格式,尤其是 JPG,带有 Gainmap 的 JPG 实际上就是两个 JPG 文件首尾拼接起来,不支持这种格式的图片查看器直接读取第一张就是普通的 SDR 图片,在社交媒体选择发送原图后,还能保留后一张 Gainmap,即使 app 本身不支持,保存到别的 app 也有可能看到 HDR 效果。
Gainmap 最早大规模应用应该是 OPPO 的 Find X6 Pro,后来 Google 推广了 UltraHDR 格式,ISO 正在制定 ISO-21496-1 标准,UltraHDR 1.1 版本已经兼容了这一标准。
Gainmap 可以只写入亮度,也可以是三通道的,最近发布的 OPPO Find X8 Ultra 中的原彩 ProXDR 就是指代三通道 Gainmap。
Gainmap 可以理解为一种补充增强信息(SEI)或颜色重映射信息(CRI),记录了 SDR 和 HDR 源的区别,另外通过类似静态元数据的东西保存了 Gainmap 的绝对亮度关系。
元数据包括:内容最大亮度增益(HDR 相比 SDR 亮多少),显示最大亮度增益(母版 HDR 相比 SDR 亮多少),编码 gainmap 时用到的 Gamma 和可选的偏移量。
关于最大亮度增益和显示最大亮度增益,一个例子是 ACR 中的 HDR 限制器,可以将后期制作时的 HDR headroom 限制到 n 档,比如设置了一个三档的限制,那么后期制作时显示器的最大增益是三档,但内容可能有超过三档的亮度增益,只是被裁切了。设置这个显示最大亮度增益的元数据的目的可能是用于还原制作时的创作意图。
关于 SDR 的名义亮度
虽然实际使用的时候很少遵守,但 SDR 其实是有规定的白点亮度的,比如 sRGB 是 80 nits,ITU-R BT.2035 里规定的是 100 nits。
可以按照这个亮度将 SDR 内容转换成绝对亮度,再应用逆向的 EOTF 编码,更多时候使用的名义亮度是 203 nits,这个亮度源自 ITU-R BT.2408 对各种亮度的推荐值,其中漫射白为 203 nits,但也说明了不能把这个漫射白亮度理解为 SDR 的名义亮度。