分类: LINUX
2011-05-12 14:19:05
详细说明一下:
读入数据流并对照直流哈夫曼树,第一个哈夫曼编码为110,其权值为6,所以往后读入6位数据“1001101”,译码成数值为77。因为每个颜色分量单元只有一个直流分量,所以下一个就是第一个交流分量了。
继续读入数据流并对照交流哈夫曼树,得哈夫曼编码为01,其权值为1,所以它的前面没有零,并往后读如1位数据“1”,译码成数值为1。如此往复,最后读到哈夫曼编码“00”,其权值为0,所以满足交流变量结束条件(最后剩余的“01010”对本颜色分量单元来说是冗余的,它可能属于下一个颜色分量单元)。
实际上,这段数据译码为:
77,(0,1),(0,5),(0,-6),(0,-3),(5,1),(2,3)
因此,把它置于1个8*8的矩阵中应为:
77 | 1 | 5 | -6 | -3 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 0 | 3 | 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 | 0 | 0 | 0 | 0 |
4.直流系数的差分编码
把所有的颜色分量单元按颜色分量(Y、Cr、Cb)分类。每一种颜色分量内,相邻的两个颜色分量单元的直流变量是以差分来编码的。也就是说,通过步骤3解码出来的直流变量数值只是当前颜色分量单元的实际直流变量减去前一个颜色分量单元的实际直流变量。也就是说,当前直流变量要通过前一个颜色分量单元的实际(非解码)直流分量来校正:
DCn=DCn-1+Diff
其中Diff为差分校正变量,也就是直接解码出来的直流系数。但如果当前颜色分量单元是第一个单元,则解码出来的直流数值就是真正的直流变量。
再次提醒的是,3个颜色分量的直流变量是分开进行差分编码的。也就是说,为1张图片解码时应设置3个独立的直流校正变量。另一个问题是,当数据流中出现标记RSTn,则3个颜色分量的直流差分校正变量Diff都需要重新复位到0。
5.反量化
不同的颜色分量使用不同的量化表,这个可以从标记段SOF中的颜色分量信息字段查得。一般是Y分量使用量化表0,而Cr、Cb两个分量共同使用量化表1。
反量化的过程比较简单。只需要对8*8的颜色分量单元的64个值逐一乘以对应的量化表内位置相同的值则可。图像内全部的颜色分量单元都要进行反量化。
6.反Zig-zag编码
如果将反量化后的每个8*8颜色分量单元的每个元素编号,如下图4,那么各反Zig-zag编码的过程就是把矩阵元素按图5重新排列。
图 4 将颜色分量单元元素编码 图 5 反Zig-zag编码
关于量化和反Zig-zag编码的先后顺序,笔者查阅的几份资料有不同的见解。经过实践试验,解码的过程中,是应该直接用文件提供的量化表反量化矩阵数据,再将其反Zig-zag编码才能正确解码。
7.隔行的正负纠正
这个问题比较特别,因为在笔者认真阅读的几份资料中都没有提及此问题。而是笔者通过对已知图像进行JPEG编码压缩,然后和该图的JPEG文件数据对比发现的问题。具体原因不明。
实际上,就是必须对每个颜色分量单元的奇数行(每个颜色分量单元有8行,假设把它按0、1、……、6、7编出行号),即1、3、5、7行,进行取相反数操作(正的变负,负的变正)。
8.反离散余弦变换
之前提到,文件中的数据是在编码时通过正向离散余弦变换(FDCT)进行时空域向频率域变换而得到的结果,所以现在解码就必须将其反向离散余弦变换(IDCT),就是把颜色分量单元矩阵中的频率域数值向时空域转换。并且,原来的频率域的矩阵大小为8*8,则经过反向离散余弦变换后,时空域的矩阵仍然是8*8。
设正负纠正后的频率域矩阵为F[u][v],而反向离散余弦变换后的矩阵为f[i][j],其中0≤u,v,i,j≤7。具体使用的公式如下:
,其中
C(u)= (当u=0),C(u)=1(当u≠0);
C(v)= (当v=0),C(u)=1(当v≠0);
另外补充一下正向离散余弦变换的公式,用于编码:
9.YCrCb向RGB转换
要在屏幕上显示图像,就必须以RGB模式表示图像的颜色。所以,解码时需要把YCrCb模式向RGB模式转换。
正如前面提到,并不是每种颜色分量的采样因子都一样,所以转换时需要注意。如果采样因子是1:1:1,则每一个像素点的3个颜色分量都被采样,所以没有问题。但4:1:1的采样因子就不一样了。由“初步了解图像数据流的结构”一节中对4:1:1的采样因子的分析,可以知道一个MCU里有4个Y分量单元,而Cr分量和Cb分量各自只有1个分量单元。以图2为例,仅有的一个Cr分量单元(红色的64个采样点)应该平铺用于4个Y分量单元,即左上角16个值用于Y1,右上角16个值用于Y2,左下角16个值用于Y5,右下角16个值用于Y6。换句话说,一个Cr采样点服务于4个Y采样点。对于Cb分量,道理一样。
另外,由于离散余弦变化要求定义域的对称,所以在编码时把RGB的数值范围从[0,255]统一减去128偏移成[-128,127]。因此解码时必须为每个分量加上128。具体公式如下:
R=Y +1.402*Cb +128;
G=Y-0.34414*Cr -0.71414*Cb +128;
B=Y +1.772*Cb +128;
还有一个问题,通过变换得出的R、G、B值可能超出了其定义域,所以要作出检查。如果大于255,则截断为255;如果小于0,则截断为0。
下面补充RGB模式向YCrCb模式的公式:
Y =0.299*R +0.587*G +0.114*B ;
Cr= -0.1687*R - 0.3313*G +0.5*B +128;
Cb=0.5 *R - 0.4187*G - 0.0813*B+128;
至此,每个MCU的解码已经完成。而每一个MCU如何组成一幅完整的图像,请参考“初步了解图像数据流的结构”分析。