第4章无损数据压缩 冰水水冰本水冰水水水冰水水水本水冰本客*冰水水水水冰本水冰水水水水水水冰本冰客水冰水水水冰客水冰本水水水水水冰水水冰本水冰水水水水水水水*客 4.1仙农-范诺与赫夫曼编码 4.1.1仙农-范诺编码 4.1.2赫夫曼编码 4.2算术编码 4.3RLE编码 4.4词典编码 4.4.1词典编码的思想 4.4.2LZ77算法 4.4.3LZSS算法 4.4.4LZ78算法 4.4.5LZW算法 练习与思考题 参考文献和站点 水冰水水求水水水冰客水水水水水水水水本水水水水水水水客*客水水水水冰水水水水水水水客水水水水水冰水客水水水水水水冰*水水水水水水半水*水水冰水 数据压缩可分成两种类型,一种叫做无损压缩,另一种叫做有损压缩 无损压缩是指使用压缩后的数据进行重构(或者叫做还原,解压缩),重构后的数据与原 来的数据完全相同;无损压缩用于要求重构的信号与原始信号完全一致的场合。一个很常见 的例子是磁盘文件的压缩。根据目前的技术水平,无损压缩算法一般可以把普通文件的数据 压缩到原来的1/2~1/4。一些常用的无损压缩算法有赫夫曼( Huffman)算法和 LZW( Lengel-Ziv& Welch)压缩算法 有损压缩是指使用压缩后的数据进行重构,重构后的数据与原来的数据有所不同,但不 影响人对原始资料表达的信息造成误解。有损压缩适用于重构信号不一定非要和原始信号完 全相同的场合。例如,图像和声音的压缩就可以采用有损压缩,因为其中包含的数据往往多 于我们的视觉系统和听觉系统所能接收的信息,丢掉一些数据而不至于对声音或者图像所表 达的意思产生误解,但可大大提高压缩比。 本章主要介绍目前用得最多和技术最成熟的无损压缩编码技术,包括包含赫夫曼编码、 算术编码、RLE编码和词典编码。对于不打算开发压缩技术和编写压缩程序的读者可不必深 究编译码的详细过程。 4.1仙农-范诺与赫夫曼编码 4.1.1仙农-范诺编码 仙农-范诺编码算法需要用到下面两个基本概念: 1. Entropy(熵)的概念 (1)熵是信息量的度量方法,它表示某一事件出现的消息越多,事件发生的可能性就 越小,数学上就是概率越小 2)某个事件的信息量用J1=-bog2P1表示,其中P,为第i个事件的概率, p 2.信源S的熵的定义 按照仙农( Shannon)的理论,信源S熵定义为 H(s)=7=∑pbog2(l/P) 其中P是符号S在出现的概率;bog2(/p1)表示包含在S中的信息量,也就是编码s所 需要的位数。例如,一幅用256级灰度表示的图像,如果每一个像素点灰度的概率均为 P1=1/256,编码每一个像素点就需要8比特
第4章 无损数据压缩 *************************************************************************** 4.1 仙农-范诺与赫夫曼编码 4.1.1 仙农-范诺编码 4.1.2 赫夫曼编码 4.2 算术编码 4.3 RLE编码 4.4 词典编码 4.4.1 词典编码的思想 4.4.2 LZ77算法 4.4.3 LZSS算法 4.4.4 LZ78算法 4.4.5 LZW算法 练习与思考题 参考文献和站点 *************************************************************************** 数据压缩可分成两种类型,一种叫做无损压缩,另一种叫做有损压缩。 无损压缩是指使用压缩后的数据进行重构(或者叫做还原,解压缩),重构后的数据与原 来的数据完全相同;无损压缩用于要求重构的信号与原始信号完全一致的场合。一个很常见 的例子是磁盘文件的压缩。根据目前的技术水平,无损压缩算法一般可以把普通文件的数据 压缩到原来的 1/2 ~ 1/4 。一些常用的无损压缩算法有赫夫曼 (Huffman) 算法和 LZW(Lenpel-Ziv & Welch)压缩算法。 有损压缩是指使用压缩后的数据进行重构,重构后的数据与原来的数据有所不同,但不 影响人对原始资料表达的信息造成误解。有损压缩适用于重构信号不一定非要和原始信号完 全相同的场合。例如,图像和声音的压缩就可以采用有损压缩,因为其中包含的数据往往多 于我们的视觉系统和听觉系统所能接收的信息,丢掉一些数据而不至于对声音或者图像所表 达的意思产生误解,但可大大提高压缩比。 本章主要介绍目前用得最多和技术最成熟的无损压缩编码技术,包括包含赫夫曼编码、 算术编码、RLE编码和词典编码。对于不打算开发压缩技术和编写压缩程序的读者可不必深 究编译码的详细过程。 4.1 仙农-范诺与赫夫曼编码 4.1.1 仙农-范诺编码 仙农-范诺编码算法需要用到下面两个基本概念: 1. Entropy(熵)的概念 (1) 熵是信息量的度量方法,它表示某一事件出现的消息越多,事件发生的可能性就 越小,数学上就是概率越小。 (2) 某个事件的信息量用 i pi I 2 = −log 表示 , 其中 i p 为第 i 个事件的概率, 0 pi 1 2. 信源S的熵的定义 按照仙农(Shannon)的理论,信源S的熵定义为 ( ) log (1/ ) 2 i i H s = = pi p 其中 i p 是符号 i s 在S中出现的概率; log (1/ ) 2 pi 表示包含在 i s 中的信息量,也就是编码 i s 所 需要的位数。例如,一幅用256级灰度表示的图像,如果每一个像素点灰度的概率均为 pi =1/ 256 ,编码每一个像素点就需要8比特
第4章无损数据压缩 例4.1]有一幅40个像素组成的灰度图像,灰度共有5级,分别用符号 表示,40个像素中出现灰度A像素数有15个,出现灰度B的像素数有7个,出现灰度C的 数有7个等等,如表4-01所示。如果用3个比特表示5个等级的灰度值,也就是每个像素用3 比特表示,编码这幅图像总共需要120比特 表4-01符号在图像中出现的数目 号 ABCIDE 出现的次数|15|77[6|5 按照仙农理论,这幅图像的熵为 H(S)=(15/40)×bog2(40/15)+(7/40)×log2(40/7)+…+(5/40)×bog2(40/5) =2.196 这就是说每个符号用2.196比特表示,40个像素需用87.84比特。 最早阐述和实现这种编码的是 Shannon(1948年)和Fano(1949年),因此被称为仙农-范诺 ( Shannon-Fano)算法。这种方法采用从上到下的方法进行编码。首先按照符号出现的频度 或概率排序,例如,A,B,C,D和E,如表4-02所示。然后使用递归方法分成两个部 分,每一部分具有近似相同的次数,如图4-01所示。按照这种方法进行编码得到的总比特数 为91,实际的压缩比约为1.3:1。 表4-02 Shannon-Fano算法举例表 符号出现的次数(P2)pg2(/P)分配的代码需要的比特数 15(0.375) 1.4150 B7(0175)2.514 14 6(0.150) 110 5(0.125) 3.0000 111 图4-01仙农-范诺算法编码举例 4.1.2赫夫曼编码 赫夫曼( Huffman)在1952年提出了另一种编码方法,即从下到上的编码方法。现仍以一 个具体的例子说明它的编码步骤 (1)初始化,根据符号概率的大小按由大到小顺序对符号进行排序,如表4-03和图4-02 所示。 (2)把概率最小的两个符号组成一个节点,如图4-02中的D和E组成节点P1 (3)重复步骤2,得到节点P、B和P,形成一棵“树”,其中的理称为根节点。 4)从根节点理开始到相应于每个符号的“树叶”,从上到下标上“0”(上枝)或者“1” (下枝),至于哪个为“1”哪个为“0”则无关紧要,最后的结果仅仅是分配的代 码不同,而代码的平均长度是相同的
第4章 无损数据压缩 2 [例4.1] 有一幅40个像素组成的灰度图像,灰度共有5级,分别用符号A、B、C、D和E 表示,40个像素中出现灰度A的像素数有15个,出现灰度B的像素数有7个,出现灰度C的像素 数有7个等等,如表4-01所示。如果用3个比特表示5个等级的灰度值,也就是每个像素用3 比特表示,编码这幅图像总共需要120比特。 表4-01 符号在图像中出现的数目 符 号 A B C D E 出现的次数 15 7 7 6 5 按照仙农理论,这幅图像的熵为 H(S) = (15/40) 2 log (40/15) + (7/40) 2 log (40/7) + + (5/40) 2 log (40/5) =2.196 这就是说每个符号用2.196比特表示,40个像素需用87.84比特。 最早阐述和实现这种编码的是Shannon(1948年)和Fano(1949年),因此被称为仙农-范诺 (Shannon- Fano)算法。这种方法采用从上到下的方法进行编码。首先按照符号出现的频度 或概率排序,例如, A , B ,C , D 和 E ,如表4-02所示。然后使用递归方法分成两个部 分,每一部分具有近似相同的次数,如图4-01所示。按照这种方法进行编码得到的总比特数 为91,实际的压缩比约为1.3 : 1。 表4-02 Shannon-Fano算法举例表 符号 出现的次数( i p ) log (1/ ) 2 pi 分配的代码 需要的比特数 A 15 (0.375) 1.4150 00 30 B 7 (0.175) 2.5145 01 14 C 7 (0.175) 2.5145 10 14 D 6 (0.150) 2.7369 110 18 E 5 (0.125) 3.0000 111 15 图4-01 仙农-范诺算法编码举例 4.1.2 赫夫曼编码 赫夫曼(Huffman)在1952年提出了另一种编码方法,即从下到上的编码方法。现仍以一 个具体的例子说明它的编码步骤: (1) 初始化,根据符号概率的大小按由大到小顺序对符号进行排序,如表4-03和图4-02 所示。 (2) 把概率最小的两个符号组成一个节点,如图4-02中的D和E组成节点P1。 (3) 重复步骤2,得到节点P2、P3和P4,形成一棵“树”,其中的P4称为根节点。 (4) 从根节点P4开始到相应于每个符号的“树叶”,从上到下标上“0”(上枝)或者“1” (下枝),至于哪个为“1”哪个为“0”则无关紧要,最后的结果仅仅是分配的代 码不同,而代码的平均长度是相同的
第4章无损数据压缩 (5)从根节点P开始顺着树枝到每个叶子分别写出每个符号的代码,如表4-03所示。 (6)按照仙农理论,这幅图像的熵为 BS)=(15/39)×bg2(39/15)+(7/39)xkog2(39/7)+…+(5/39)x bog2(39/5)=2.1859 压缩比1.37:1 表4-03赫夫曼编码举例 符号出现的次数|1og2(1/p)分配的代码需要的位数 A15(0.3846 15 B7(0.1795)2.48 C6(0.1538) 2.70 101 D6(0.1538270 110 E5(0.1282) 2.96 111 A(0.3846) 0 B(0.1795) c015381P2 D(01538)-0 E(0.1282) PI 图4-02赫夫曼编码方法 赫夫曼码的码长虽然是可变的,但却不需要另外附加同步代码。例如,码串中的第1位 为0,那末肯定是符号A,因为表示其他符号的代码没有一个是以0开始的,因此下一位就表 示下一个符号代码的第1位。同样,如果出现“110”,那么它就代表符号D。如果事先编写 出一本解释各种代码意义的“词典”,即码簿,那么就可以根据码簿一个码一个码地依次进 行译码 采用赫夫曼编码时有两个问题值得注意:①赫夫曼码没有错误保护功能,在译码时,如 果码串中没有错误,那么就能一个接一个地正确译出代码。但如果码串中有错误,哪怕仅仅 是1位出现错误,不但这个码本身译错,更糟糕的是一错一大串,全乱了套,这种现象称为 错误传播( error propagation)。计算机对这种错误也无能为力,说不出错在哪里,更谈不 上去纠正它。②赫夫曼码是可变长度码,因此很难随意查找或调用压缩文件中间的内容,然 后再译码,这就需要在存储代码之前加以考虑。尽管如此,赫夫曼码还是得到广泛应用。 与仙农一范诺编码相比,这两种方法都自含同步码,在编码之后的码串中都不须要另外 加标记符号,即在译码时分割符号的特殊代码。此外,赫夫曼编码方法的编码效率比仙农 范诺编码效率高一些。请读者自行验证。 4.2算术编码 算术编码在图像数据压缩标准(如JPEG,JBIG)中扮演了重要的角色。在算术编码中,消 息用0到1之间的实数进行编码,算术编码用到两个基本的参数:符号的概率和它的编码间隔 信源符号的概率决定压缩编码的效率,也决定编码过程中信源符号的间隔,而这些间隔包含
第4章 无损数据压缩 3 (5) 从根节点P4开始顺着树枝到每个叶子分别写出每个符号的代码,如表4-03所示。 (6) 按照仙农理论,这幅图像的熵为 H(S) = (15/39) 2 log (39/15) + (7/39) 2 log (39/7) + + (5/39) 2 log (39/5) = 2.1859 压缩比1.37:1。 表4-03 赫夫曼编码举例 符号 出现的次数 log2(1/pi) 分配的代码 需要的位数 A 15(0.3846) 1.38 0 15 B 7(0.1795) 2.48 100 21 C 6(0.1538) 2.70 101 18 D 6(0.1538) 2.70 110 18 E 5(0.1282) 2.96 111 15 图4-02 赫夫曼编码方法 赫夫曼码的码长虽然是可变的,但却不需要另外附加同步代码。例如,码串中的第1位 为0,那末肯定是符号A,因为表示其他符号的代码没有一个是以0开始的,因此下一位就表 示下一个符号代码的第1位。同样,如果出现“110”,那么它就代表符号D。如果事先编写 出一本解释各种代码意义的“词典”,即码簿,那么就可以根据码簿一个码一个码地依次进 行译码。 采用赫夫曼编码时有两个问题值得注意:①赫夫曼码没有错误保护功能,在译码时,如 果码串中没有错误,那么就能一个接一个地正确译出代码。但如果码串中有错误,哪怕仅仅 是1位出现错误,不但这个码本身译错,更糟糕的是一错一大串,全乱了套,这种现象称为 错误传播(error propagation)。计算机对这种错误也无能为力,说不出错在哪里,更谈不 上去纠正它。②赫夫曼码是可变长度码,因此很难随意查找或调用压缩文件中间的内容,然 后再译码,这就需要在存储代码之前加以考虑。尽管如此,赫夫曼码还是得到广泛应用。 与仙农-范诺编码相比,这两种方法都自含同步码,在编码之后的码串中都不须要另外 添加标记符号,即在译码时分割符号的特殊代码。此外,赫夫曼编码方法的编码效率比仙农 -范诺编码效率高一些。请读者自行验证。 4.2 算术编码 算术编码在图像数据压缩标准(如JPEG,JBIG)中扮演了重要的角色。在算术编码中,消 息用0到1之间的实数进行编码,算术编码用到两个基本的参数:符号的概率和它的编码间隔。 信源符号的概率决定压缩编码的效率,也决定编码过程中信源符号的间隔,而这些间隔包含
第4章无损数据压缩 在0到1之间。编码过程中的间隔决定了符号压缩后的输出。算术编码器的编码过程可用下面 的例子加以解释 [例42]假设信源符号为(00,01,10,11},这些符号的概率分别为{0.1,0.4,0.2, 0.3},根据这些概率可把间隔[0,1)分成4个子间隔:[0,0.1),[0.1,0.5),[0.5,0.7) [0.7,1),其中[x,y)表示半开放间隔,即包含x不包含y。上面的信息可综合在表4-04中 表4-04信源符号,概率和初始编码间隔 11 0.1 0.2 0.3 例始编码间隔0,001,0.5)[05,07[07,1 如果二进制消息序列的输入为:10001100101101,编码时首先输入的符号是10, 找到它的编码范围是[0.5,0.7]。由于消息中第二个符号00的编码范围是[0,0.1),因此它 的间隔就取[0.5,0.7)的第一个十分之一作为新间隔[0.5,0.52)。依此类推,编码第3个符 号11时取新间隔为[0.514,0.52),编码第4个符号00时,取新间隔为[0.514,0.5146),… 消息的编码输出可以是最后一个间隔中的任意数。整个编码过程如图4-03所示 繃码间隔 信源107052052051460514205144051402 符号 输出 0.50.5140.5140.5143 5143840.5143876 输入10 图4-03算术编码过程举例 这个例子的编码和译码的全过程分别表示在表4-05和表4-06中。根据上面所举的例子, 可把计算过程总结如下 考虑一个有M个符号a1=(2…,M的字符表集,假设概率p(a1)=P1,而 P2(a1)=P1+P2+…+PM)=1。输入符号用xn表示,第n个子间隔的范围用 1n=[n,n)=[n1+dn∑p-,ln1+dn∑p,)表示。其中b=0,do=1和po=0 ln表示间隔左边界的值,厂n表示间隔右边界的值,dn=rn-l表示间隔长度。编码步骤如 下 步骤1:首先在1和0之间给每个符号分配一个初始子间隔,子间隔的长度等于它的概率, 初始子间隔的范围用l1=1n)=[∑P∑P,)表示。令d1=-1,L=l和R=F 步骤2:L和的二进制表达式分别表示为:
第4章 无损数据压缩 4 在0到1之间。编码过程中的间隔决定了符号压缩后的输出。算术编码器的编码过程可用下面 的例子加以解释。 [例4.2] 假设信源符号为{00, 01, 10, 11},这些符号的概率分别为{ 0.1, 0.4, 0.2, 0.3 },根据这些概率可把间隔[0, 1)分成4个子间隔:[0, 0.1), [0.1, 0.5), [0.5, 0.7), [0.7, 1),其中 [x, y) 表示半开放间隔,即包含 x 不包含 y 。上面的信息可综合在表4-04中。 表4-04 信源符号,概率和初始编码间隔 符号 00 01 10 11 概率 0.1 0.4 0.2 0.3 初始编码间隔 [0, 0.1) [0.1, 0.5) [0.5, 0.7) [0.7, 1] 如果二进制消息序列的输入为:10 00 11 00 10 11 01,编码时首先输入的符号是10, 找到它的编码范围是[0.5, 0.7]。由于消息中第二个符号00的编码范围是[0, 0.1),因此它 的间隔就取[0.5, 0.7)的第一个十分之一作为新间隔[0.5, 0.52)。依此类推,编码第3个符 号11时取新间隔为[0.514, 0.52),编码第4个符号00时,取新间隔为[0.514, 0.5146),… 。 消息的编码输出可以是最后一个间隔中的任意数。整个编码过程如图4-03所示。 图4-03 算术编码过程举例 这个例子的编码和译码的全过程分别表示在表4-05和表4-06中。根据上面所举的例子, 可把计算过程总结如下。 考虑一个有 M 个符 号 a (1,2, ,M ) i = 的字符表集,假设概率 p ai = pi ( ) , 而 ( )= 1 2 ) 1 1 + + + = = M M i pi ai p p p 。输入符号用 n x 表示,第 n 个子间隔的范围用 = − = = = − + − − − + i i n i i i I n l n rn l n dn pi l n d p 1 1 1 1 1 1 1 [ , ) [ , ) 表示。其中 l 0 = 0 ,d0 = 1 和 p0 = 0, n l 表示间隔左边界的值, n r 表示间隔右边界的值, n n n d = r − l 表示间隔长度。编码步骤如 下: 步骤1:首先在1和0之间给每个符号分配一个初始子间隔,子间隔的长度等于它的概率, 初始子间隔的范围用 I1 = [l 1 ,r1 ) = [ = − i i pi 1 1 ,= i i i p 1 )表示。令 1 1 1 d = r −l , 1 L = l 和 1 R = r 。 步骤2:L和R的二进制表达式分别表示为:
第4章无损数据压缩 L=12k和R k 其中u和v等于“1”或者“0 比较u1和v1:①如果1≠v1,不发送任何数据,转到步骤3:②如果a1=V1,就发送 二进制符号u1 比较a2和v2:①如果a2≠v2,不发送任何数据,转到步骤3:②如果l2=V2,就发 送二进制符号a2° 这种比较一直进行到两个符号不相同为止,然后进入步骤3, 步骤3:n加1,读下一个符号。假设第n个输入符号为xn=a1,按照以前的步骤把这 个间隔分成如下所示的子间隔 ln=[n,)=[n+dn∑p-1,ln+dn∑P) 令L=n,R=rn和dn=n-ln,然后转到步骤2 表4-05编码过程 骤|输入 编码间隔 编码判决 符号 1|10[0.5,0.7] 号的间隔范围[0.5,0.7) 200[0.5,0.52] [0.5,0.7间隔的第一个1/10 3m1[0.514,0.250.52间隔的最后三个1/o 00[0.514,05146][0.514,0.52间隔的第一个1/10 10[0.5143,0.51442][0.514,0.5146间隔的第五个1/10开始,二个1/10 11[0.514384,0.51442][0.5143,0.51442]间隔的最后3个1/10 701[0.5143836, [0.514384,0.51442]间隔的4个1/10,从第1个1/10 .514402] 开始 从[0.5143876,0.51402)中选择一个数作为输出:0.5143876 表4-06译码过程 步骤 译码符号 译码判决 [0.5,0.7] 10卩0.51439在间隔[0.5,0.7) 20.5,0.52] 00051439在间隔[05,07)的第1个1/10 3[0.5140.52] 110.51439在间隔[0.5,0.52)的第7个1/10 [0.514,0.5146]000.51439在间隔[0.514,0.52)的第1个/10 0.5143,0.51442]100.51439在间隔[0.514,0.5146)的第5个1/10 0.514384,0.51442]110.51439在间隔[0.5143,0.51442)的第7个1/10 [0.51439 01D.51439在间隔[0.51439,0.5143948]的第 0.5143948 1/10 译码的消息:10001100101101 「例3]假设有4个符号的信源,它们的概率如表4-07所示 表407符号概率 信源符号a; a 概率P|P=05p2=025p3=0.125|p2=0125
第4章 无损数据压缩 5 = − = 1 2 k k L uk 和 = − = 1 2 k k k R v 其中 k u 和 k v 等于“1”或者“0”。 比较 1 u 和 1 v :①如果 1 1 u v ,不发送任何数据,转到步骤3;②如果 1 1 u = v ,就发送 二进制符号 1 u 。 比较 u2 和 2 v :①如果 2 2 u v ,不发送任何数据,转到步骤3;②如果 2 2 u = v ,就发 送二进制符号 u2 。 … 这种比较一直进行到两个符号不相同为止,然后进入步骤3, 步骤3: n 加1,读下一个符号。假设第 n 个输入符号为 n ai x = ,按照以前的步骤把这 个间隔分成如下所示的子间隔: = = = = − + − − − + − i i i i n n n n n i n dn pi I I r I d p I 1 1 1 1 1 1 1 [ , ) [ , ) 令 n L = I , n R = r 和 n n n d = r − I ,然后转到步骤2。 表4-05 编码过程 步骤 输入 符号 编码间隔 编码判决 1 10 [0.5, 0.7] 符号的间隔范围[0.5, 0.7) 2 00 [0.5, 0.52] [0.5, 0.7]间隔的第一个1/10 3 11 [0.514, 0.52] [0.5, 0.52]间隔的最后三个1/10 4 00 [0.514, 0.5146] [0.514, 0.52]间隔的第一个1/10 5 10 [0.5143, 0.51442] [0.514, 0.5146]间隔的第五个1/10开始,二个1/10 6 11 [0.514384, 0.51442] [0.5143, 0.51442]间隔的最后3个1/10 7 01 [0.5143836, 0.514402] [0.514384, 0.51442]间隔的4个1/10,从第1个1/10 开始 8 从[0.5143876, 0.514402)中选择一个数作为输出:0.5143876 表4-06 译码过程 步骤 间隔 译码符号 译码判决 1 [0.5, 0.7] 10 0.51439在间隔 [0.5, 0.7) 2 [0.5, 0.52] 00 0.51439在间隔 [0.5, 0.7)的第1个1/10 3 [0.514, 0.52] 11 0.51439在间隔[0.5, 0.52)的第7个1/10 4 [0.514, 0.5146] 00 0.51439在间隔[0.514, 0.52)的第1个1/10 5 [0.5143, 0.51442] 10 0.51439在间隔[0.514, 0.5146)的第5个1/10 6 [0.514384, 0.51442] 11 0.51439在间隔[0.5143, 0.51442)的第7个1/10 7 [0.51439, 0.5143948] 01 0.51439在间 隔[0.51439, 0.5143948] 的第 1个 1/10 7 译码的消息:10 00 11 00 10 11 01 [例3] 假设有4个符号的信源,它们的概率如表4-07所示: 表4-07 符号概率 信源符号ai a1 2 a 3 a 4 a 概率 i p p1 = 0.5 p2 = 0.25 p3 = 0.125 p4 = 0.125