Opus从入门到精通(八)Opus编码基础之压缩编码

3,418 阅读16分钟

只有在保持信号质量的前提下,设法降低码率及数据量,才能使标准得到应用。而这种降低码率的过程,被称为压缩编码或新源编码. 这节介绍一些基础的压缩编码思想与方法,为后面Opus语音编码做基础准备. 压缩编码又可以分为无损压缩,有损压损,混合压缩 无损压缩编码有:

  1. 莫尔斯
  2. 哈夫曼
  3. 游程编码RLC
  4. 算术编码
  5. 香农-费诺编码
  6. Lempel-Zir编码

视频编码比语音编码描述更直观,本文以视频编码示例讲解主要的压缩编码原理.

1.莫尔斯码

莫尔斯码就是大家熟悉的电报码,它的发明为人类做出了巨大的贡献.该码采用"."和"-"来表示26个英文字母,这实质上还是二进制码(点为"0",而杠为"1"),但是它没有采用固定字长的编码方式,而是采用了常用字母用短码表示(如E用"."表示,T用"-"表示),不常用字母用长码表示(如Z用"--.."表示,j用"-..-"表示)的变长编码方式.通过对英文单词进行大量统计,找出各字母的概率,最后确定有12个字母出现概率最低,用4bit数字表示,有8个字母出现概率较低,用3bit数字表示;有4个字母出现概率较高,用2bit数字表示;有两个字母出现概率最高,用1bit表示,共26个字母.

  • 其中出现概率最低的12个字母共需12*4bit = 48bit
  • 其中出现概率较低的8个字母共需8*3bit = 24bit
  • 其中出现概率较高的4个字母共需4*2bit = 8bit
  • 其中出现概率最高的两个字母共需2*1bit = 2bit

这样可以算出26个字母中每个字母的平均码长为: (48+24+8+2)/26 = 3.15位/字母

而要用固定码长方式则需要2的五次方=32,即5bit来表示.显然平均码长减低了近2/5,达到了压缩的目的,而这种压缩对于信息无任何损坏,属于无损压缩.

由此看来改变吗的规律是:先找出统计规律,然后对出现概率打的用短码,反之用长码,从而使码率降低. 其实我们后面的文字编码标准也采用了这种思想,像UTF-8中数字占1个字节、英文字母占1个字节,常用中文字符占用3个字节(大约2万多字),但超大字符集中的更大多数汉字要占4个字节(在unicode编码体系中,U+20000开始有5万多汉字)。

再附上一张莫尔斯编码表吧!

莫尔斯编码表

2.预测编码

2.1 差值编码

根据莫尔斯码编码规律的两个重要原则,先对视频图像信号的空间相关性(帧内相关性)进行统计分析. 原始图像数据在空间上存在着很大的冗余度,存在大量无频传送的多余信息,即空间相关性很强,可以把一帧图像看成是由像块,轮廓,细节3部分构成的.像块是指图像中成片相同像素组成的块,这种信号的频率小于2MHz,它的空间相关性最强.轮廓指的是像块间的分界,这种信号的频率大约在2MHz~3.5MHz左右,它的相关性较差.而细节则是图像中相关性最小,变化最频繁的细节描述,其信号频率大约在3.5MHz以上.通过大量的统计表明:像块要占用图像中绝大部分约90%以上,而轮廓和细节只占较少的部分,不到10%,换句话说,在视频信号中国低频部分占绝大多数,而高频部分则所占比例较小.

另一方面,视频信号不仅具有空间相关性,它还具有在时间轴上,以场帧和帧频为扫描周期的时空形结构,因此它还应觉有时间相关性,也就是帧间相关性.特别是对应那些静止的画面,其帧间相同位置的样值则100%相同.而那些非静止的画面中,相邻帧不同的部分也只是运动物体,只占较小的比例.

根据以上分析,可以设想,在对视频信号的数字化过程中,发送端处理货传输的不同图像中当前样值本身,而是该样值与前一个(相邻)样值的差值,则这些差值绝大部分是很小的或者为零,可以用短码来表示,而对那些出现概率较低的较大差值,用长码来表示,则可是总体码数下降.这种采用对相邻样值差值进行变长编码方式成为差值编码,又称为差分脉冲调制(DPCM).在接收端,将已得到的前一样值与刚收到的差值相加,就可还原出所要的当前样值.

从另一个角度看,可以把前一个样值看成是当前样值的的预测值,并与当前样值相减,得到一个差值(预测错误).该差值可以看成是当前要传送的样值对于预测值的修正值,并对该差值编码,传送,这样在接收端,可以将已得到的前一个样值加上这一解码后的修正值,就得到了一个正确的当前样值.因此差值编码也可以称为预测编码

差值编码原理图
从图中可以看出,在信号的发送端,当前样值Vi(n)一路直接送入减法器,而另一路则送入延时线TS(预测器),其延迟时间定为一个采样周期,此时,从TS输出的出二样值的差值(预测误差),该预测误差应为: ΔVi(n)=Vi(n)-Vi(n-1) 经过量化器Q量化后,ΔVi'(n)为ΔVi(n)+ε(n).其中ε(n)为量化误差或称量化噪声. 在信号接收端,差值信号(预测误差)ΔVi(n)+ε(n)经过逆量化器Q(-1)的D/A变换后,把该信号(包括ε(n))送入加法器,并经过延时线TS延迟一个采样周期的前一个输出样值(预测值)Vo(n-1)相加,从而又得到当前样值Vo(n). 从以上过程可以看出,发送端输出的是当前样值与前一样值的差值,而接收端将该项预测误差与前一输出样值相加,又还原为当前样值,因此差值编码是可以实现图像信号的压缩,传输与还原的.

2.2预测编码

预测编码是数字视频信号信源编码的主要方式之一.它也称为查分脉冲编码调制(DPCM).前面介绍的差值编码,只是预测编码中的一维预测,即只用同一行中当前样值的前一样值当做当前样值的预测值,这样的预测器可以对水平和表面给出非常好的效果,但对于垂直方向的效果并不理想.因此人们采用了二维或三维的预测方法.

3.霍夫曼(Huffman)编码

在前面的讲述中,是根据图像的相关性以及大量统计,找出了图像像素样值的预测规律.这为去除相关性,进行差值传输,提供了依据,打下了基础,然而这只是信源编码中的一个方面,另一个方面则是对差值信息(预测误差)进行熵编码(Entropy Coding),而不是普通意义上的数值编码.

熵编码是一类无损编码,它是因为编码后的平均码长接近信源的熵而得名.在熵编码中,一般多采用可变字长编码方式.其基本思想是对信源中出现概率大的对象用短码表示,而出现概率较小的对象用长码表示,从而统计上获得较短的平均码长.其中所指对象并没有规定是某种模拟或数字信息,它只是一个欲编码的对象或符号.熵编码要求所编的码应是即时可译码,短码不应与长码的码首重复,各码之间无需附加信息便可自然分开.

与莫尔斯码类似,霍夫曼码也属于熵编码.它是在数字视频中应用的一类可变长编码.其编码的具体方法是:

  1. 首先将欲编码的信源对象(在预测编码中应是量化后的预测误差),按出现的概率由大到小排成一列
  2. 找出最小的两个概率点,大的用码元"1"表示,小的用码元"0"表示(如概率相等,可自行确认"0"和"1"分配方式
  3. 再将这两个概率点的概率相加,生成一新的概率点,随后在新的概率点和余下的概率点中选出两个最小的概率点比较,大着为"1",小者为"0".
  4. 再将这两个概率点的概率相加,生成一个新的概率点,
  5. 以此类推,直至新的概率点的概率为1为止.
  6. 最后沿着由对象符号到概率为1的路劲,将该路径上的"1"和"0"记录下来,便得到了各信源对象的霍夫曼编码.

下图是7个信源"对象x1~x7的霍夫曼编码图:

霍夫曼编码
上图示出了霍夫曼编码过程,如果采用固定码长的编码方式,此例中7个对象需3位码长,而采用了霍夫曼编码后,其平均码长为:

L = \sum_{N=1}^7 P(X_N)L(X_N) = 2.57(bit/pel)

上式中P(XN)wei XN的出现概率,L(XN)为XN的码长.可见比固定码长编码时的3bit要短,压缩了码位

在实际应用中,往往是将霍夫曼编码以查找表的形式,预先将对象与码值一一对应的存储在只读存储器(ROM)中.编码时,以对象为地址读出相应的霍夫曼编码;解码时,以霍夫曼为地址读出相应的对象,从而满足了即时编译的要求.

霍夫曼编码实际上是一种映射码,其与被编码对象的物理参数无关,是根据"对象"出现的概率而编制的.一旦编成,则霍夫曼码与对象是一一对应的,而与概率无关.

4.变换编码

在多媒体数字视频信源编码中,变换编码是实现图像数据压缩的主要手段之一.变换编码值的是正交变换编码,它将空间域的视频图像信号变换到由正交矢量定义的变换域中,以便去除其空间相关性,并对变换域中的系数采用适当的量化和编码方法,已达到数据压缩的目的.离散余弦变化(DCT),就是正交变换中的一种.他是把图像从空间域变换到频率域的一种变换形式.其目的在于找出图像在频域中的相关规律及特点,以便从频域的角度去除图像的相关性,达到图像压缩的目的.

4.1 离散余弦变换

在前面介绍了图像在空间域中的一种压缩算法,即预测编码.它是巧妙的利用了视频图像在空间域中具有较强的相关性这一特点设计的.然而人们发现,对于那些十分复杂的图像而言,空间相关性并不十分明显.因此预测编码就显得有些力不从心.经过进一步研究人们认识到,图像的相关性不仅表现在空间域中,它在其他域中,如频率域中也表现了很强的相关性.

DCT是英文Discrete Consine Transform的缩略语,意思是离散余弦变化,它是一种傅里叶变化,任何连续的实对称函数,采用傅里叶变换后,就只含余弦项.本片我们不讨论离散讨论傅里叶变化的数学证明等(具体可以参考:傅里叶分析之掐死教程(完整版)更新于2014.06.06,是描述离散余弦变换在压缩编码中步骤.

视频图像的DCT变换,是对每个单独的彩色图像分量进行的,先把整个分量图像分成许多88=64个样点组成的像块.并对其采样,然后再对这88=64个样值逐一进行FDCT(正向DCT)变换,将视频图像信号由空间域变换到频率域.如下图

8*8像素空间域

8*8 DCT系数频率域

图中f(x,y)表示空间位置(x,y)点的样值函数(x,y=0,1,2....7),F(u,v)为频率域中对应于频率位置(u,v)点的DCT系数(u,v=0,1,2...7),沿u,v方向频率增加.在空间域中88的样值矩阵,经FDCT变换后,成为了频率域中88FDCT系数矩阵.图中F(u,v)的频域图中的右下角对应高频部分,而在左上角对应低频部分,其中F(0,0)对应直流分量,成为DC系数.其他63个对应交流分量的系数成为AC系数.

由于视频数字化采用8bit量化,即最大幅值对应256级(量化级).所以F(0,0)的变化范围为256的64/8倍,即可能取值为0~2047之间,而交流系数的变化范围应为-1024-1023.在F(u,v)系数矩阵中,低频系数的值大,而高频系数的值小,下表为一组实际的,变换前后的8*8样值矩阵和DCT系数矩阵.

0 1 2 3 4 5 6 7
150 170 132 185 147 190 215 220
165 185 130 190 175 195 223 199
155 163 180 220 202 173 197 170
143 154 160 170 211 185 190 166
130 140 172 190 193 150 180 140
135 164 198 180 177 141 172 135
170 190 163 140 165 132 160 140
160 200 145 135 170 199 190 129
0 1 2 3 4 5 6 7
136.2340 -48.8294 -39.2458 9.8608 -22.6310 11.6491 -63.7071 -5.3816
62.2669 -77.2554 16.1615 -12.8225 35.0540 23.9713 -5.6764 -41.6991
7.5839 -7.4069 75.5760 26.7426 -26.4953 -12.8395 -10.5650 -43.5935
18.6219 18.1673 23.2682 -26.0828 17.7958 21.6025 10.0939 6.4744
-9.2768 10.0678 12.2530 -9.9202 10.1096 -12.9974 10.0253 10.5422
10.7947 2.3326 -29.5610 -20.2712 -7.3535 12.1952 9.6559 0.2945
10.7947 2.3326 -29.5610 -29.2712 -7.3535 12.1952 9.6559 0.2945
-8.3913 12.2379 -8.4750 -6.5153 15.8826 13.3316 -2.1819 2.2038

DCT变换是在信号发送端所做的一种图像信息压缩的前期操作,在接收端则可以通过逆变换(IDCT),将频率域中的DCT系数矩阵变换为空间域中的图像样值矩阵,使图像得以还原.

4.2 DTC系数量化

从上表可以看出矩阵f中各值的相关性较差,而经过DCT变换后的F矩阵中的各DCT系数间的相关性已经显现出来了,即左上角的系数值大,而右下角的系数值小,为数据压缩创造了必要条件.但是这种相关性还不是十分明显,要最终实现数据压缩,还需要进一步降低非"0"系数的幅值,以及增加"0"值系数的数目,从而进一步提高F矩阵的相关性.为此还要对变换后的DCT系数进行量化,也就是按照某种要求将F矩阵中的各系数值按不同的比例减少,显然量化是图片质量下降的最主要原因.

对DCT系数的量化是基于限失真(Finite Distortion)编码理论进行的.它允许DCT系数经量化后,对图像造成一定的失真,但这种失真应在人的视觉所能接收的容限之内.

根据FDCT系数矩阵的不同区域,分配不同的量化步长的量化方法,称为区域滤波法.

4.3 Zig-Zag扫描

量化后的DCT系数仍然是二维系数矩阵,要进行数据传输,还需要将其变为一维数据序列.Zig-Zag扫描采用的是Z字形扫描方式.这主要是因为,在量化后的DCT系数矩阵中,非0的数据主要集中于矩阵的左上角.从直流分量DC开始进行Z字形扫描,可以增加连续0系数的个数,也就是增加0的游程长度.这样对传输中的数据压缩十分有利.

4.4 游程编码(RLC)

量化后的DCT系数矩阵,经过Zig-Zag扫描后变变为了以为数组序列,然后这一数组序列的尾部都是连续的0数据,这些连续0数据的个数称为游程.为了避免在数据传输中,逐个第传送0数据,进一步实现数据压缩,需要对这一维数组进行游程编码. 游程编码的方法是将扫描得到的一维数组序列,转换为一个由二元数组(num,level)组成的数组序列,其中num表示连续0的长度,level表示这串连续0之后出现的一个非零值,后面所有剩余的连续0,用符号EOB来表示.

4.5 熵编码

在编码中不是根据被编码数据的数值大小进行编码,而是根据被编码数据在所有数据中出现的概率来编码.概率大的用短码,反之用长码,从而进一步提高熵值,降低传输信息的平均码长.霍夫曼编码就是一种在视频数据压缩中,被广泛采用的熵编码.

在变换编码中,经过游程编码后的字符对数组序列,并不直接作为用于传输的数据,还要对其进行霍夫曼编码,以进一步提高数据压缩率.在发送端,将根据每一字符对出现的概率进行霍夫曼编码,并形成一个码表(霍夫曼码表)存储在编码器的ROM中,数据传输时,将严格按照码表,把每一个字符变换为霍夫曼码.在数据接收端,则必须采用同样的霍夫曼码表解码.