使用须知
感谢大家试用 HDR Conversion 并提出很多宝贵的反馈意见。
在使用各种代码库的时候,最痛苦的事莫过于“黑箱”和不一致,尤其是在面对 HDR 这种新兴的,较为复杂的图像格式时,用不同的库可能得到不同的数值结果。
为此,以 Google 开源的 libultrahdr 1.4.0 版本为基准,我对 HDR Conversion 0.1.5 版本进行了一些测试,并找到了一些待改进的方向和思考。
使用的三个样本是:
- A: 手机 V 拍摄的 JPG,包含一个 1/4 分辨率的 Gainmap,色彩空间为 Display P3。
- B: Adobe Lightroom 导出的 HDR JPEG,包含全分辨率的 Gainmap,色彩空间为 sRGB。
- C: 手机 H 拍摄的 JPG,包含一个 1/4 分辨率的 Gainmap,Baseline 空间为 Display P3,Alternate 空间为 BT.2020。
元数据读取
Gainmap 的元数据是该 HDR 格式重要的组成部分。HDR Conversion 目前的行为如下:
- 在读取 ISO 21496-1 时参考的是标准文件的数据结构,直接解析二进制数据得到的。在二进制中,一些浮点类型的元数据是以分子和分母的形式存放的,HDR Conversion 在读取时会将其转换为浮点数。
- 在读取 UltraHDR 时,使用的是
xml.etree.ElementTree解析 XML 部分。
ultrahdr_app -m 1 -P
三个样本的元数据读取结果如下(最大误差):
| 样本 | maxContentBoost | minContentBoost | gamma | offset | hdrCapacityMax |
|---|---|---|---|---|---|
| A | 2.91e-6 | 2.12e-7 | 0 | 0 | 2.91e-6 |
| B | 2.27e-6 | 4.69e-7 | 0 | 0 | 3.31e-6 |
| C | 3.29e-7 | 0 | 0 | 0 | 3.31e-6 |
误差可能来自 libultrahdr probe 的小数打印截断。可以认为 HDR Conversion 的元数据读取是可靠的。
读取 JPEG
ISO 21496-1 或 UltraHDR 包含至少两个 JPEG 图像:Baseline 和 Gainmap。HDR Conversion 目前使用的是 Pillow 读取 JPEG 图像。
在 libultrahdr 中,先输出原始的 YCbCr 平面,之后应用 BT.601 系数转换到 RGB。在测试中,部分像素出现了一个码值的差异,可能来源于整数舍入时的误差。尝试用 imagecodecs 读取 JPEG,结果与 Pillow 相同。
这一个码值的差异经过 Gainmap 应用过程后,在线性 RGB 上可能会带来最大约 0.034 的绝对差异。由解码 JPEG 带来的误差将不会被后续优化,完全依赖解码器实现。
Gainmap 使用
读取到两个图像和元数据后,HDR Conversion 会按照 ISO 21496-1 标准应用它们。主要包含以下几步:
- 将 Baseline 图像从 JPEG 解码的整数码值转换为线性 RGB。
- 将 Gainmap 重采样到 Baseline 的分辨率。
- 如果颜色空间不一致,按照元数据中的标识转换其中一个。
- 将 Gainmap 应用到 Baseline 图像,得到 HDR 线性图像。
HDR Conversion 目前的行为如下:
- 线性化:如果有 ICC,按照 ICC 中的 TRC 进行线性化;如果没有 ICC,按照 sRGB EOTF 进行线性化。
- 重采样:使用 opencv 提供的 Lanczos4。
- 颜色空间转换:读取 ICC,构建 RGB 到 RGB 的转换矩阵进行转换。
- Gainmap 应用:按照 ISO 21496-1 标准公式应用 Gainmap。
三个样本的在线性 RGB 上的绝对偏差如下,libultrahdr 输出为 linear RGBA half-float raw:
| 样本 | max | mean | median | p99 | diff > 0.1 |
|---|---|---|---|---|---|
| A | 1.7926 | 0.002780 | 0.000161 | 0.04654 | 0.3396% |
| B | 0.03392 | 0.000933 | 0.000633 | 0.003876 | 0% |
| C | 0.5564 | 0.004344 | 0.001120 | 0.04942 | 0.1461% |
差异来源按照影响大小排序如下:
- Gainmap 重采样:无需重采样的样本 B 差异显著小于需要重采样的样本 A/C。在
libultrahdr中,Gainmap 重采样使用的是 Shepard IDW,而 HDR Conversion 使用的是 Lanczos4。Lanczos4 在局部边缘可能会出现过冲,导致局部差异较大。 - sRGB EOTF:HDR Conversion 使用了参数化的 sRGB EOTF,而
libultrahdr使用了一个 1D LUT,可能存在部分差异。 - ICC CMS:HDR Conversion 目前包括一个简单的 ICC 解析器,能够处理任意符合要求的 ICC 文件,并根据其实际情况进行颜色空间转换。
libultrahdr将颜色空间分为 BT.709 / Display-P3 / BT.2100 三类,并使用内置矩阵进行转换。
针对重采样的问题,HDR Conversion 已在 develop 分支中引入了手动实现的 Shepard IDW 插值方法,和可选的其它重采样算法。使用样本 A 测试结果如下:
| resize method | max | mean | median | p99 | p99.9 | diff > 0.1 |
|---|---|---|---|---|---|---|
| Shepard IDW | 1.0203 | 0.001052 | 0.000104 | 0.01756 | 0.05921 | 0.0293% |
| Lanczos4 | 1.7926 | 0.002780 | 0.000161 | 0.04654 | 0.21732 | 0.3396% |
更加接近 libultrahdr 的结果,如果 ISO 21496-1 未来确定了重采样算法,HDR Conversion 将会默认使用。
关于 EOTF 和 CMS 导致的差异,我认为 HDR Conversion 的方案更适合科研和开发使用,也更贴合 ISO 21496-1 的定义。
关于 CICP
在 Gainmap JPEG 的 ICC 中,时常能发现一些 CICP tag,除了一些在标准中明确说明的,目前还不清楚它们的具体作用。
如果需要 Baseline 和 Alternate 使用不同的颜色空间,Gainmap 中的 ICC 需要包含 CICP Tag 来指示颜色空间。
CICP Tag 中的传递函数似乎不会起到作用,因为 Gainmap 的线性化使用的是 Gainmap metadata 而不是 ICC。有部分图片的 Gainmap ICC 中无 TRC 字段,在 CICP 中指定了 PQ 或者 HLG,但不清楚其作用。