JPEG中Huffman解码实例讲解
DHT Huffuman表格式
--------------------------------------------------------------------------
名稱 ? ? ?字節數 ? ? 值 ? ? ? 說明
--------------------------------------------------------------------------
段標識 ? ? ? 1? ? ? ? FF
段類型 ? ? ? 1? ? ? ? C4
段長度 ? ? ? 2? ? ? ? ? ? ? ? ? ? 其值=19+n(當只有一個HT表時)
(以下為段內容)
HT信息 ? ? ?1? ? ? ? ? ? ? ? ? ? 0-3位:HT號
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?4位: HT類型, 0=DC表,1=AC表
? ? ? ? 5-7位:必須=0
HT位表? ? ? 16? ? ? ? ? ? ? ? ? 這16個數的和應該≤256
HT值表? ? ? ?n? ? ? ? ? ? ? ? ? ?n=表頭16個數的和
--------------------------------------------------------------------------
讀取Huffman表
FF C4 01?A2 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:Huffman表識別碼
01?A2:DHT表長度(01~0B的字節數)
00:4bit=0,為DC表;低3bit=0,HT號為0;表示DC直流0號表
00 01 05 01 01 01 01 01 01 00 00 00 00 00 00 00:DHT不同bits位數的碼字數量,數據之和表示葉子節點數目:1+5+1+1+1+1+1+1 = 12;
00 01 02 03 04 05 06 07 08 09 0A 0B:編碼內容,即每個葉子節點下的編碼值
構建Huffman樹
讀取到Huffman表的數據之后,就需要構建Huffman樹了。其具體規則如下:
? (a)第一個編碼的數字必定為0;如果第一個編碼的位數為1,就被編碼為0;如果第一個編碼的位數為2,就被編碼為00;如果第一個編碼的位數為3,就被編碼為000。。。
? (b)從第二個編碼開始,如果它和它前面編碼具有相同的位數,則當前編碼是它前面的編碼加1;如果它的編碼位數比它前面的編碼位數大,則當前編碼時它前面的編碼加1之后再在后面添加若干個0,直到滿足編碼位數的長度為止。
還是以上面的數據00 01 05 01 01 01 01 01 01 00 00 00 00 00 00 00為例:
第1個字節00表示沒有位數為1的編碼;
第2個字節01表示位數為2的編碼有2個;由于沒有位數為1的編碼,因此這里位數為2的編碼中的第一個為00;
第3個字節05表示位數為3的編碼有5個;因此,這里位數為3的編碼中的第一個為00+1=01,然后添加1個“0”,得到010;位數為3的編碼中的第二個為010+1=011;第三個為011+1=100;第四個為100+1=101;第五個為101+1=110;
第4個字節01表示位數為4的編碼有1個;因此,這里位數為4的編碼中的第一個為110+1=111,然后添加1個“0”,得到1110;
第5個字節01表示位數為5的編碼有1個;因此,這里位數為5的編碼中的第一個為1110+1=1111,然后添加1個“0”,得到11110;
依次類推,得到如下Huffman樹,表1:
| Y(luminance亮度)-DC ? | ||||||||||||||||
| 序號(bits位數) | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
| 相同Bits位的個數 | 0 | 1 | 5 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 說明 | 沒有位數為1的編碼 | 1個2bits | 5個3bits | 1個4bits | 1個5bits | 1個6bits | 1個7bits | 1個8bits | 1個9bits | 沒有位數為10的編碼 | 沒有位數為11的編碼 | 沒有位數為12的編碼 | 沒有位數為13的編碼 | 沒有位數為14的編碼 | 沒有位數為15的編碼 | 沒有位數為16的編碼 |
| 碼字(二進制) | 無 | 00 | (00+1)<<1 ==> 010 011 100 101 110 | (110+1)<<1 ==> 1110 | (1110+1)<<1 ==> 1111 0 | (11110+1)<<1 ==> 1111 10 | (111110+1)<<1 ==> 1111 110 | (1111110+1)<<1 ==> 1111 1110 | (11111110+1)<<1 ==> 1111 1111 0 | 無 | 無 | 無 | 無 | 無 | 無 | 無 |
根據Huffman樹,建立DHT權值與實際保存數據與DCT量化后數據 表2,查此表可以對jpeg做解碼:
| 序號 | Bits位數 | 碼字長度 | 碼字 | DHT權值 | Size(數值bits寬度) | Additionnal Bits (實際保存的數據) | DC-value(DCT量化后的數據) | |||
| 1 | 2bits | 2 | 00 | 0x0 | 0x00 | 0 | 0 | |||
| 2 | 3bits | 3 | 010 | 0x2 | 0x01 | 1 | 0 | 1 | -1 | 1 |
| 3 | 3 | 011 | 0x3 | 0x02 | 2 | 00,01 | 10,11 | -3,-2 | 2,3 | |
| 4 | 3 | 100 | 0x4 | 0x03 | 3 | 000,001,010,011 | 100,101,110,111 | -7,-6,-5,-4 | 4,5,6,7 | |
| 5 | 3 | 101 | 0x5 | 0x04 | 4 | 0000,…,0111 | 1000,…,1111 | -15,…,-8 | 8,…,15 | |
| 6 | 3 | 110 | 0x6 | 0x05 | 5 | 0000 0,…,01111 | 1000 0,…,11111 | -31,…,-16 | 16,…,31 | |
| 7 | 4bits | 4 | 1110 | 0xE | 0x06 | 6 | 0000 00,…,011111 | 1000 00,…,111111 | -64,…,-32 | 32,…,64 |
| 8 | 5bits | 5 | 1111 0 | 0x1E | 0x07 | 7 | 0000 000,… | …,1111 111 | -127,…,-64 | 64,…,127 |
| 9 | 6bits | 6 | 1111 10 | 0x3E | 0x08 | 8 | 0000 0000,… | …,1111 1111 | -255,…,-128 | 128,…,255 |
| A | 7bits | 7 | 1111 110 | 0x7E | 0x09 | 9 | 0000 0000 0,… | …,1111 1111 1 | -511,…,-256 | 256,…,511 |
| B | 8bits | 8 | 1111 1111 | 0xFE | 0x0A | A | 0000 0000 00,… | …,1111 1111 11 | -1023,…,-512 | 512,…,1023 |
| C | 9bits | 9 | 1111 1111 0 | 0x1FE | 0x0B | B | 0000 0000 000,… | …,1111 1111 111 | -2047,…,-1024 | 1024,…,2047 |
| 高4bits:保留零的個數 低4bits:接著的數據位長 | 0n | 負數 | 正數 | -(1<<(n+1)-1) ~ -(1<<n) | (1<<n) ~ (1<<(n+1)-1) | |||||
| DHT權值表中,高4bit表示零保留的個數,低4bit表示接著的數據位長。 | ||||||||||
| Huffman:DC實際值?->?Size[編碼長度] ->?權值 ->?bitstring{.Len;?? .value;} Encode: DC實際值?->?DQT量化?->?ZigZag掃描?->(Y:DPCM編碼,CbCr)->? huffman ->?write | ||||||||||
?
根據Huffman系數,或者讀取Huffman系數,重建Huffman表:
static BYTE std_dc_luminance_nrcodes[17]={0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0};
static BYTE std_dc_luminance_values[12]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
static BYTE std_dc_chrominance_nrcodes[17]={0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0};
static BYTE std_dc_chrominance_values[12]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
static BYTE std_ac_luminance_nrcodes[17]={0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d };
static BYTE std_ac_luminance_values[162]=
? { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa };
static BYTE std_ac_chrominance_nrcodes[17]={0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77};
static BYTE std_ac_chrominance_values[162]=
{ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa };
依照上述重建Huffman表的方法,可得:
| DHT-Y-DC | DHT-Y-AC | DHT-CbCr-DC | DHT-CbCr-AC | |||||||||
| 序號 | 相同Bits位數的:碼字個數 | 相同bits位數:碼字起始 | 相同bits位數:碼字結束 | 相同Bits位數的:碼字個數 | 相同bits位數:碼字起始 | 相同bits位數:碼字結束 | 相同Bits位數的:碼字個數 | 相同bits位數:碼字起始 | 相同bits位數:碼字結束 | 相同Bits位數的:碼字個數 | 相同bits位數:碼字起始 | 相同bits位數:碼字結束 |
| 1? | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 1 | 0 | 0 | 2 | 0 | 0x1 | 3 | 0 | 0x2 | 2 | 0 | 0x1 |
| 3 | 5 | 0x2 | 0x6 | 1 | 0x4 | 0x4 | 1 | 0x6 | 0x6 | 1 | 0x4 | 0x4 |
| 4 | 1 | 0xE | 0xE | 3 | 0xA | 0xC | 1 | 0xE | 0xE | 2 | 0xA | 0xB |
| 5 | 1 | 0x1E | 0x1E | 3 | 0x1A | 0x1C | 1 | 0x1E | 0x1E | 4 | 0x18 | 0x1B |
| 6 | 1 | 0x3E | 0x3E | 2 | 0x3A | 0x3B | 1 | 0x3E | 0x3E | 4 | 0x38 | 0x3B |
| 7 | 1 | 0x7E | 0x7E | 4 | 0x78 | 0x7B | 1 | 0x7E | 0x7E | 3 | 0x78 | 0x7A |
| 8 | 1 | 0xFE | 0xFE | 3 | 0xF8 | 0xFA | 1 | 0xFE | 0xFE | 4 | 0xF6 | 0xF9 |
| 9 | 1 | 0x1FE | 0x1FE | 5 | 0x1F6 | 0x1FA | 1 | 0x1FE | 0x1FE | 7 | 0x1F4 | 0x1FA |
| 10 | 0 | 0 | 0 | 5 | 0x3F6 | 0x3FA | 1 | 0x3FE | 0x3FE | 5 | 0x3F6 | 0x3FA |
| 11 | 0 | 0 | 0 | 4 | 0x7F6 | 0x7F9 | 1 | 0x7FE | 0x7FE | 4 | 0x7F6 | 0x7F9 |
| 12 | 0 | 0 | 0 | 4 | 0xFF4 | 0xFF7 | 0 | 0 | 0 | 4 | 0xFF4 | 0xFF7 |
| 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 14 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0x3FE0 | ?0x3FE0 |
| 15 | 0 | 0 | 0 | 1 | 0x7FC0 | 0x7FC0 | 0 | 0 | 0 | 2 | 0x7FC2 | 0x7FC3 |
1)??????? 將待解碼數據轉換成二進制的數據流;
2)??????? 遍歷表Huffman_size、Huffman_code,從待解碼二進制數據流中尋找到長度與Huffman_size相等,內容與Huffman_code相等的二進制數據段,并記錄下表的ID(即:是在表的第幾個數據中尋找到的);
3)??????? 將此ID 值除以16,其商為cnt(指之前有cnt個0),其余數即為取數長度Len;
4)??????? 在二進制的數據流中,從與Huffman_code相同的數據流后,開始取數,取數長度為第3步得到的Len,假設取得的數據為data;
5)??????? 根據data的值,轉換得到相應的解碼數據de_data。(根據最高位,為1則為相應的數,為0則取反后的負值。例,data=100,則解碼后數據de_data值為4;data=010,解碼后數據de_data為-5;
6)??????? 寫上de_data的值,并在前面添加上cnt個0。至此,解碼完成。
示例數據講解:
?長度01 A2后面的字節: 00 表示Y-DC, tablenum=0; 10表示Y-AC, tablenum=1;01表示Cb-DC,tablenum=2;11表示Cb-AC,tablenum=3;
后面的數據依次是bits位數的個數表,bits位數表(碼表);
根據這個重建Huffman表,得到size與code表;
DHT后面是SOS數據,實際的數據流從E2 E8 A2 8A F9 93 F7 開始
Huffman解碼時,每次讀取32bit數據,此次前4字節數據為E2 E8 A2 8A,轉換城二進制數據為:
1110 0010 1110 1000 1010 0010 10000 1010
首次編碼的數據一定是Y-DC,所以這里可跟表2匹配:匹配二進制數據的長度與Huffman_size相等,內容與Huffman_code相等的二進制數據段,記錄下Huffman的ID號,此時匹配上的1110, 碼字長度為4,對應的DHT權值為6,即后面需要讀取6 bits數據(001011)作為該組數據,對應的實際DCT量化后的數據值為-53。【(001011對應10進制數據為11) 故數據為:11- (1<<6)? ==> -53 】,此次計算共用的bit位數為4+6 = 10,所以下一組數據從偏移10bits開始,依次類推,可得出下如下數據:
1110 0010 11? ? 101 0001? ? 010 0? ? ?010 1? ? ?0000 1010
| 二進制數據 | 1110 0010 11? | 101 0001 | 010 0 | 010 1 | 00 | 00 | 1010 后面讀byte數據,補足32bit,再做Huffman解碼,如: 1010 (F9)(93) (F7) | ... |
| 實際數值 | -53 | -14 | -1 | 1 | 0 | 0 | ... | |
| 說明 | 4bits碼字,6bits數據 | 3bits碼字,4bits數據 | 3bits碼字,1bits數據 | 3bits碼字,1bits數據 | 2bits數據 | ... |
當數據長度不夠時,可從后面讀取byte的數據以填充,以補足32 bits數據做Huffman解碼。?
?Y-AC,Cb-DC,Cb-AC也依次類推得到相應的數據值。
總結
以上是生活随笔為你收集整理的JPEG中Huffman解码实例讲解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: webpack的source-map的详
- 下一篇: Facebook三大愿景和五大核心价值