OCIO v2 的好处都有啥
- Color
- 三十分钟系列
OCIO v2 的好处都有啥
起源
最近ACES
的各种讨论感觉又火了起来。ACES
经过这么多年的打磨、更新、教育、标杆作品出现,使得行业对于ACES
的接纳程度越来越高了。
我个人觉得最功不可没的还属是各大软件厂商的支持,使得ACES
不再是少数人的玩具,每个人都可以自己在软件里面,自己摆弄一下各种in colorspace
和out colorspace
选项,就能够看到直观的色彩变化了。
今天,不说ACES
本身了,说说ACES
背后的“好心人” OpenColorIO
。
OCIO
手撸实现 vs 不禁让我想起自己在2014年左右开始研究ACES
的时候,自己看着CTL
的算法在各种软件里面进行实现,其中包括python
、nuke NDK
、OFX
、renderman shader
等,非常麻烦:
- 每个实现方式都略有不同
- 纯粹
CPU
的实现效能又比较差……(主要还是因为自己人菜)
OCIO
作为ASWF
接纳的开源项目,是一套非常成熟的色彩管理解决方案。有了OCIO
,所有的色彩管理都可以认为是一套“方案”或者“预设”,OCIO
按照这个方案对色彩进行运算处理即可。
好处主要有:
- 色彩管理方案 和 实际运算引擎 分离。兼容未来新的色彩空间,无需每出现一套新的处理方案就需要重写计算部分
- 分离后的色彩管理方案,可以轻松实现自定义配置。版本控制优秀
- 可以保证在所有支持
OCIO
的软件内得到相同的结果 - 软件厂家只需要内嵌
OCIO
,无需自己亲自实现色彩运算部分 - 让色彩管理操作简化,降低用户跨软件的学习成本
提示
不得不说,Sony Pictures Imageworks 真·好心人! 又把自家的好东西拿出来了~
OCIO v2
来了!
相关信息
OCIO v2
主要是由Autodesk 主导,在2017年开始开发,2021年1月放出官方正式版。
可以拍着胸脯来说,只要你用了比较新的VFX 软件,那么OCIO
基本上已经是标配了,即便不了解色彩管理的背景知识,还是可以进行操作:
- 开启
OCIO
配置 (或插件) - 选择某个
OCIO config
文件 - 根据实际制作规范,选择对应的in、out 色彩空间
- 开干!
OCIO v2
对艺术家的影响其实不大,因为操作没有什么变化。但是底层变化比较多。其中比较大的功能性更新主要有:
- 全新的
GPU
渲染器。速度快+保证和CPU
效果一致 - 更快的
CPU
渲染器。利用SSE 指令集
,最快提速20x - 支持整形像素buffer。
和我们关系不大 - 更好的针对处理器优化。
和我们关系不大 - 所有操作都支持反向
- 支持
ACES
的全新操作器。与ACES
官方CTL
效果一致 - 支持
ASC CLF
。支持并且很彻底的支持了ACES 1.2
中的CLF
格式 - 内置了常用的色彩转换,省着连最基本的转换都需要自己去找
LUT
- 所有的
OCIO
转换操作,都能够转换成为CTF xml
- 可以通过公开的API 进行所有操作
- 可以用
Display-referred
类空间作为connection space
。不必所有的转换都需要回到scene-referred
。 - shared view 可以对于多个显示器进行复用。
和我们关系不大 - 支持
ICC profile
文件。嗯……支持的很基本 - 太多了…… 自己可以去OCIO v2 去看
LUT
,又来了!
计算反向看完了刚才那一大堆OCIO v2
的新特性,不知道你有没有很敏锐的发现一些小秘密?
提示
所有操作都支持反向?!那岂不是…… 3D LUT
?
没错,计算反向LUT
,他又回来了!
TL;DR
如果你只是想得到一个反向LUT
,那么跟着下面操作就行了。
- 安装
OCIO v2
brew install opencolorio
- 等待漫长的安装
- 开始计算反
LUT
ociobakelut --format resolve_cube --invlut [INPUT.cube] --cubesize 65 [INV.cube]
- 好了
更加详细的解释
如果读到了这里,我估计你不会满足于上面的操作。是不是想要了解更多?
- 这个反
LUT
的效果怎么样? OCIO v2
的反LUT
算法是什么?- 比起之前自己写的那么多种反向计算
LUT
算法,有什么优势?
效果
首先来看反LUT
的效果。这里测试使用的是Sony Slog Sgamut3.cine to Rec709
的官方LUT
。
原始 | 原始+官方LUT | 原始+官方LUT+反LUT |
---|---|---|
简单来说,可用!还不错!操作非常简单!综合性价比高!
具体分析一下的话,首先是肉眼观感,基本上可以做到非常不错的抵消。但是从标准color box
就能看出来问题了,还是对于clamp
或者极度压缩的区域是无法很好的处理。(这本身就是一个 ill problem,原理上无法解决,只能 trick 来逼近)
算法是如何实现的?
OCIO
是开源的,那么所有的答案自然就在他的代码里面了。我们去OpenColorIO 的github 仓库 看看。
经过一番学习,我目前理解的算法方式如下(还没仔细看,不代表正确)。
参考:OpenColorIO/src/OpenColorIO/ops/lut3d/Lut3DOpCPU.cpp
中的
void InvLut3DRenderer::apply(const void * inImg, void * outImg, long numPixels) const
{...}
unsigned long invert_hypercube
(
unsigned long n,
float* x_out,
const float* gr,
unsigned long* ind2off,
float* val,
unsigned long* guess,
unsigned long list_len,
long* ops_list,
unsigned long* entering_list,
unsigned long* new_vert_list,
unsigned long* path_list,
unsigned long* path_order
)
{...}
算法原理
首先LUT
对于整体色彩空间来说,产生的是一种“非均匀的形变”。有点像是橡皮泥一项,可以随意的捏。这里用2D 格子来进行说明。
但是对于4号小格子来说,由于LUT
的精度限制,所以可以认为一个小格子只能发生仿射变换。
好了,当出现“仿射变换”的时候,线性代数就告诉我们,问题就比较好解决了。整个求反向LUT
的大问题就被拆解成了两个小问题:
- 如何找到重新采样的晶格顶点,属于哪个格子?
- 如何对一个小格子求解仿射变换的逆变换?
重新采样的晶格顶点属于哪个格子?
如何确定重新采样的晶格顶点,属于形变后哪个格子?
我们还是画图来看。对于LUT
变换后的色彩空间重新进行均匀的顶点采样,可以看到重新采样的3号格子的右下角顶点,落在了变换前的4号格子内。
这里有很多技巧可以优化查找速度,不过最粗暴的方法就是进行遍历!由于LUT
只需要生成一次,所以即使慢也没有什么太大的关系。
仿射变换的逆变换
当确定3号格子的右下角晶格点属于原先的4号格子后,我们就需要进行逆变换。计算出晶格点对应原始空间的坐标。
这个空间坐标就是反向LUT
对应的数值!
算法的一些问题
很明显这个算法的性能很好,这符合OCIO
对于实时处理的需求。不过也存在几个问题:
- 如果小格子被压缩成为一条线?也就是仿射变换矩阵的秩 = 0,那么就没有逆矩阵了(可以求伪逆)。在
LUT
边缘处很容易出现这个问题 - 重新采样的一个格子,对应的顶点,往往会属于多个变换前的格子。仅仅对于每个顶点求解逆变换,并不是该格子内部所有点的最优解。
和其他反向算法比起来?
我也写过好几种不同的反向计算LUT
的算法了。由于OCIO v2
的反向算法也是完全无需人工干预的,所以这里就不和 色彩匹配算法(3D Thin-Plate Spline)比较了,主要和利用机器学习的梯度下降算法进行比较。
还是先说结论:
对比项目 | OCIO v2 算法 | 梯度下降算法 |
---|---|---|
肉眼感官 | ✅ 优秀 | ✅ 优秀 |
数值精度 | ✅ 中心区域优秀 ⚠️ 边缘range稍优于梯度下降 | ✅ ✅ 中心区域更优秀 ❌ 边缘抖动| |
计算速度 | ✅ 很快(秒级) | ❌ 很慢(半天级别) |
实现难度 | ✅ 无需自己实现 | ❌ 自己实现门槛高 |
操作难度 | ✅ 安装即用 | ❌ 要敲代码,或者封装 |
从上面来看,综合性价比最好的选择就不用我说了吧……
总结
你觉得命令行操作依旧很麻烦?
如果你有安装nuke 13.1
以上的版本,就会发现nuke
内嵌的OCIO
已经是2.0 版本啦,那么反向LUT
的操作甚至可以直接在软件内的OCIO FileTransform
节点中进行操作!
不过经过对比,发现这种方法得到的效果和使用ociobakelut
生成LUT
的方法有一些区别。
目前比较值得怀疑的点是 OCIO
提供了 OPTIMIZATION_LOSSLESS
和 OPTIMIZATION_LUT_INV_FAST
两种模式,nuke
在软件内追求速度,所以使用了FAST 模式;而ociobakelut
命令行不关心速度,就使用了INV_EXACT 模式。
Andy 泪目
曾经的知识,在新的科技面前,变得好像没什么了不起了 😭
参考阅读: