分类:
2008-12-01 17:05:14
视频简单地说就是活动的图像。保存和描述数字视频的简单方法就是记录和描述连续的一帧帧的静止图像。保存静止图像的最简单格式是BMP格式,就是位图。BMP是未经压缩的原始图像保存格式,采用RGB描述。数字视频流则采用YUV描述。所以播放视频时,要将YUV格式的数据转换成RGB格式显示。至于YUV与RGB如何相互装换,这里不详细介绍,网上有一大堆资料。
一、视频压缩
MPEG视频压缩编码后包括三种元素:
I帧(I-frames):帧内压缩编码形成的图像
P帧(P-frames):前向预测帧,以一个P 帧或 I 帧为预测帧进行编码
B帧(B-frames):从相邻(前后均可)的最近的I 帧或 P 帧作双向预测进行编码
在MPEG编码的过程中,部分视频帧序列压缩成为I帧;部分压缩成P帧;还有部分压缩成B帧。I帧法是帧内压缩法,也称为“关键帧”压缩法。I帧法是基于离散余弦变换DCT( Discrete Cosine Transform )的压缩技术,这种算法与JPEG压缩算法类似。JPEG压缩是一种针对静止的连续色调的图像压缩方法,它属于帖内压缩。采用I帧压缩可达到1/6的压缩比而无明显的压缩痕迹。
MPEG标准采用YCbCr(YUV)4::2:2的采样格式,其含义为:每个点保存一个 8bit 的亮度值(也就是Y值),每2个点保存一个 Cr(8bit) 和Cb(8bit) 值, 图像在肉眼中的感觉不会起太大的变化。其编码的基本方法是在单位时间内,首先采集并压缩第一帧的图像为I帧。然后对于其后的各帧,在对单帧图像进行有效压缩的基础上,只存储其相对于前后帧发生变化的部分。帧间压缩的过程中也常间隔采用帧内压缩法,由于帧内(关键帧)的压缩不基于前一帧,一般每隔15帧设一关键帧,这样可以减少相关前一帧压缩的误差积累。MPEG编码器首先要决定压缩当前帧为I帧或P帧或B帧,然后采用相应的算法对其进行压缩。一个视频序列经MPEG全编码压缩后可能的格式为:IBBPBBPBBPBBPBBIBBPBBP BBPBBPBBI......
下面说明I帧、P帧以及B帧的特点:
1.I帧:帧内编码帧
I帧特点:
①它是一个全帧压缩编码帧。它将全帧图像信息进行JPEG压缩编码及传输。
②解码时仅用I帧的数据就可重构完整图像。
③I帧描述了图像背景和运动主体的详情。
④I帧不需要参考其他画面而生成。
⑤I帧是P帧和B帧的参考帧(其质量直接影响到同组中以后各帧的质量)。
⑥I帧是帧组GOP的基础帧(第一帧),在一组中只有一个I帧。
⑦I帧不需要考虑运动矢量。
⑧I帧所占数据的信息量比较大。
2. P帧:前向预测编码帧。
(1)P帧的预测与重构:P帧是以I帧为参考帧,在I帧中找出P帧“某点”的预测值和运动矢量,取预测差值(对其进行类似JPEG压缩编码)和运动矢量(Huffman编码)一起传送。在接收端根据运动矢量从I帧中找出P帧“某点”的预测值并与差值相加以得到P帧“某点”样值,从而可得到完整的P帧。
(2)P帧特点
①P帧是I帧后面相隔1~2帧的编码帧。
②P帧采用运动补偿的方法传送它与前面的I或P帧的差值及运动矢量(预测误差)。
③解码时必须将I帧中的预测值与预测误差求和后才能重构完整的P帧图像。
④P帧属于前向预测的帧间编码。它只参考前面最靠近它的I帧或P帧。
⑤P帧可以是其后面P帧的参考帧,也可以是其前后的B帧的参考帧。
⑥由于P帧是参考帧,它可能造成解码错误的扩散。
⑦由于是差值传送,P帧的压缩比较高。
3.B帧:双向预测内插编码帧。
(1)B帧的预测与重构
B帧以前面的I或P帧和后面的P帧为参考帧,“找出”B帧“某点”的预测值和两个运动矢量,并取预测差值和运动矢量传送。接收端根据运动矢量在两个参考帧中“找出(算出)”预测值并与差值求和,得到B帧“某点”样值,从而可得到完整的B帧(不知如何算出)。
2)B帧特点
①B帧是由前面的I或P帧和后面的P帧来进行预测的。
②B帧传送的是它与前面的I或P帧和后面的P帧之间的预测误差及运动矢量。
③B帧是双向预测编码帧。
④B帧压缩比最高,因为它只反映丙参考帧间运动主体的变化情况,预测比较准确。
⑤B帧不是参考帧,不会造成解码错误的扩散。
注:I、B、P各帧是根据压缩算法的需要,是人为定义的,它们都是实实在在的物理帧,至于图像中的哪一帧是I帧,是随机的,一但确定了I帧,以后的各帧就严格按规定顺序排列。
二、视频编码
上图为视频压缩编码的简单流程。I帧编码对象是整个帧内数据,P、B帧编码的对象是预测差值和运动向量,对差值采用JPEG编码方式,对运动向量可以简单地用Huffman编码。P、B编码方式与I帧编码方式大同小异,下面以I帧编码为例详细说明之。
I帧采用的是JPEG编码方式,JPEG编码集合DPCM编码、RLE编码(行程编码)、熵编码(Huffman)等编码方式一体,所以JPEG有很高的压缩比。
JPEG编码的流程为:
8×8的图象经过DCT变换后,其低频分量都集中在左上角,高频分量分布在右下角(DCT变换实际上是空间域的低通滤波器)。由于该低频分量包含了图象的主要信息(如亮度),而高频与之相比,就不那么重要了,所以我们可以忽略高频分量,从而达到压缩的目的。如何将高频分量去掉,这就要用到量化,它是产生信息损失的根源。这里的量化操作,就是将某一个值除以量化表中对应的值。由于量化表左上角的值较小,右上角的值较大,这样就起到了保持低频分量,抑制高频分量的目的。JPEG使用的颜色是YUV格式。Y分量代表了亮度信息,UV分量代表了色差信息。相比而言,Y分量更重要一些。我们可以对Y采用细量化,对UV采用粗量化,可进一步提高压缩比。所以上面所说的量化表通常有两张,一张是针对Y的;一张是针对UV的。
上面讲了,经过DCT变换后,低频分量集中在左上角,其中F(0,0)(即第一行第一列元素)代表了直流(DC)系数,即8×8子块的平均值,要对它单独编码。由于两个相邻的8×8子块的DC系数相差很小,所以对它们采用差分编码DPCM,可以提高压缩比,也就是说对相邻的子块DC系数的差值进行编码。8×8的其它63个元素是交流(AC)系数,采用行程编码。这里出现一个问题:这63个系数应该按照怎么样的顺序排列?为了保证低频分量先出现,高频分量后出现,以增加行程中连续“0”的个数,这63个元素采用了“之”字型(Zig-Zag)的排列方法,如下图所示。
行程编码
上面,我们得到了DC码字和 AC行程码字。为了进一步提高压缩比,需要对其再进行熵编码,这里选用Huffman编码,分成两步:
(1)熵编码的中间格式表示
对于AC系数,有两个符号。符号1为行程和尺寸,即上面的(RunLength,Size)。(0,0)和(15,0)是两个比较特殊的情况。(0,0)表示块结束标志(EOB),(15,0)表示ZRL,当行程长度超过15时,用增加ZRL的个数来解决,所以最多有三个ZRL(3×16+15=63)。符号2为幅度值(Amplitude)。
对于DC系数,也有两个符号。符号1为尺寸(Size);符号2为幅度值(Amplitude)。
(2)熵编码
对于AC系数,符号1和符号2分别进行编码。零行程长度超过15个时,有一个符号(15,0),块结束时只有一个符号(0,0)。
对符号1进行Hufffman编码(亮度,色差的Huffman码表不同)。对符号2进行变长整数VLI编码。举例来说:Size=6时,Amplitude的范围是-63~-32,以及32~63,对绝对值相同,符号相反的码字之间为反码关系。所以AC系数为32的码字为100000,33的码字为100001,-32的码字为011111,-33的码字为011110。符号2的码字紧接于符号1的码字之后。
对于DC系数,Y和UV的Huffman码表也不同。
掉了这么半天的书包,你可能已经晕了,呵呵。举个例子来说明上述过程就容易明白了。
下面为8×8的亮度(Y)图象子块经过量化后的系数。
15 0 -1 0 0 0 0 0
-2 -1 0 0 0 0 0 0
-1 -1 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
可见量化后只有左上角的几个点(低频分量)不为零,这样采用行程编码就很有效。
第一步,熵编码的中间格式表示:先看DC系数。假设前一个8×8子块DC系数的量化值为12,则本块DC系数与它的差为3,根据下表
Size Amplitude
0 0
1 –1,1
2 –3,-2,2,3
3 –7~-4,4~7
4 –15~-8,8~15
5 –31~-16,16~31
6 –63~-32,32~63
7 –127~-64,64~127
8 –255~-128,128~255
9 –511~-256,256~511
10 –1023~512,512~1023
11 –2047~-1024,1024~2047
查表得Size=2,Amplitude=3,所以DC中间格式为(2)(3)。
下面对AC系数编码。经过Zig-Zag扫描后,遇到的第一个非零系数为-2,其中遇到零的个数为1(即RunLength),根据下面这张AC系数表:
Size Amplitude
1 –1,1
2 –3,-2,2,3
3 –7~-4,4~7
4 –15~-8,8~15
5 –31~-16,16~31
6 –63~-32,32~63
7 –127~-64,64~127
8 –255~-128,128~255
9 –511~-256,256~511
10 –1023~512,512~1023
查表得Size=2。所以RunLength=1,Size=2,Amplitude=3,所以AC中间格式为(1,2)(-2)。
其余的点类似,可以求得这个8×8子块熵编码的中间格式为
(DC)(2)(3),(1,2)(-2),(0,1)(-1),(0,1)(-1),(0,1)(-1),(2,1)(-1),(EOB)(0,0)
第二步,熵编码:
对于(2)(3):2查DC亮度Huffman表得到11,3经过VLI编码为011;
对于(1,2)(-2):(1,2)查AC亮度Huffman表得到11011,-2是2的反码,为01;
对于(0,1)(-1):(0,1)查AC亮度Huffman表得到00,-1是1的反码,为0;
……
最后,这一8×8子块亮度信息压缩后的数据流为11011, 1101101, 000, 000, 000, 111000,1010。总共31比特,其压缩比是64×8/31=16.5,大约每个象素用半个比特。