这里有篇文章讲解如何进行Huffman编码的JPEG Huffman Coding Tutorial,写的还是很清晰,我本来打算翻译一下这篇文章,但是想想觉得还是配合它的思路以不同的角度再写一篇,它是解码方式,我这里是以编码方式来描述,它的Y:Cb:Cr是1:1:1,我这里是4:1:1,当然它是英文的,我是中文的 @@。
JPEG/Huffman编码基础知识不了解的还是要先学习下基础知识,可以参考JPEG学习笔记,否则你可能无法看懂这里在说什么。
简单回顾下JPEG编码过程,这里我们假设RGB->JPEG:
色彩空间转换
正向离散余弦变换
量化(需要量化表)
Huffman编码(需要Huffman编码表)
生成图片流(按照JFIF格式)
其它的我们都不说了,直接开始吧,如果你现在觉得上面的概念/原理还不是很理解,还来的急,请跳转到文章顶部从头开始读。
有些中间数据的推理是通过JPEGsnoop或者手工进行的,所以你也要熟悉。
假设我们有RGB数据,这里我用的是test.bmp,一张16×8的的白黑位图(左DU白,右DU黑),可以用16进制工具打开来查看,实际数据就是:
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
假设我们有SOF数据
8位数据样本(1字节)
图像高度为8(2字节)
图像宽度为16(2字节)
颜色分量数,JPEG都是YCrCb,即3(1字节)
颜色分量信息,大小是颜色分量数 multiply 3
因为分量信息中颜色分量ID占用1个字节,水平/垂直因子占用1个字节(高4位水平,低4位垂直),量化表占用1个字节
H 2:1:1
V 2:1:1
所以总体采样因子就是(2 * 2):(1 * 1):(1 * 1),即4:1:1
MCU宽是水平采样因子最大值 multiply 8(记该最大值为Hmax)
MCU高是垂直采样因子最大值 multiply 8(记该最大值为Vmax)
因此这里就是(Hmax * 8):(Vmax * 8) = 16:16
如果整幅图片的高度或者宽度不是MCU的整数倍,就需要padding,解码之后丢弃大于宽度或者高度部分的数据
在数据流当中,MCU是按从左到右,从上到下来排列的。
因为每个MCU由若干数据单元组成,而数据单元又必须是8:8的,所以MCU当中数据单元的个数就是4(Hmax * Vmax)
组装起来可能就如下:
FF C0 00 11 08 00 08 00 10 03 01 22 00 02 11 01 03 11 01
DHT(FF C4)如下(这里的Huffman编码表是标准的,没有优化过的)
FF C4 00 1F 00 00 01 05 01 01 01 01 01 01 00 00 00 00 00 00 00 00 01 02 03 04 05 06 07 08 09 0A 0B FF C4 00 B5 10 00 02 01 03 03 02 04 03 05 05 04 04 00 00 01 7D 01 02 03 00 04 11 05 12 21 31 41 06 13 51 61 07 22 71 14 32 81 91 A1 08 23 42 B1 C1 15 52 D1 F0 24 33 62 72 82 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FF C4 00 1F 01 00 03 01 01 01 01 01 01 01 01 01 00 00 00 00 00 00 01 02 03 04 05 06 07 08 09 0A 0B FF C4 00 B5 11 00 02 01 02 04 04 03 04 07 05 04 04 00 01 02 77 00 01 02 03 11 04 05 21 31 06 12 41 51 07 61 71 13 22 32 81 08 14 42 91 A1 B1 C1 09 23 33 52 F0 15 62 72 D1 0A 16 24 34 E1 25 F1 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 F4 F5 F6 F7 F8 F9 FA
重构Huffman编码表(这样才比较好理解,编码表如何构建出来,参考[JPEG学习笔记],这里只列出需要用到的,部分有省略),4张表分别为直流0(直流Y),交流0(交流Y),直流1(直流C),交流1(交流C)
*** Marker: DHT (Define Huffman Table) (xFFC4) *** OFFSET: 0x000000B1 Huffman table length = 31 ---- Destination ID = 0 Class = 0 (DC / Lossless Table) Codes of length 01 bits (000 total): Codes of length 02 bits (001 total): 00 Codes of length 03 bits (005 total): 01 02 03 04 05 Codes of length 04 bits (001 total): 06 Codes of length 05 bits (001 total): 07 Codes of length 06 bits (001 total): 08 Codes of length 07 bits (001 total): 09 Codes of length 08 bits (001 total): 0A Codes of length 09 bits (001 total): 0B Codes of length 10 bits (000 total): Codes of length 11 bits (000 total): Codes of length 12 bits (000 total): Codes of length 13 bits (000 total): Codes of length 14 bits (000 total): Codes of length 15 bits (000 total): Codes of length 16 bits (000 total): Total number of codes: 012 Length Codeword Code 2 00 00(End of Block) 3 010 01 3 011 02 3 100 03 3 101 04 3 110 05 4 1110 06 5 1111 0 07 6 1111 10 08 7 1111 110 09 8 1111 1110 0A 9 1111 1111 0 0B *** Marker: DHT (Define Huffman Table) (xFFC4) *** OFFSET: 0x000000D2 Huffman table length = 181 ---- Destination ID = 0 Class = 1 (AC Table) Codes of length 01 bits (000 total): Codes of length 02 bits (002 total): 01 02 Codes of length 03 bits (001 total): 03 Codes of length 04 bits (003 total): 00 04 11 Codes of length 05 bits (003 total): 05 12 21 Codes of length 06 bits (002 total): 31 41 Codes of length 07 bits (004 total): 06 13 51 61 Codes of length 08 bits (003 total): 07 22 71 Codes of length 09 bits (005 total): 14 32 81 91 A1 Codes of length 10 bits (005 total): 08 23 42 B1 C1 Codes of length 11 bits (004 total): 15 52 D1 F0 Codes of length 12 bits (004 total): 24 33 62 72 Codes of length 13 bits (000 total): Codes of length 14 bits (000 total): Codes of length 15 bits (001 total): 82 Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA Total number of codes: 162 Length Codeword Code 2 00 01 2 01 02 3 100 03 4 1010 00(End of Block) 4 1011 04 4 1100 11 5 1101 0 05 5 1101 1 12 5 1110 0 21 6 1110 10 31 6 1110 11 41 7 1111 000 06 7 1111 001 13 7 1111 010 51 7 1111 011 61 ...... *** Marker: DHT (Define Huffman Table) (xFFC4) *** OFFSET: 0x00000189 Huffman table length = 31 ---- Destination ID = 1 Class = 0 (DC / Lossless Table) Codes of length 01 bits (000 total): Codes of length 02 bits (003 total): 00 01 02 Codes of length 03 bits (001 total): 03 Codes of length 04 bits (001 total): 04 Codes of length 05 bits (001 total): 05 Codes of length 06 bits (001 total): 06 Codes of length 07 bits (001 total): 07 Codes of length 08 bits (001 total): 08 Codes of length 09 bits (001 total): 09 Codes of length 10 bits (001 total): 0A Codes of length 11 bits (001 total): 0B Codes of length 12 bits (000 total): Codes of length 13 bits (000 total): Codes of length 14 bits (000 total): Codes of length 15 bits (000 total): Codes of length 16 bits (000 total): Total number of codes: 012 Length Codeword Code 2 00 00(End of Block) 2 01 01 2 10 02 3 110 03 4 1110 04 5 1111 0 05 6 1111 10 06 7 1111 110 07 8 1111 1110 08 9 1111 1111 0 09 10 1111 1111 10 0A 11 1111 1111 110 0B *** Marker: DHT (Define Huffman Table) (xFFC4) *** OFFSET: 0x000001AA Huffman table length = 181 ---- Destination ID = 1 Class = 1 (AC Table) Codes of length 01 bits (000 total): Codes of length 02 bits (002 total): 00 01 Codes of length 03 bits (001 total): 02 Codes of length 04 bits (002 total): 03 11 Codes of length 05 bits (004 total): 04 05 21 31 Codes of length 06 bits (004 total): 06 12 41 51 Codes of length 07 bits (003 total): 07 61 71 Codes of length 08 bits (004 total): 13 22 32 81 Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 Codes of length 10 bits (005 total): 09 23 33 52 F0 Codes of length 11 bits (004 total): 15 62 72 D1 Codes of length 12 bits (004 total): 0A 16 24 34 Codes of length 13 bits (000 total): Codes of length 14 bits (001 total): E1 Codes of length 15 bits (002 total): 25 F1 Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 F4 F5 F6 F7 F8 F9 FA Total number of codes: 162 Length Codeword Code 2 00 00(End of Block) 2 01 01 3 100 02 4 1010 03 4 1011 11 5 1100 0 04 5 1100 1 05 5 1101 0 21 5 1101 1 31 6 1110 00 06 6 1110 01 12 6 1110 10 41 6 1110 11 51 ......
DQT(FF DB)如下
FF DB 00 43 00 05 03 04 04 04 03 05 04 04 04 05 05 05 06 07 0C 08 07 07 07 07 0F 0B 0B 09 0C 11 0F 12 12 11 0F 11 11 13 16 1C 17 13 14 1A 15 11 11 18 21 18 1A 1D 1D 1F 1F 1F 13 17 22 24 22 1E 24 1C 1E 1F 1E
FF DB 00 43 01 05 05 05 07 06 07 0E 08 08 0E 1E 14 11 14 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E
0x0043为所占大小
1个字节为QT信息,高4位为QT精度(在这里精度数据都是0),低4位为QT号
64字节的QT数据
还原成矩阵形式(Zigzag)
QT 0
5 3 3 5 7 12 15 18 4 4 4 6 8 17 18 17 4 4 5 7 12 17 21 17 4 5 7 9 15 16 24 19 5 7 11 17 20 33 31 23 7 11 17 19 24 31 34 28 15 19 23 26 31 36 36 30 22 28 29 29 34 30 31 30
QT 1
略
前提条件都有了,开始做变换了。
通过SOF数据我们知道有1个MCU,Y有4个DU(2个是真实的数据,2个是填充),Cb有一个DU,Cr有一个DU。
RGB
略
DU 1(Y)
255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
DU 1(-128)
127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127
DU 1(FDCT)
1016 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 0 0 0 0 0 0 0 0 0 0 0 0 0
DU 1(Quantization)
203 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 0 0 0 0 0 0 0 0 0 0 0 0 0
DU 2(Y)
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 0 0 0 0 0 0 0 0 0 0 0 0 0 0
DU 2(-128)
-128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 -128
DU 2(FDCT)
-1024 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 0 0 0 0 0 0 0 0 0 0 0 0 0
DU 2(Quantization)
-205 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 0 0 0 0 0 0 0 0 0 0 0 0 0
于是得到
DC分别为203和-205(绝对),转换为相对则是203和-408
AC都为0
其它为0或者填充数据暂时就不用管了。
现在进行Huffman编码
203 = 1100 1011(查表或者计算都可以得出,最高位为1表示正数,最高位为0表示负数,取反得出其值),继而DC编码前缀为1111 10(根据Y的DC表可以得出,数据占8位)
-408 = 0011 0011 1
则
1111 10 1100 1011 // 直流Y 1111 10 1100 1011 1010 // 直流Y + 交流Y 1111 10 1100 1011 1010 1111 110 0011 0011 1 1010 // 直流Y + 交流Y + 直流Y + 交流Y 1111 10 1100 1011 1010 1111 110 0011 0011 1 1010 00 1010 00 1010 // 直流Y + 交流Y + 直流Y + 交流Y + 2个填充DU(因为MCU为4个DU) 1111 10 1100 1011 1010 1111 110 0011 0011 1 1010 00 1010 00 1010 00 00 // 直流Y + 交流Y + 直流Y + 交流Y + 2个填充DU(因为MCU为4个DU + 直流Cb + 交流Cb 1111 10 1100 1011 1010 1111 110 0011 0011 1 1010 00 1010 00 1010 00 00 00 00 // 直流Y + 交流Y + 直流Y + 交流Y + 2个填充DU(因为MCU为4个DU + 直流Cb + 交流Cb + 直流Cr + 交流Cr 1111 10 1100 1011 1010 1111 110 0011 0011 1 1010 00 1010 00 1010 00 00 00 00 111111 // 直流Y + 交流Y + 直流Y + 交流Y + 2个填充DU(因为MCU为4个DU + 直流Cb + 交流Cb + 直流Cr + 交流Cr + 填充位
去掉空格
1111101100101110101111110001100111101000101000101000000000111111
也就是说数据其实只有58位,补齐到字节对齐,共占64位,就得到了我们最终要的数据。
16进制表示
FB 2E BF 19 E8 A2 80 3F
这下你或许对这复杂的JPEG原理有所了解了吧,但是记住这才是开始(当然你无法全手工的为一张复杂的图片来编码,这篇文章只是帮助理解原理),JPEG正真复杂的是它对各种算法的优化,那才是重点。