JPEG解碼——(4)霍夫曼解碼


本篇是該系列的第四篇,承接前篇的文件頭解析,主要介紹霍夫曼解碼相關內容。

承接上篇,文件頭解析完畢后,就進入了編碼數據區域,即SOS的tag后的區域,也是圖片數據量的大頭所在。

1. 待處理的數據區域

  一個例子來說明,仍使用那張animal_park.jpg的圖片。

  其二進制數據顯示如下(FFDA所代表的SOS之后深色標注區域):

  截取到的二進制數據為:F9 96 8B FA 71 EA 5B 24 B5 ...

2. 解碼過程規則描述

a)從此顏色分量單元數據流的起點開始一位一位的讀入,直到讀入的編碼與該分量直流哈夫曼樹的某個碼字(葉子結點)一致,然后用直流哈夫曼樹

      查得該碼字對應的權值。權值(共8位)表示該直流分量數值的二進制位數,也就是接下來需要讀入的位數。

b)繼續讀入位數據,直到讀入的編碼與該分量交流哈夫曼樹的某個碼字(葉子結點)一致,然后用交流哈夫曼樹查得該碼字對應的權值。權值的高4位

      表示當前數值前面有多少個連續的零,低4 位表示該交流分量數值的二進制位數,也就是接下來需要讀入的位數。

c)不斷重復步驟b,直到滿足交流分量數據結束的條件。

      而結束條件有兩個,只要滿足其中一個即可:

  ①當讀入碼字的權值為零,表示往后的交流變量全部為零;

  ②已經讀入63個交流分量。

3. 准備工作——霍夫曼表

  在解析文件頭時,會得到四張霍夫曼表——DC0,AC0, DC1,AC1,待后面解碼時使用。

  DC0——Y分量的直流部分

  AC0——Y分量的交流部分(表太長,沒列全)

 

   DC1——UV分量的直流部分

  AC1——UV分量的交流部分

4. 解碼步驟

  這是難點所在,解碼的過程其實就是霍夫曼樹的查找過程。mcu單元內部使用了RLE行程編碼和霍夫曼編碼來壓縮數據。

  此時,正需要一個例子來實戰說明,因為理論是對實踐的抽象。

  例子:F9 96 8B FA 71 EA 5B 24 B5。。。

  對應的二進制位展開:1111 1001, 1001 0110, 1000 1011, 1111 1010, 0111 0001, 1110 1010, 0101 1011, 0010 0100, 1011 0101。。。

step1. 先讀入若干位與DC0表的Code進行匹配。

          讀取2位的11時,  無匹配的Code,因為2位寬的Code只有0b00和0b01

                 3位的111        無                              3                           0b100,0b101和0b110。

                 4位的1111      無                              4                            0b1110。

                 5位的11111    無                              5                            0b11110。

                 6位的111110  有                              6                            0b111110,恰好匹配!其對應的CodeVal為0x7

step2. 利用上面得到的CodeVal進行拆分,並讀取后面若干位。
  0x7=0x07,高四位為0,低四位為7,則再讀取后面的7位二進制,為:01, 1001 0。
  后面讀取的值,這樣算:如果開頭為1則為正數,如果開頭為0,則為負數,然后對各位求反得到數值,即可。

  01, 1001 0這個值,由於開頭為0,則為負數,多少呢?取反得到:10, 01101 = 0x4D = 77,最后得到最終值為:-77。

step3. 通過上面兩步驟的第一次掃描,得到的為Y分量的DC值,后面還需經過63次掃描得到剩余的AC值(一般掃描幾次就結束了)。

  上面DC值標記為-77。

step4. 繼續通過類似step1和step2來取得AC值,注意要查找AC0表。

  讀取5位的110, 10時,有匹配的Code:0b11010=0x1a,其對應的CodeVal=0x04;
  取得后四位的值——4,表示還需讀取的二進制位數量,來表示真正的信源值——0b0010,經(step2中描述)變換后值為-13;
  那么可以RLE標記為(0,-13),其中0來自於CodeVal的高4位,-13為另讀入的數據值。可也記為key-val對。

step5. 重復step4的操作,直到得到(0,0)(位置為5B那個字節的最高四位)。

   后面的依次為:

  Code                                CodeVal          RLE_val         RLE

 11, 1111 1010(0x3FA)         0x34            0111(-8)          (3, -8)

 00                                        0x1              0 (-1)              (0, -1)

 1, 1110 10(0x7A)                 0x71            1(1)                 (7, 1)

 0, 0                                      0x1              1(1)                 (0, 1)

 01                                        0x0                --                   (0, 0)  -> 結束於5B的高4位

  為更直觀的介紹解析結果,將二進制位數據進行划分,表示如下:

  未標記的hex表示:           F9               96               8B              FA              71              EA              5B              24             B5。。。

  未標記的binary表示:1111 1001, 1001 0110, 1000 1011, 1111 1010, 0111 0001, 1110 1010, 0101 1011, 0010 0100, 1011 0101。。。

  標記后的binary表示:1111 1001, 1001 0110, 1000 1011, 1111 1010, 0111 0001, 1110 1010, 0101 1011, 0010 0100, 1011 0101。。。

  紅色表示為查表得到的Code,藍色表示RLE_val(其二進制位長度為CodecVal后四位值)。

step6. 通過step1-step5的掃描,得到RLE表:-77, (0, -13), (3, -8),(0, -1),(7, 1), (0, 1), (0, 0)

step7. step1到step6結束后,表示一個mcu的霍夫曼解碼結束,則可以進行8x8的矩陣展開。

  RLE中的(m,n),m表示前面填充0的個數,n表示實際值。

  根據RLE表,其霍夫曼解碼結果如下:

 5. 一些思考總結

  由此huffman decode后得到的表,可以看出其巨大優勢,僅僅使用了6Bytes+4bits就表示了8*8=64Bytes的數據量,體現了用時間換空間的

特點,即增加更多計算工作,來減少數據存儲空間。

  同時,還需要注意以下幾點:

  a). 接下來根據Y分量采樣因子來確定后續是Y分量的表還是UV分量的表。

   如果Y/U/V采樣因子都為1x1,則接下來依次得到U和V分量的表,再后面繼續為Y分量的表;

   如果Y分量采樣因子為2x2,即最常見的YUV420格式(每2x2個像素點,進行2x2個Y分量采樣,以及1x1個U和V分量采樣),則當前的已得到

的表為Y00,后續的表為Y01,Y10和Y11,然后才能是U分量的表和V分量的表。

  因為采樣是按照block為原子單位展開,如下圖所示(黑色點表示一個block):

  

     這里需要補充幾個名詞:

    block——8x8的像素采樣表。

    MCU——根據采樣因子確定的一個完整編碼單元。

    針對YUV420的2x2的Y分量采樣率,其關系如下圖:

  

   而如果是1x1的采樣率,則一個MCU內只包含一個Y分量的block,一個U分量的block和一個V分量的block,圖示就不畫了。

   例如,該圖片因為2x2的采樣率,則一個MCU的大小位16x16,其包括四個Y分量的block,一個U分量的block和一個V分量的block。

  b). 由於DPCM(diff pcm)編碼原因,第N個Y分量的DC值保存的是與前面一個的差值。取得第N個值時,掃描出的值再加上前一個值(跨MCU時仍成立)。
   接下來的1011, 0010 0100, 1011 0101用於確定Y01的表,根據同樣的規則,查表分割如下:

    1011, 0010 0100, 1011 0101

   得到RLE序列為:9, (0, 1), (0, 1), (0, 0)

   經DPCM修正為:9+(-77)=-68, (0, 1), (0, 1), (0, 0)

   如下為重建該block后的表:

    

  c). 由於編碼時某些場景會插入某些字節,因此掃描時要跳過某些字節。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM