我的博客和笔记我的博客和笔记
首页
文章
  • TurboLink
  • TinyEncrypt
  • UnrealStyleGuide
  • AxTrace
  • Cyclone
  • 数学相关
  • 图形学
  • 密码学
  • 编程语言
关于
GitHub
首页
文章
  • TurboLink
  • TinyEncrypt
  • UnrealStyleGuide
  • AxTrace
  • Cyclone
  • 数学相关
  • 图形学
  • 密码学
  • 编程语言
关于
GitHub
  • 我的文章

    • 从抛币协议到智能合约

      • Part1
      • Part2
    • JPEG算法解密

      • Part1
      • Part2
      • Part3
      • Part4
        • 步骤五:哈弗曼编码
      • Part5
      • Github
    • SPH算法简介

      • Part1
      • Part2
      • Part3
      • Part4
      • Github
    • 赌博中的数学:Martingle策略
    • 如何生成一个随机的圆形
    • 一个简单的DH密钥协商算法的实现
    • 如何计算线段和圆的交点
    • 一道数学趣题
    • 斐波那契数列和1/89
    • 匀速贝塞尔曲线运动的实现

      • Part1
      • Part2
  • 开源项目

    • TurboLink
    • TinyEncrypt
    • UnrealStyleGuide
    • AxTrace
    • Cyclone
  • 学习笔记

    • 数学相关

      • 常用数学符号
      • 群
      • 数论(一)
      • 数论(二)
      • 数论(三)
      • 概率
    • 密码学

      • RSA
      • 抛币协议
      • 智能扑克协议
    • 图形学

      • 数学基础

        • 矢量
        • 矩阵
        • 立体角
        • 几何变换(一)
        • 几何变换(二)
        • 法线变换
        • 摄像机变换
      • 光照模型

        • 传统光照模型
        • 光度学
        • 双向反射分布函数(BRDF)
        • 微平面理论(一)
        • 微平面理论(二)
        • 微平面理论(三)
        • 光照方程
      • 环境光渲染

        • 环境光渲染(一)
        • 环境光渲染(二)
    • 编程语言

      • JavaScript

        • 环境搭建
        • 基本语法
        • 函数
        • 对象和类

JPEG算法解密(四)

步骤五:哈弗曼编码


JPEG压缩的最后一步是对数据进行哈弗曼编码(Huffman coding),哈弗曼几乎是所有压缩算法的基础,它的基本原理是根据数据中元素的使用频率,调整元素的编码长度,以得到更高的压缩比。
举个例子,比如下面这段数据

AABCBABBCDBBDDBAABDBBDABBBBDDEDBD

这段数据里面包含了33个字符,每种字符出现的次数统计如下

字符ABCDE
次数615291
如果我们用我们常见的定长编码,每个字符都是3个bit。
字符ABCDE
编码001010011100101

那么这段文字共需要3*33=99个bit来保存,但如果我们根据字符出现的概率来编码,也就是出现频率较高的字符,使用较短的编码,如下:

字符ABCDE
编码11001110101111

那么这段文字共需要3*6+1*15+4*2+2*9+4*1=63个bit来保存,压缩比为63%,哈弗曼编码一般都是使用二叉树来生成的,这样得到的编码符合前缀规则,也就是较短的编码不能够是较长编码的前缀,比如字符'B'使用的编码是'0',那么其他字符的编码的第一个字符都不能是‘0’。
上面这个编码实例,就是由下面的这颗二叉树生成的。

我们回到JPEG压缩上,回顾上一节的内容,经过数据量化,我们现在要处理的数据是一串一维数组,举例如下:

①原始数据
在实际的压缩过程中,数据中的0出现的概率非常高,所以首先要做的事情,是使用RLE编码对其中的0进行处理,把数据中的非零的数据,以及数据前面0的个数作为一个处理单元。
①原始数据
②RLE编码3570,0,0,-6-20,0,-90,0,…,0,80,0,…,0
如果其中某个单元的0的个数超过16,则需要分成每16个一组,如果最后一个单元全都是0,则使用特殊字符“EOB”表示,EOB意思就是“后面的数据全都是0”,
①原始数据
②RLE编码3570,0,0,-6-20,0,-90,0,…,0,80,0,…,0
3570,0,0,-6-20,0,-90,0,…,00,0,80,0,…,0
(0,35)(0,7)(3,-6)(0,-2)(2,-9)(15,0)(2,8)EOB
其中(15,0)表示15+1也就是16个0,接下来我们要处理的是括号里右面的数字,这个数字的取值范围在-2047~2047之间,JPEG提供了一张标准的码表用于对这些数字编码:
ValueSizeBits
00–
-11101
-3,-22,3200,0110,11
-7,-6,-5,-44,5,6,73000,001,010,011100,101,110,111
-15,…,-88,…,1540000,…,01111000,…,1111
-31,…,-1616,…,3150 0000,…,0 11111 0000,…,1 1111
-63,…,-3232,…,63600 0000,……,11 1111
-127,…,-6464,…,1277000 0000,……,111 1111
-255,…,-128128,…,25580000 0000,……,1111 1111
-511,…,-256256,…,51190 0000 0000,……,1 1111 1111
-1023,…,-512512,…,10231000 0000 0000,……,11 1111 1111
-2047,…,-10241024,…,204711000 0000 0000,……,111 1111 1111
举例来说,第一个单元中的“35”这个数字,在表中的位置是长度为6的那组,所对应的bit码是“100011”,而“-6”的编码是”001″,由于这种编码附带长度信息,所以我们的数据变成了如下的格式。
①原始数据
②RLE编码3570,0,0,-6-20,0,-90,0,…,0,80,0,…,0
3570,0,0,-6-20,0,-90,0,…,00,0,80,0,…,0
(0,35)(0,7)(3,-6)(0,-2)(2,-9)(15,0)(2,8)EOB
③BIT编码(0,6, 100011)(0,3, 111)(3,3, 001)(0,2, 01)(2,4, 0110)(15,-)(2,4, 1000)EOB
括号中前两个数字分都在0~15之间,所以这两个数可以合并成一个byte,高四位是前面0的个数,后四位是后面数字的位数。
①原始数据
②RLE编码3570,0,0,-6-20,0,-90,0,…,0,80,0,…,0
3570,0,0,-6-20,0,-90,0,…,00,0,80,0,…,0
(0,35)(0,7)(3,-6)(0,-2)(2,-9)(15,0)(2,8)EOB
③BIT编码(0,6, 100011)(0,3, 111)(3,3, 001)(0,2, 01)(2,4, 0110)(15,-)(2,4, 1000)EOB
(0x6,100011)(0x3,111)(0x33,001)(0x2,01)(0x24,0110)(0xF0,-)(0x24,1000)EOB
对于括号前面的数字的编码,就要使用到我们提到的哈弗曼编码了,比如下面这张表,就是一张针对数据中的第一个单元,也就是直流(DC)部分的哈弗曼表,由于直流部分没有前置的0,所以取值范围在0~15之间。
LengthValueBits
3 bits 04
05
03
02
06
01
00 (EOB)
000
001
010
011
100
101
110
4 bits 071110
5 bits 081111 0
6 bits 091111 10
7 bits 0A1111 110
8 bits 0B1111 1110
举例来说,示例中的DC部分的数据是0x06,对应的二进制编码是“100”,而对于后面的交流部分,取值范围在0~255之间,所以对应的哈弗曼表会更大一些
LengthValueBits
2 bits 01
02
00
01
3 bits 03100
4 bits 00 (EOB)
04
11
1010
1011
1100
5 bits 05
12
21
1101 0
1101 1
1110 0
6 bits 31
41
1110 10
1110 11
………
12 bits 24
33
62
72
1111 1111 0100
1111 1111 0101
1111 1111 0110
1111 1111 0111
15 bits821111 1111 1000 000
16 bits 09
…
FA
1111 1111 1000 0010
…
1111 1111 1111 1110
这样经过哈弗曼编码,并且序列化后,最终数据成为如下形式
①原始数据
②RLE编码3570,0,0,-6-20,0,-90,0,…,0,80,0,…,0
3570,0,0,-6-20,0,-90,0,…,00,0,80,0,…,0
(0,35)(0,7)(3,-6)(0,-2)(2,-9)(15,0)(2,8)EOB
③BIT编码(0,6, 100011)(0,3, 111)(3,3, 001)(0,2, 01)(2,4, 0110)(15,-)(2,4, 1000)EOB
(0x6,100011)(0x3,111)(0x33,001)(0x2,01)(0x24,0110)0xF0(0x24,1000)EOB
④哈弗曼编码1001000111001111111 1111 010100101011111 1111 010001101111 1111 0011111 1111 010010001010
⑤序列化
Prev
Part3
Next
Part5