关于图像的YC压缩与YC伸张

来源:互联网 发布:python在spss中的应用 编辑:程序博客网 时间:2024/05/17 07:32

这两天一直在研究图像的RGB显示超限的问题,谷歌了老半天,终于找到一篇Silky的帖子。帖子内容如下,希望可以帮到有需要之人。

 

我把以前写过的东西做一个整理,因为时间的关系,我没有办法把每一个细节都讲得非常的详细,不过我会把大概的原因,和处理的方法,尽量用很精简的方式,条列整理出来。
如果对更深入的原理有兴趣,请搜寻过去零散的讨论。

一切都要从 ITU-R BT.601 这个"建议"开始说起。
现今的 DVD/VCD/DV 都是遵循 ITU-R BT.601 这个规格,这个规格规定了,模拟影像转数字时,取样的方式,储存的数据格式、数据范围等等。
当影像转为 MPEG 的时候,RGB 数据要转成 MPEG 使用的 YUV 格式。ITU-R BT.601 里面规定了这个 RGB <-> YUV 的转换式,数据范围 0~255 的 RGB 要转为 YUV 的时候,要先做数据范围的压缩,把范围压缩成 16~235,然后才转成 YUV 储存起来。然后 MPEG 解压缩的时候,解出来的 YUV,要做数据范围的扩张,将 Y: 16~235, UV: 16~240 的数据扩展为 0~255 的 RGB,也就是还原回原来的 RGB 数值,然后才能显示在显示器的屏幕上。
这个 0~255 RGB -> 16~235 YUV 的过程,就叫做 YC 压缩。
反过来 16~235 YUV -> 0~255 RGB 的过程就叫做 YC 伸张。

我们可以很清楚地看到,YC 伸张和压缩要互相搭配,最终显示出来的结果才正确。
如果:
A. 播放时
1. 转 MPEG 的时候没有做 YC 压缩,储存的是 0~255 的 YUV,播放时就不可以做 YC 伸张,否则 0~255 的资料再伸张一次,会变成 -19~278。
当然,8 bits 的数据储存范围只能是 0~255,数据超出的范围会被削掉(clipping),整个画面对比会过强,色彩会崩溃。

2. 转 MPEG 的时候有做 YC 压缩,储存的是 16~235 的 YUV,播放时就一定要做 YC 伸张,如果不做 YC 伸张,显示的是 16~235 YUV -> 16~235 RGB。
RGB [235,235,235] 在显示器上看起来不是纯白,而会有点灰灰的,[255,255,255] 才是纯白。
相同的,[16,16,16] 看起来也不会是纯黑,[0,0,0] 才是纯黑。
16~235 的 RGB,数据范围(动态范围)缩小,对比会变差,色彩黯淡,看上去好像蒙上了一层白纱。

显示卡的 DirectDraw Overlay,使用硬件的 YUV -> RGB 色彩空间转换,都会遵守 ITU-R BT.601 的建议,认为 MPEG 的 YUV 数据范围应该是 16~235,所以都会做 YC 伸张。
所以我们可以得到结论,当转成 MPEG 的时候,一定要确保 YUV 的数据范围是 16~235,这样在计算机上看、在电视上看,才会看到正确的色彩、对比表现。

所以
B. 压缩时
1. 如果输入的 RGB 数据范围是 0~255,转 MPEG-2 时就要先做 YC 压缩,转成 16~235 的 YUV,这样将来播放时显示才会正确。

2. 如果输入的 RGB 数据范围是 16~235,转 MPEG-2 时就不能做 YC 压缩,要直接转成 16~235 的 YUV,这样将来播放时显示才会正确。
如果输入的是 16~235 RGB,转 MPEG 时又再做一次 YC 压缩,数据范围会变成 30~218 YUV,这样即使将来播放时做 YC 伸张,还是只能伸张到 16~235 的 RGB,结果还是不对。


那么,重点就是
1. 怎么知道输入的讯源是 16~235 RGB,还是 0~255 RGB?
2. 怎么知道压缩的 MPEG 软件在转 RGB -> YUV 的时候会做 YC 压缩,还是不做 YC 压缩?

 

我们先看第一点,假设你的讯源是:
1. DivX/XviD 的 AVI,要转 DVD/SVCD/VCD
DivX 和 XviD 都遵循 ITU-R BT.601 规范,解码输出 RGB 时都会做 YC 伸张,所以以 DivX/XviD 的 AVI 作为讯源,都是 0~255 范围的 RGB。

2. 讯源是 DVD,或 HDTV 的 MPEG-2 TS,或其它 MPEG 文件
看你用来解码 MPEG,输出 RGB 的软件是哪一个,这个软件解码输出的设定为何。

例如:
2a. 解码软件是 DVD2AVI,在 RGB -> YUV 的设定底下有两个选项,一个叫做 PC Scale,另一个叫做 TV Scale。选 PC Scale,解码就会使用 PC Scale 的转换式,输出 0~255 的 RGB;选 TV Scale,解码就会输出 16~235 的 RGB。

由上述的说明,我们可以知道 DVD2AVI 的一个运用:
当我们不勾选 DVD2AVI -> Help -> DirectDraw Overlay 时,DVD2AVI 不会启动 DirectDraw Overlay,而是走传统的 GDI 显示方式,输出 RGB 给显示卡显示。此时画面上看到的色彩,会受 YUV -> RGB 选项底下设定的 PC/TV Scale 影响;选 TV Sclae,颜色黯淡;选 PC Scale,颜色正确。
当我们启动 DirectDraw Overlay,此时画面的显示,是由 DVD2AVI 直接输出 YUV,走 DirectDraw Overlay,丢给显示卡去做 YUV -> RGB 的色彩空间转换。此时画面上显示的颜色,由显示卡决定,PC/TV Scale 的设定完全不影响看到的画面。
而显示卡的色空间转换,如前所述,不乱搞的话,都是遵循 ITU-R BT.601,用 PC Scale。

在接下去说明之前,要先介绍两个名词:
0~255 的 RGB,又叫做 full-range RGB
16~235 的 RGB,又叫做 compressed-range RGB

更深入的介绍,有兴趣的人可以参考 SGI 网站上的这一篇好文章
Digital Media Programming Guide Chapter 2. Digital Media Essentials

知道这两个新名词后,接着往下看
2b. 解码软件是 m2v,在 m2v 的设定画面里,YUV Range 底下有两个选项让你选择,一个是 Full Range,另一个是 ITU-R BT.601 Range。怎么样,是不是觉得这两个名词很熟悉  

相信看过上面的解释,您应该可以猜到,选 Full Range 的意思是代表告诉 m2v,我的 YUV 数据范围已经是 0~255 的 YUV 了,不要再做伸张了唷。所以选 Full Range,m2v 就不会做伸张,而是直接转换。
相反的选 ITU-R BT.601 Range,就是告诉 m2v,我的 YUV 数据范围是 16~235,输出时请做 YC 伸张。

所以:
1) m2v 选 Full Range,等于 DVD2AVI 的 TV Scale,输出时不做 YC 伸张,16~235 YUV 输出的是 16~235 RGB。

2) m2v 选 ITU-R BT.601 Range,等于 DVD2AVI 的 PC Scale,输出时会做 YC 伸张,16~235 YUV 输出的是 0~255 的 RGB。

其它 MPEG Decoder,请自行实验其输出结果。

3. 如果讯源是 DV-AVI
看用来解码的 DV Codec 是哪一个。
如果是 Canopus DV Codec,不会伸张,16~235。
如果是 MS DV Codec, Panasonic DV Codec,会伸张,0~255。

4. 讯源是用 PhotoShop 等绘图软件,自制的计算机动画
无庸置疑,是 0~255 RGB。

 

OK,这样我们就知道讯源是 0~255 还是 16~235 了,接下来,第二点,MPEG 压缩软件会不会做 YC 压缩?

答案是,不同软件有不同做法。我试验过的几个:
1. 可以自由切换选择要不要做 YC 压缩
TMPGEnc, CCE SP

2. 一律做 YC 压缩,当成输入的都是 0~255 RGB
MainConcept MPEG Enocder, Panansonic MPEG2&1 Encoder
DivX, XviD

3. 一律不做 YC 压缩,当成输入的都是 16~235 RGB
MPEG Conversion Studio, ProCoder。

我们以 TMPGEnc 为例
TMGEnc 选择切换要不要做 YC 压缩的选项,叫做 "Output YUV data as Basic YCbCr ont CCIR601"。
名词解释时间  
0~255 YUV = full-range YUV,TMPGEnc 叫做 Basic YUV (YCbCr)。
16~235 YUV = compressed-range YUV = ITU-R BT.601 YUV,TMPGEnc 叫做 CCIR601 YUV。

勾选 "Output YUV data as Basic YCbCr ont CCIR601" 这个选项,TMPGEnc 就会认为要输出的是 Basic YUV = 0~255 YUV,所以不做 YC 压缩,直接转换。
不勾选这个选项,TMPGEnc 会认为要输出的是 CCIR601 YUV = 16~235 YUV,所以会做 YC 压缩,转成 16~235 YUV。

会不会很复杂,开始头晕了? ^^;
没关系,我最后会总结整理成一个很简单的列表,但是在此之前我必须先说明完原理,因为组合的情况有很多种,不同 Decoder 输出不一样,不同 MPEG 压缩软件的处理不一样,我不可能有时间一一去测试所有的组合情况,所以唯有您自行理解原理,了解吸收了以后,遇到不同的组合,您才能知道要怎么设定,而不是只死记一种做法,这也是为什么我会不厌其烦地,再三地解释、说明这些令人头晕的道理 ^^;

那么会有哪些组合的情况呢?
在 TMPGEnc 的网站上曾经出现过一篇很精彩的讨论,参与讨论的有 TMPGEnc 的作者崛老,还有 m2v 的作者 marumo(那位署名 "茂木" 的即是 marumo)。
在这篇讨论中崛老提到,"Output YUV data as Basic YCbCr ont CCIR601" 选项做的事情,是当 RGB -> YUV 的时候,使用不同的转换式,不勾会做 YC 压缩,勾了就不做 YC 压缩。崛老还举出了所有可能的情况,我把他翻译过来给大家看:
http://www.pegasys-inc.co.jp/bbscgi/bbs/board.cgi?board=tmpgenc&cmd=topic&wparam=182

1. 当讯源不是 CCIR601 标准,也就是 (0~255) 时
不勾 ==> RGB(0~255) -> YUV(16~235) 正确 ^_^

勾 ==> RGB(0~255) -> YUV(0~255)
播放时会做伸张 YUV(0~255) -> RGB(-19~278) 超过 0 和 255 的数据都会被削掉,
画面色彩崩溃,错误 >_<

2. 当讯源是 CCIR601 标准,也就是 (16~235) 时
不勾 ==> RGB(16~235) -> YUV(30~218) 颜色变淡、对比变差,画面好像罩上了一层白雾 >_<

勾 ==> RGB(16~235) -> YUV(16~235) 正确 ^_^

然后崛老说像 Canopus DV Codec 这种 CCIR601 标准(不做伸张)的讯源,
要勾选才正确;反过来说,非 CCIR601 标准的讯源(做过伸张),不勾选才正确。

 

所以总结起来,如果讯源是 MPEG,用 DVD2AVI 解码,则正确的做法

代码:

DVD2AVI PC Scale -> 0~255 RGB -> TMPGEnc 不勾 "Output YUV data as Basic YCbCr ont CCIR601" DVD2AVI TV Scale -> 16~235 RGB -> TMPGEnc 要勾 "Output YUV data as Basic YCbCr ont CCIR601"同理,如果是 m2v 解码

代码:

m2v ITU-R BT.601 Range -> 0~255 RGB -> TMPGEnc 不勾 m2v Full Range -> 16~235 RGB -> TMPGEnc 要勾如果用的是 CCE SP 来压 MPEG,CCE SP 切换的选项在 Video 里面,叫做 Luminance level,有两个选项
16-235 = 做 YC 压缩 = TMPGEnc 不勾 "Output YUV data as Basic YCbCr ont CCIR601"
0-255 = 不做 YC 压缩 = TMPGEnc 勾 "Output YUV data as Basic YCbCr ont CCIR601"

所以

代码:

DVD2AVI PC Scale -> 0~255 RGB -> CCE SP 选 "16-235" DVD2AVI TV Scale -> 16~235 RGB -> CCE SP 选 "0-255"m2v 的情况依此类推。


如果 MPEG 压缩软件不能切换 YC 压缩的选项,例如 ProCoder,那怎么办?
我以前写过一篇,转贴过来,省打字时间
==
ProCoder 1.5 版有个重要的更新,ITU-R BT.601 color correction 设定,
可以让你选择要不要做 YC 压缩,这是一个很重要的设定。

TMPGEnc 有这个设定,"Output YUV data as Basic YCbCr ont CCIR601",
这个设定不是"改善"色深,而是做"正确"的选择,保持本来的颜色。
本来就应该要根据输入的讯源,正确的选择切换这个选项,才能得到正确的结果。
这个选项不是用来"改善"或者是"补强"用的,不要弄错了原本的意图。
其它 MPEG 压缩程序例如 CCE SP 也有相同的设定。

而 ProCoder v1.01.35 版没有这个设定,一律将 input 视为是 CCIR601 YUV
(颜色范围是 Y:16~235, UV:16~240),所以使用者无法根据使用的讯源做切换。
Canopus 本身的 DV Codec 便是输出 CCIR601 YUV,其 RGB 范围是 16~235,
刚好和 ProCoder 互相搭配。但是其它 DV Codec,例如 MS 的 DV Codec
Panasonic 的 DV Codec,输出的则是 Basic YUV。

这样压缩 CCIR601 讯源时没有问题,但是遇到 Basic YUV(颜色范围是 YUV:0~255,
例如自行用计算机绘图制作的 CG 动画,做过 YC 伸张的 DVD/VCD/DV 讯源... 等等),
ProCoder 就惨了,压出来的对比会过强,色彩会完全崩溃。

有时候 Basic YUV 的影片本身的对比、色彩并不是很强烈,经过 ProCoder 错误的压缩后,
反而会让人有"色彩变鲜艳了"的感觉,不过其实那反而不是原本的颜色。
如果影片本身的对比、色彩本来就很强烈,再经过错误压缩,就会发生凄惨的"色崩"现象。
由于这个后果不是我们能预期、控制的,所以如果真要调整颜色,还不如用正确的色彩压缩设定,
让所见即所得,然后另外用调整颜色的滤镜自行修改颜色,调整到我们需要的样子。

由于 ProCoder v1.01.35 没有提供切换 YC 压缩的设定,所以遇到 Basic YUV 讯源,
在送给 ProCoder 压缩之前,你需要先自行用其它软件,将 Basic YUV 转为 CCIR601 YUV,
再送给 ProCoder 压缩,色彩才会正确。

Avisynth, AviUtl 都有这个转换的功能。
==

也就是说如果要给 ProCoder 压缩,DVD2AVI 一定要选 TV Scale 输出,m2v 一定要选 Full Range 输出,如果是使用其它不能选择输出模式的 MPEG Decoder,只好用 AviUtl/Avisynth 的 filter 做后制处理。

 

 

OK,基本的讲完了 ^^;
接下来进阶讨论(我的手好酸 ><)...

1. 以上讲的是讯源都是 RGB,压 MPEG 时要做 RGB -> YUV,如果讯源是 YUV,则如何设定?

当讯源已经是 YUV 时,就不用去管 YC 伸张压缩的设定。
例如用 MainConcept MPEG Encoder 压 DV-AVI,用 Canopus DV Codec 解码,MainConcept MPEG Encoder RGB -> YUV 一律做 YC 压缩,照理说颜色会变淡。但是由于 MainConcept MPEG Encoder 可以接收 YUY2 输入,所以 Canopus DV Codec 会直接输出 16~235 YUY2 给 MainConcept MPEG Encoder,这样一来,就跳过了 RGB -> YUV 的步骤,当然也就没有 YC 压缩的问题,所以也就不会出现颜色不正确的情况。

然而如果是 TMPGEnc,以及有用到 VFAPI,因为 VFAPI 都要转成 RGB 处理,所以仍需注意 YC 伸张压缩的设定。
例如如果用 TMPGEnc 压 DV-AVI,一样用 Canopus DV Codec 解码,用默认值转换式,输出的是 16~235 RGB,所以便要勾 "Output YUV data as Basic YCbCr ont CCIR601"。

2. 解码时做 YC 伸张的优缺点?
a. 优点
1) 所见即所得,屏幕上见到的样子,就是将来压好 MPEG 解码输出的样子,这样做后制处理时,比较容易调整。

2) 大部分 MPEG Encoder 都是认为会接收 0~255 RGB 的输入,所以 RGB -> YUV 时都会作 YC 压缩,因此讯源在作解码时一定要作 YC 伸张,才会正确。

b. 缺点
1) 0~255,8 bits 的范围全用光了,没有留下运算时需要的 headroom。

2) Source (16~235 YUV) -> 0~255 RGB -> MPEG (16~235 YUV)
YC 伸张后再压缩,会有一点损失

YC 伸张计算式
Y' = (Y - 16) * 255 / (235 - 16)
C' = C * 255 / (255 - (240-16))

CCE SP 的说明书中,解释 16-235 和 0-255 选项的作用时,有列直接转换,和 YC 压缩转换所使用的不同的计算式
"16-235" --> YC 压缩转换
Rd = 219*R + 16*256
Gd = 219*G + 16*256
Bd = 219*B + 16*256
Y = 77*Rd + 150*Gd + 29*Bd / 2^16
CR = (( 131*Rd - 110*Gd - 21*Bd ) / 2^16 ) +128
CB = (( -44*Rd - 87*Gd + 131*Bd ) / 2^16 ) +128

"0-255" --> 直接转换
Y = 77*Rd + 150*Gd + 29*Bd / 2^8
CR = (( 131*Rd - 110*Gd - 21*Bd ) / 2^8 ) +128
CB = (( -44*Rd - 87*Gd + 131*Bd ) / 2^8 ) +128

如上列所见,这个转换式有小数点,需要舍弃进位,所以反复多次 YC 压缩伸张 RGB <-> YUV 变换,画质会有一点损失。

0 0