组内新人培训(三):色彩范围碎碎念,以及Expr

NAZOrip@F
NAZOrip@F 2017年10月19日
  • 在其它设备中阅读本文章


    对于应用层的视频压缩技术,大体上,从零开始学习大概要经过几个过程,
    其一是学会通过顺序叠加滤镜来处理视频瑕疵,这个阶段我们称之为入门。
    其二是学会使用正确的逻辑来使用滤镜,诸如进行UnsharpMask之前要加降噪预处理以防止同步锐化噪点等,这个阶段我们可以用理论知识来武装自己,使压制过程更加科学。
    其三则是使用更复杂的处理流程对逻辑进一步优化,简单展望比如多重预处理结构、基于神经网络训练出的新插件、基于心理学优化的客观评价算法的自适应优化等等。

    对于前两点,其实前人做了充足的工作,在之前几期组员培训中也提到过,网络上有很多不错的教学资料。而对于后一点,很多新技术还在酝酿的过程中,有一些我们也讲不清楚。所以现在的情况是,虽然大体上理论框架是齐全的,但细节部分仍需要修修补补以降低其入门门槛。你有这个能力但不去做,阻碍了广大人民群众生产力解放的责任你担得起么?
    这也是我们偶尔碎碎念,做些组内教学的原因。而我们的定位也是对已有的资料做些补充,如果有机会偶尔也可能会涉猎一些黑科技。
    从这个意义上讲,虽然都不是什么复杂的东西,但对于新人来说看不懂是很正常的。
    这就是我说了这么长时间想告诉你的结论,后面的教学文章都是如此,往后就不再提了。

    另外值得一提的是,作为一个刚入群的新人压制者,你看到第一篇的手把手教学觉得很亲切,看到第二篇就开始讲滤镜觉得有点快,看到第三篇就准备讲堆栈了有点发懵。从本篇教学开始我们所做的内容就不是面对24k纯新的了,更多是的以专题的形式呈现。如我刚才所说的,即便如此这些也都是一些基础内容,也并不存在什么难度。只不过要看懂的话我们默认你已经学会了VCB公开课程和组长视频教程的全部内容,如果没有的话建议你先不要接触这些黑魔法,先回去接受完整洗脑。

一、色彩范围碎碎念

如果你一路跟着这套教学读下来,那你应该会发现整个系列中的应用倾向性是非常强的。比如你看我几乎没提过反交错的内容,几乎没有提到过位深转换的内容,这些可是都以往的ripper必备的知识,只不过有很多陈年旧事现在不会遇到我们就不再提。

TVrange、PCrange、YC伸张、YC收缩这些都是老生常谈的问题了,前几天群里有朋友在讨论,心想现在还是偶尔会遇到的,于是再拿出来讲一下。

简单来说,TVrange和PCrange分别表示8bit下[16,235]和[0,255]的色彩范围。从TV到PC以及从PC到TV就分别被称为YC伸张和YC收缩。
如果你看过YUV模型中各个平面的颜色分布就会发现,luma平面的分布比较广泛,而chroma平面则相反,其信息都集中在中心区域(如图)

请输入图片描述

所以通常我们在视频处理中对颜色越界的处理通常只针对luma平面,这是由YUV转换公式决定的。
当然如果在一些特殊情况下进行正规的YC变换的话还是需要联通chroma平面一同调整的。值得注意的是例如8bit下luma的TVrange是众所周知的16-235,而chroma平面则是16-240。

那么为什么要进行YC变换呢?
由于人眼观感上对于极端低亮和高亮区域的分离不明显,当我们发现在某些场景中,由于SB制作人员的疏忽,导致了色彩范围错误,某些细节本来画上去了,但是都集中在过暗区域或过亮区域,就是看的不清楚,这种时候就要通过YC变换让这一部分细节“变”出来,如下是VCB科普里的范例图。
请输入图片描述请输入图片描述

但是我个人对这种处理持保留态度,我认为应当具体情况具体分析。
道理可以很简单,YC伸张的直观视觉效果是画面变“暗”,YC收缩的直观效果是画面变“亮”。

如果将过暗的区域提亮,或将过亮区域的调暗,那么被隐藏的细节就会显现出来,反之,如果将不该暗(本来就很暗)的场景变得更暗,不该亮(本来就很亮)的场景变得更亮那么就会出问题,两者的共同结果是导致信息损失。一部动画中必然是在整个色彩值域上都覆盖有像素,暗场和明场都有分布。实际操作中你会发现,经常性地你在场景A使用YC收缩获得了比原来清晰的细节,但却会引起场景B中的细节丢失。所以我认为逐GOP调整是可行的,全局性调整是必然带来信息损失的。

所以什么时候需要调整,什么时候不需要调整。这是否是一种随个人兴趣而定的主观调整,而你又是否有时间去逐场景整理?这就是制作者需要思考的问题了。

二、关于Expr工具

上面的色彩范围云云都是引子,实际上本篇文章主要想讲的是expr工具。
作为vs提供的三大原生调色板工具之一,海量的功能以它为基础,比如上文的YC变换我们就可以用expr实现。
比如如果我们要进行线性伸张,那么表达式就可以写成["x 16 - 219 / 255 *","x 16 - 224 / 255 *"],两个双引号内分别表示亮度和色度的处理方案。
理论上你也可以采用其他伸张方案,只要函数保持单调增即可,比如一个下凹曲线,也许还会来的更加科学。
但是我们实在没办法按照自己的兴趣来控制这条曲线的曲率,所以一般不会这么做。
YC伸张效果直观对比(可观察木门上纹理的区别。由于该图并没有颜色越界,所以这种处理是错误的,这里仅用作举例。值得注意的是,在vs的YC变换的实际应用中,既存在像Expr/Levels这种直来直去的逐像素变换方案,也存在fmtc.bitdepth这种附带dither的保护性方案,使用时应具体情况具体分析。)

诚然expr可以实现的所有功能lut和lut2都可以做到,不过expr却具有lut没有的优势,比如说expr对多平面同时处理时支持原生16bit的输入输出,不像lut2最多支持各平面合计20bit。比如lut的计算逻辑是在每次运行脚本时预先计算结果储存在内存中,调用时查表,而EXPR每一次调用都要再进行一次单独运算而避免查表(查表也是要耗费计算力的)。实际测试中在不同算式复杂度结合使用两种方案可以优化脚本的执行效率。

然而有这么多优势,为什么而大家还是喜欢lut而不喜欢expr呢?
因为人家lut2是可以清楚地写出逻辑结构的,而expr则需要用到堆栈。
很多人一看到堆栈就怕了,堆栈是什么几把玩意,走了走了。

请输入图片描述

实际上没有这个必要,这其实只是一点小把戏,本篇文章就是对这部分内容进行补充。
VCB公开课程中有一章详细介绍了堆栈的逻辑,其中中缀表达式和后缀表达式的转换方法都已经被介绍的很详细了。事实上,需要堆栈知识的地方仅限于“如果要编写一个自动将中缀表达式转换为后缀表达式的脚本”之类的情况(如果你真的写过会发现其实是一种不错的逻辑训练,推荐有志青年用各种姿势尝试),在应用层面,了解堆栈原理固然好,就算不求甚解,对expr使用也是完全不打紧的。不管怎么说,你在阅读过lp的教学后应该能很容易地将 (1-2)^3/4+5 这个中缀改写为["1 2 - 3 pow 4 / 5 +"]的表达

但有一个问题是lp在教学中没有提到的,也是我刚开始一直没搞懂的,条件结构应该怎么写?
比如利用中缀表达式写的 x>y?0:255
表述这样一个逻辑

if x>y:
    返回0
else:
    返回255

它在后缀表达式中的对应范例为:"x y > 0 255 ?" 即"x y 判断条件 真值 假值 ?",如果有elif,向其中叠加就可以了。
试着自己写一写,你会发现它的逻辑简单到令人发指,可能你最开始还需要先列个草稿,但当你熟悉之后比如你要写一个判断当前y平面有没有颜色越界(低于16或高于235),有则标白无则标黑。那么就可以直接写出"x 15 <= 255 x 236 >= 255 0 ? ?"连眼睛都不用眨一下。

其他的应用比如说结合GradFun3和f3kdb的优势合成一个变化范围二者取大(或取小)的去色带平面,那么可以写成这样

core.std.Expr([g3,f3,src],["x z - abs y z - abs > x y ?"])

当然如果你一定要用复杂一点的写法来展现自己已经熟练掌握了expr也是可以的(笑)

"x z - abs y z - abs > x z > z x z - abs + z x z - abs - ? y z > z y z - abs + z y z - abs - ? ?"

虽然已经讲了这么多,但我才不会告诉你如果用Lut的Functions不光可以用普通的逻辑结构写而且不会多次计算呢

迷之压制组,这个组的一切都是迷。
我们下期再见。