笨笨数据压缩教程Word格式文档下载.docx
《笨笨数据压缩教程Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《笨笨数据压缩教程Word格式文档下载.docx(37页珍藏版)》请在冰豆网上搜索。
![笨笨数据压缩教程Word格式文档下载.docx](https://file1.bdocx.com/fileroot1/2023-2/3/24ec1b67-6f86-42c1-b316-ee854dde38ea/24ec1b67-6f86-42c1-b316-ee854dde38ea1.gif)
缩技术;
缩技术;
MP3等;
/-------------------、;
AVI
二值;
灰度;
彩色;
矢量;
MPEG2等
/------\;
/-------------\;
图像;
图像
Huffman;
算术;
LZ77;
LZ78;
LZW;
|;
编码;
编码;
\-------------/;
传真机;
FELICS;
GIF;
ostScript
标准;
JPEG等;
JPEG等WindowsWMF等
UNIX下;
接近无损;
PKZIP、LHarc、ARJ、
的COMPACT压缩极限;
UNIX下的COMPRESS
程序等;
的高级应用;
程序等
本书也将大致遵循上面的结构展开,准备好了吗?
开始
关于版权问题的几点补充说明
《笨笨数据压缩教程》中介绍的压缩算法中,有一部分受到美国专利法的保护(例如LZW算法的某些部分和高阶算术压缩算法的某些细节等)。
虽然在这一问题上王笨笨认为在计算机领域对某种抽象的算法而非程序实现加以保护有阻碍技术进步之嫌,但仍然需要提醒那些试图在自己的程序中实现某种压缩技术并将程序用于商业目的的人们,在实现以前,最好先对技术专利情况加以了解,以免最终陷入商业被动。
《笨笨数据压缩教程》中提供的源代码有一部分由王笨笨本人编写,有一部分由文思软件工作室的其他程序员编写,还有部分源代码由王笨笨从因特网上获得,但这些代码全部都是“自由代码”(freecode)。
如果你打算在你的程序中使用这些代码,你必须仔细阅读并遵守以下所有规定:
你可以使用、复制、发布、修改这些代码,并将其用于包括个人、组织、商业在内的各种目的,你不需要为此向我们支付任何款项。
我们不为使用这些代码的后果承担任何法律责任。
但如果你在代码中发现了错误或对代码存有疑问,你可以使用E-Mail方式通知我们,我们会在力所能及的前提下提供技术支持。
不要以任何方式假定是你编写了这些代码。
如果你将这些代码用于你的程序中,请你务必于程序的显著位置(例如About对话框或Readme文档中)注明“本程序中的某些代码由文思软件工作室提供”。
目录
第一章:
轻松一下:
数据压缩简史
第二章:
技术准备:
概率、模型和编码
第三章:
奇妙的二叉树:
Huffman的贡献
第四章:
向极限挑战:
算术编码
第五章:
聪明的以色列人(上):
LZ77
第六章:
聪明的以色列人(下):
LZ78和LZW
第七章:
小结一下:
压缩方法的比较和应用(附索引数据的压缩)
第八章:
抓住特性:
从行程编码到二值和灰度图像压缩
第九章:
熟悉的格式:
GIF和TIFF
第十章:
损失一点精度:
伟大的JPEG
第十一章:
媒体世界:
声音和视频
第十二章:
更高的目标:
回顾与展望
你一定看出了本书目录中显现出来的层次关系。
是的,本书是按照前言中对压缩技术的分类编排的。
假如你想系统地学习和掌握压缩技术,最好按照章节顺序依次阅读;
当然,如果你仅仅把本书当作了解压缩技术的窗口,或者将本书作为一本速查手册,那么,你完全可以根据你的需要进行跳跃式的浏览。
第1章轻松一下:
数据压缩简史
算起来,数据压缩的起源要比计机的起源早得多,有兴趣的读者可以翻阅一下任何一本成语辞典,查查诸如“二桃三士”、“萧规曹随”之类的短语涵盖了多少信息内容。
认真一点:
数据压缩技术在计算机技术的萌芽时期就已经被提上了议事日程,有关信息如何被高效存储和传递的话题不断被军事科学家、数学家、电子学家讨论来、讨论去。
终于,随着信息论的产生和发展,数据压缩也由热门话题演变成了真正的技术。
通用无损数据压缩
科学家在研究中发现,大多数信息的表达都存在着一定的冗余度,通过采用一定的模型和编码方法,可以降低这种冗余度。
贝尔实验室的ClaudeShannon和MIT的R.M.Fano几乎同时提出了最早的对符号进行有效编码从而实现数据压缩的Shannon-Fano编码方法。
D.A.Huffman于1952年第一次发表了他的论文“最小冗余度代码的构造方法”(AMethodfortheConstructionofMinimumRedundancyCodes)。
从此,数据压缩开始在商业程序中实现并被应用在许多技术领域。
UNIX系统上一个不太为现代人熟知的压缩程序COMPACT就是Huffman0阶自适应编码的具体实现。
80年代初,Huffman编码又在CP/M和DOS系统中实现,其代表程序叫SQ。
在数据压缩领域,Huffman的这一论文事实上开创了数据压缩技术一个值得回忆的时代,60年代、70年代乃至80年代的早期,数据压缩领域几乎一直被Huffman编码及其分支所垄断。
如果不是后面将要提到的那两个以色列人,也许我们今天还要在Huffman编码的0和1的组合中流连忘返。
让我们沿着Huffman的轨迹再向后跳跃几年,80年代,数学家们不满足于Huffman编码中的某些致命弱点,他们从新的角度入手,遵循Huffman编码的主导思想,设计出另一种更为精确,更能接近信息论中“熵”极限的编码方法——算术编码。
凭借算术编码的精妙设计和卓越表现,人们终于可以向着数据压缩的极限前进了。
可以证明,算术编码得到的压缩效果可以最大地减小信息的冗余度,用最少量的符号精确表达原始信息内容。
当然,算术编码同时也给程序员和计算机带来了新的挑战:
要实现和运行算术编码,需要更为艰苦的编程劳动和更加快速的计算机系统。
也就是说,在同样的计算机系统上,算术编码虽然可以得到最好的压缩效果,但却要消耗也许几十倍的计算时间。
这就是为什么算术编码不能在我们日常使用的压缩工具中实现的主要原因。
那么,能不能既在压缩效果上超越Huffman,又不增加程序对系统资源和时间的需求呢?
我们必须感谢下面将要介绍的两个以色列人。
直到1977年,数据压缩的研究工作主要集中于熵、字符和单词频率以及统计模型等方面,研究者们一直在绞尽脑汁为使用Huffman编码的程序找出更快、更好的改进方法。
1977年以后,一切都改变了。
1977年,以色列人JacobZiv和AbrahamLempel发表了论文“顺序数据压缩的一个通用算法”(AUniversalAlogrithemforSequentialDataCompression)。
1978年,他们发表了该论文的续篇“通过可变比率编码的独立序列的压缩”(CompressionofIndividualSequencesviaVariable-RateCoding)。
所有的一切都改变了,在这两篇论文中提出的两个压缩技术被称为LZ77和LZ78(不知为什么,作者名字的首字母被倒置了)。
简单地说,这两种压缩方法的思路完全不同于从Shannon到Huffman到算术压缩的传统思路,倒是和本章开头所举的成语辞典的例子颇为相似,因此,人们将基于这一思路的编码方法称作“字典”式编码。
字典式编码不但在压缩效果上大大超过了Huffman,而且,对于好的实现,其压缩和解压缩的速度也异常惊人。
1984年,TerryWelch发表了名为“高性能数据压缩技术”(ATechniqueforHigh-PerformanceDataCompression)的论文,描述了他在SperryResearchCenter(现在是Unisys的一部分)的研究成果。
他实现了LZ78算法的一个变种——LZW。
LZW继承了LZ77和LZ78压缩效果好、速度快的优点,而且在算法描述上更容易被人们接受(有的研究者认为是由于Welch的论文比Ziv和Lempel的更容易理解),实现也比较简单。
不久,UNIX上出现了使用LZW算法的Compress程序,该程序性能优良,并有高水平的文档,很快成为了UNIX世界的压缩程序标准。
紧随其后的是MS-DOS环境下的ARC程序(SystemEnhancementAssociates,1985),还有象PKWare、PKARC等仿制品。
LZ78和LZW一时间统治了UNIX和DOS两大平台。
80年代中期以后,人们对LZ77进行了改进,随之诞生了一批我们今天还在大量使用的压缩程序。
HaruyasuYoshizaki(Yoshi)的LHarc和RobertJung的ARJ是其中两个著名的例子。
LZ77得以和LZ78、LZW一起垄断当今的通用数据压缩领域。
目前,基于字典方式的压缩已经有了一个被广泛认可的标准,从古老的PKZip到现在的WinZip,特别是随着Internet上文件传输的流行,Z[wiki]IP[/wiki]格式成为了事实上的标准,没有哪一种通用的文件压缩、归档系统敢于不支持ZIP格式。
多媒体信息的压缩
今天的程序员们和设计师们往往乐此不疲地为计算机更换更大的硬盘,增加更多的内存,其主要目的是为了存放和处理越来越多的声音、图像和视频数据。
对声音、图像、视频等多媒体信息的压缩有两条思路,要么采用成熟的通用数据压缩技术进行压缩,要么根据媒体信息的特性设计新的压缩方法。
事实上,人们在两条道路上都作了卓有成效的探索。
还记得GIF格式吗?
GIF可以把原始图形文件以非常小数据量存储,可以在同一个文件中存储多幅图像从而实现动画效果。
知道GIF中的图像使用什么方法压缩的吗?
LZW!
原来如此啊。
GIF大概是使用通用压缩技术压缩图像信息的最成功的例子,当然,GIF文件中除了经过LZW压缩的像素信息以外,还保存有图像的各种属性信息以及图像所使用的调色板信息等。
GIF精确地保留了原始图像的每一个像素信息,是无损图像压缩的代表。
根据媒体特性量身定制的压缩方法中,行程编码(RLE:
Run-LengthEncoding)是最为简单、最容易被想到的一种。
大多数计算机中产生的图像(和现实世界的图像例如照片不同)都具有着大面积重复的颜色块,为什么非要用无数个完全相同的颜色值来表示某块图像呢?
我们完全可以用一个颜色值加一个重复次数来表示这一块图像,冗余度由此减小了,这就是RLE方法的基本思路。
显然,它不适于用来压缩照片、声音等很少连续重复信息的数据。
RLE方法最有代表性的实现有PCX和Targa图形格式。
如果分别考察的话,只有黑白两种颜色的二值图像以及只有256级灰度变化的图像具有一些独特的地方,可以被压缩算法加以利用。
我们知道,传真图像是一种典型的二值图像。
国际电报电话咨询委员会(CCITT)为此建立了一系列的压缩标准,专门用于压缩传递二值图像(可以是无损的或有损的)。
对于灰度图像,除了著名的JPEG标准以外,后文将要介绍的一种叫FELICS的算法可以实现效果非常好的无损压缩。
70年代末80年代初,人们逐渐意识到,对到多数灰度或是彩色图像乃至声音文件,没有必要忠实地保留其所有信息,在允许一定的精度损失的情况下,可以实现更为有效的压缩方法。
到80年代末,许多人已经在这一领域取得了不小的收获,设计出了一批在压缩效果上让人惊讶不已的声音和图像压缩算法。
在此基础上,国际标准化组织(ISO)和CCITT联合组成了两个委员会。
委员会的名字我们大概都已经非常熟悉了:
静态图像联合专家小组(JPEG)和动态图像联合专家小组(MPEG)。
JPEG的压缩目标是静止图像(灰度的和彩色的),MPEG的目标则是声音和视频。
但他们的基本思路是完全一样的,即保留媒体信息中最有规律、最能体现信息主要特征的数据,而略去其他不重要的数据。
他们都取得了令人赞叹的成就。
你刚看完VCD吗?
那么你刚刚享用过他们为我们带来的乐趣了。
知道普通VCD每一帧有多少彩色像素吗?
知道每秒钟播放多少帧吗?
知道的话,算一算一部100分钟的电影不压缩的话需要多少空间。
每张光盘的容量是640M,那么,不压缩的电影需要多少张光盘来存放呢?
你该知道JPEG或是MPEG的厉害了吧。
最后,必须简单地提到与图像压缩领域相关的电子出版印刷领域中的一种叫做PostScript的东西。
PostScript是作为电子印刷业的标准页面描述语言被设计出来的,它起源于1976年的Evans&
Sutherland计算机公司,当时的名字是DesignSystem。
1978年,JohnWarnock和MartinNewel将其演变为JAM语言。
1982年,JohnWarnock和ChuckGeschke创建了著名的AdobeSystem公司,并第三次设计和实现了这个语言,并将其称为PostScript。
PostScript的主要思路是存储和传输预先定义的命令来“画”出图像,而不是存储和传输图像的每一个像素,这特别适用于在激光打印机上的输出。
采用类似“从(10,10)到(100,100)画一条红色直线”或是“在(50,50)以40为半径画一个蓝色的圆”之类的命令存储图像显然比直接存储每个像素节省了不少地方。
所以,从压缩技术的角度来看,PostScript也可以算是压缩方法的一种。
根据类似的原理,Windows中的WMF格式、HP的HPGL语言、AutoCAD中使用的DXF格式等等,都可以对某种特定的图像进行有效的压缩。
第2章技术准备:
概率、模型和编码
什么是熵
数据压缩不仅起源于40年代由ClaudeShannon首创的信息论,而且其基本原理即信息究竟能被压缩到多小,至今依然遵循信息论中的一条定理,这条定理借用了热力学中的名词“熵”(Entropy)来表示一条信息中真正需要编码的信息量:
考虑用0和1组成的二进制数码为含有n个符号的某条信息编码,假设符号Fn在整条信息中重复出现的概率为Pn,则该符号的熵也即表示该符号所需的位数位为:
En=-log2(Pn)
整条信息的熵也即表示整条信息所需的位数为:
E=∑En
举个例子,对下面这条只出现了abc三个字符的字符串:
aabbaccbaa
字符串长度为10,字符abc分别出现了532次,则abc在信息中出现的概率分别为0.50.30.2,他们的熵分别为:
Ea=-log2(0.5)=1
Eb=-log2(0.3)=1.737
Ec=-log2(0.2)=2.322
整条信息的熵也即表达整个字符串需要的位数为:
E=Ea*5+Eb*3+Ec*2=14.855位
回想一下如果用计算机中常用的ASCII编码,表示上面的字符串我们需要整整80位呢!
现在知道信息为什么能被压缩而不丢失原有的信息内容了吧。
简单地讲,用较少的位数表示较频繁出现的符号,这就是数据压缩的基本准则。
细心的读者马上会想到,我们该怎样用01这样的二进制数码表示零点几个二进制位呢?
确实很困难,但不是没有办法。
一旦我们找到了准确表示零点几个二进制位的方法,我们就有权利向无损压缩的极限挑战了。
不要着急,看到第四章就明白了。
模型
从上面的描述,我们明白,要压缩一条信息,首先要分析清楚信息中每个符号出现的概率。
不同的压缩程序通过不同的方法确定符号的出现概率,对符号的概率计算得越准确,也就越容易得到好的压缩效果。
在压缩程序中,用来处理输入信息,计算符号的概率并决定输出哪个或哪些代码的模块叫做模型。
难道对信息中字符的出现概率这么难以估计以至于有各种不同的压缩模型吗?
对上面的字符串我们不是很容易就知道每个字符的概率了吗?
是的是的,不过上面的字符串仅有10个字符长呀,那只是例子而已。
考虑我们现实中要压缩的文件,大多数可是有几十K甚至几百K长,几M字节的文件不是也屡见不鲜吗?
是的,我们可以预先扫描文件中的所有字符,统计出每个字符出现的概率,这种方法在压缩术语里叫做“静态统计模型”。
但是,不同的文件中,字符有不同的分布概率,我们要么先花上大量的时间统计我们要压缩的所有文件中的字符概率,要么为每一个单独的文件保存一份概率表以备解压缩时需要。
糟糕的是,不但扫描文件要消耗大量时间,而且保存一份概率表也使压缩后的文件增大了不少。
所以,在实际应用中,“静态统计模型”应用的很少。
真正的压缩程序中使用的大多是一种叫“自适应模型”的东西。
自适应模型可以说是一台具有学习功能的自动机。
他在信息被输入之前对信息内容一无所知并假定每个字符的出现概率均等,随着字符不断被输入和编码,他统计并纪录已经出现过的字符的概率并将这些概率应用于对后续字符的编码。
也就是说,自适应模型在压缩开始时压缩效果并不理想,但随着压缩的进行,他会越来越接近字符概率的准确值,并达到理想的压缩效果。
自适应模型还可以适应输入信息中字符分布的突然变化,可以适应不同的文件中的字符分布而不需要保存概率表。
上面提到的模型可以统称为“统计模型”,因为他们都是基于对每个字符出现次数的统计得到字符概率的。
另一大类模型叫做“字典模型”。
实际上,当我们在生活中提到“工行”这个词的时候,我们都知道其意思是指“中国工商银行”,类似的例子还有不少,但共同的前提是我们心中都有一本约定俗成的缩写字典。
字典模型也是如此,他并不直接计算字符出现的概率,而是使用一本字典,随着输入信息的读入,模型找出输入信息在字典中匹配的最长的字符串,然后输出该字符串在字典中的索引信息。
匹配越长,压缩效果越好。
事实上,字典模型本质上仍然是基于对字符概率的计算的,只不过,字典模型使用整个字符串的匹配代替了对某一字符重复次数的统计。
可以证明,字典模型得到的压缩效果仍然无法突破熵的极限。
当然,对通用的压缩程序来说,保存一本大字典所需的空间仍然是无法让人忍受的,况且,任何一本预先定义的字典都无法适应不同文件中数据的变化情况。
对了,字典模型也有相应的“自适应”方案。
我们可以随着信息的不断输入,从已经输入的信息中建立合适的字典,并不断更新这本字典,以适应数据的不断变化。
让我们从另一个角度理解一下自适应模型。
CluadeShannon曾试图通过一个“聚会游戏”(partygame)来测定英语的真实信息容量。
他每次向听众公布一条被他隐藏起一个字符的消息,让听众来猜下一个字符是什么,一次猜一个,直到猜对为止。
然后,Shannon使用猜测次数来确定整个信息的熵。
在这个实验中,一种根据前面出现过的字符估计下一个字符概率的模型就存在于听众的头脑中,比计算机中使用的自适应模型更为高级的是,听众除了根据字符出现过的次数外,还可以根据他们对语言的经验进行猜测。
编码
通过模型,我们已经确定了对某一个符号该用多少位二进制数进行编码。
现在的问题是,如何设计一种编码方案,使其尽量精确地用模型计算出来的位数表示某个符号。
最先被考虑的问题是,如果对a用3个二进制位就可以表示,而对b用4个二进制位就可以表示,那么,在解码时,面对一连串的二进制流,我怎么知道哪三个位是a,哪四个位是b呢?
所以,必须设计出一种编码方式,使得解码程序可以方便地分离每个字符的编码部分。
于是有了一种叫“前缀编码”的技术。
该技术的主导思想是,任何一个字符的编码,都不是另一个字符编码的前缀。
反过来说就是,任何一个字符的编码,都不是由另一个字符的编码加上若干位0或1组成。
看一下前缀编码的一个最简单的例子:
符号;
编码
A;
0
B;
10
C;
110
D;
1110
E;
11110
有了上面的码表,你一定可以轻松地从下面这串二进制流中分辨出真正的信息内容了:
1110010101110110111100010-DABBDCEAAB
下一个问题是:
象上面这样的前缀编码只能表示整数位的符号,对几点几位的符号只能用近似的整数位输出,那么怎样输出小数位数呢?
科学家们用算术编码解决了这个问题,我们将在第四章对算术编码作详细的讨论。
总结一下
不同的模型使用不同的方法计算字符的出现概率,由此概率可以得出字符的熵;
然后使用不同的编码方法,尽量接近我们期望得到的熵值。
所以,压缩效果的好坏一方面取决于模型能否准确地得到字符概率,另一方面也取决于编码方法能否准确地用期望的位数输出字符代码。
换句话说,压缩=模型+编码。
如下图所示:
----