根据前面学习到的jpeg解码知识,编写jpeg解码code,此处采用实际的解码过程对jpeg进行讲解
如图1,为实际的jpg图像数据,根据JPEG格式,解析出对应的标识符与对应的数据信息。
FF D8:SOI 文件头
FF E0:APP0 图像信息识别
FF DB:DQT 量化表
FF C0:SOF0 帧开始
FF C4:DHT Huffman表
FF DA:SOS 扫描行开始
encode数据
FF D9:SOI 文件尾
扫描文件头,得到有效的DQT量化表信息,如图1:
SOF识别图像基本信息,如图2:
图像分辨率:1920*1080,解码4:1:1图像,y分量是Cb、Cr的4倍;
MCU大小为8*8,4:1:1模式下,1920/(8*2)=120,1080/(2*8)=67.5,此时需要补偿整数个MCU,所以实际宽为68*16=1088,共有120行,68列个MCU。
所以,实际处理的图像大小为1920*1088,120*68个MCU,每个MCU大小是8*8,Y分量按照2*2个MCU解码。
DHT Huffman表信息,并根据 JPEG中Huffman解码实例讲解 ,重建Huffman树,得到Huffman的code与size表, 如图3,00 -> Y-DC,tablenum=0:
图4,10 -> Y-AC,tablenum=1:
图5,01 -> CbCr-DC,tablenum=2:
图6,11 -> CbCr-AC,tablenum=3:
SOS之后,3byte数据省略(用作他途),后续即可读取有效的32bit数据,解码如下:
获取32bit数据:0xe2e8a28a --> 1110 0010 1110 1000 1010 0010 1000 1010
Huffman查表得到DHT码字:0x06,高4bit表示零保留位数,低4bit表示数据位长,即取接下来6bit数据;
取得6bit数据:0010 11 ==>0xb
计算实际的数据值:(0xb+1)-(1<<6) = -52,累计使用的bit数量为10 bit
DC数据经过DPCM编码。即当前DC值减去前一个DC值的结果,MCU首个DC值必为0,所以DC值为得出的数据+DC数据,此时DC量化后的实际值为-52;(AC数据不需要做DPCM编码)
量化:用像素值÷量化表对应值所得的结果
所以,逆量化数据值=DQT*(-52),此时得到-416;
对逆量化数据做反Zig-Zag,得到-416;
反Zig-Zag表:
0 | 1 | 8 | 16 | 9 | 2 | 3 | 10 |
17 | 24 | 32 | 25 | 18 | 11 | 4 | 5 |
12 | 19 | 26 | 33 | 40 | 48 | 41 | 34 |
27 | 20 | 13 | 6 | 7 | 14 | 21 | 28 |
35 | 42 | 49 | 56 | 57 | 50 | 43 | 36 |
29 | 22 | 15 | 23 | 30 | 37 | 44 | 51 |
58 | 59 | 52 | 45 | 38 | 31 | 39 | 46 |
53 | 60 | 61 | 54 | 47 | 55 | 62 |
原图像是分割为8*8的MCU块单独编码,所以解码也是按照一个MCU来解码。
当一个MCU解码时:
1. DC分量遇到数据位长为0时,数据也为0;
2. AC分量遇到EOB结束符号时,结束该MCU解码:零保留个数为0,数据位长也为0时;
3. AC分量遇到ZRL码时,是为15个零数据:零保留个数为0xF,数据位长为0时;
最终解码出来的MCU的DCT数据为:
将DCT数据做反DCT变化,得到实际的YUV像素数据:
将YUV数据转换为RGB格式,保存为可视bmp格式。
R = (u8_t)(Y+ 1.4075*(Cr - 128));
G = (u8_t)(Y-0.7169*(Cr - 128)-0.3455*(Cb - 128));
B = (u8_t)(Y+1.779*(Cb- 128));