色带处理
Last updated
Last updated
俗话说知己知彼,百战不殆,要对付色带这一号敌人,了解色带是如何产生的非常重要。
首先,色带往往出现在画面中的平面部分,大面积的色块往往是色带集中出现的区域,同时,一些渐变场景也常常会看到它。在现在的显示设备上,我们常常采用8bit每通道的RGB来量化色彩灰阶并显示画面。也就是说,RGB每个通道可以有256种灰阶表示,我们总共能显示的颜色种类就有256*256*256,也就是16777216种颜色。
你可能会说:好耶!有那么多颜色能表示,怎么会出现色带呢!
其实很简单,最简单粗暴的试想一下,屏幕上出现了一条从黑到白的线条,从最左到最右总长1920个像素,那每一个灰度区间如果从线性的角度讲,一个区间会长约7.5个像素,那区间和区间之间就会出现明显的一条痕迹,这就是色带的来历。所以,8bit下无论怎样都很有可能会出现色带,只是你能不能看得出而已。
当然了,上面特意提到了线性的角度,那么实际上,我们日常看的显示器内容,都是已经经过gamma校正了的,关于gamma校正这里不想细究,它的作用是通过重新分配灰度系数,让对黑暗不敏感,亮部敏感的人眼能够更清晰的看到画面中偏黑的区域。简单的来说,你看到的灰阶从最暗到最亮的分配并不是均匀的,越黑的部分分配的灰阶越多,这听起来可能有点怪,但是通过下图我们可以直观的感受到区别。
如果我们用5bit(32位)来表示的话,那么必然会出现色彩断层,但是线性分布和gamma校正后的感觉会完全不同
Gamma的出现虽然让人眼对画面的光暗得到了巨大的提升,但是它也打破了灰度的均匀分配,让色带更可能出现了。
其实方法总结下来就是两点,要么添加噪点,要么就将构成色带的像素替换为临近像素的中间值(其实就是一个字,抹!)
很显然的,由于我们是人类,眼神十分的堪忧,没有经过特别的训练和熟悉一般很难看出色带,所以加点噪点可以更进一步的混淆人眼,让我们感觉不出色带的存在。同样的,你也很难在画面的纹理部分看出色带,只有什么都没有的纯色块/平面才会让色带看起来非常明显。
当然,这样无脑的加噪会影响观感,而且效果也只能算凑合。我们接触的大部分BDMV都会为了防止色带打上一层不痛不痒的噪点(所以我们俗称SBMV),这么做属于治标不治本的办法,但是保留噪点作为去色带操作后的保底是一个不错的选择,万一色带没抹干净好歹还有层噪点做遮羞布,其实也挺好的。
如果想要加噪,最直接的方法就是使用AddGrain来进行:
addgrain = core.grain.Add(res,1.0)
需要注意的是,加噪的时候,我们一般不推荐添加色度平面的噪点。毕竟彩色噪点看起来真的很不好看,还让本来就码率预算不充足的色度平面更加雪上加霜。所以我们推荐在加噪后,使用std.ShufflePlanes
来仅将加噪后的Y平面与原Clip拼成一个新的Clip
当然了,全屏幕直接加噪,还是不够优雅,毕竟噪点也是占用大量码率的,我们希望能够好钢用在刀刃上——在需要加噪的地方加噪:
很显然的,大部分噪点其实出在比较暗的地方,较亮地方的噪点用打噪点也没办法很好的糊弄过去,较暗的地方打噪点效果就比较好,那么有没有一种办法,能够让噪点打在暗的地方呢?
以下部分需要对:std.Expr()有一定程度的理解,对std.MaskedMerge有一定程度的理解
这时候就需要一些简单的数学知识了:
首先我们创建一个blankclip,所有像素的值都是32768,再对这个clip进行加噪:
然后我们可以设计一个函数(例如二次函数)作为Mask,将0-255的8bit输入(x),转化为每个16bit下的像素应有的0-65535的权值(y)
如果y越接近与0,那么意味着噪点会被尽可能的添加回去
如果y越接近65535,那么意味着噪点会被尽可能的不添加回去
nrweight = core.std.Expr(src8, ["x 48 - dup * 5 *", ""], vs.YUV420P16)
然后我们使用std.MaskedMerge()
来基于Mask合并片源与噪点层:
out = core.std.MaskedMerge(noise,nullclip,nrweight,[0,1,2],True)
我们就获得了一个能够自适应添加噪点的clip了!
抹这个操作就字如其名了,检测色带,针对色带进行平滑就是抹的主要目的,我们常常使用f3kdb来进行去色带操作,但是如果遇到真的,非常难搞的色带时,GradFun3也是个不错的选择
f3kdb的效果在deband滤镜中已经算是翘楚了,它的原理听起来也非常简单:将构成色带的像素替换为临近像素的中间值,并抖动加噪从而摆脱色带。很显然,这样的操作与降噪很像,并且会抹去画面中的细节。
f3kdb的所有参数的具体信息都可以查看滤镜百科中去色带滤镜部分,这里来讲讲f3kdb的常用写法:
由于BDMV里会默认添加一层噪点,它对于f3kdb滤镜去色带会有巨大的影响,所以一般我们需要在降噪之后再使用f3kdb,以保证最好的效果和最小的细节损伤,这个操作一般被称为:nr-deband
待续
例如这个函数,在的时候(8bit下这是相对暗的区域),的取值是0,代表在这个区域的加噪强度是最高,而由于二次函数的特性,所以接下来的曲线会特别陡,在时,,加噪强度已经降低到了50%,并且在左右时,降噪强度已经变为0%,这样的函数可以说是比较理想的,当然如果你想调整零点或者曲线开口程度,那相信你应该知道该怎么改这个函数。所以,我们可以用VS中的Expr来基于clip创建这样一个mask: