760 likes | 986 Views
数据压缩. 数据压缩可分成两种类型 : 无损压缩 有损压缩 无损压缩是指使用压缩后的数据进行重构 ( 或者叫做还原,解压缩 ) ,重构后的数据与原来的数据完全相同;无损压缩用于要求重构的信号与原始信号完全一致的场合。一个很常见的例子是磁盘文件的压缩。根据目前的技术水平,无损压缩算法一般可以把普通文件的数据压缩到原来的 1/2 ~ 1/4 。一些常用的无损压缩算法有霍夫曼 (Huffman) 算法和 LZW(Lenpel-Ziv & Welch) 压缩算法。. 对称和不对称编码:
E N D
数据压缩 数据压缩可分成两种类型: 无损压缩 有损压缩无损压缩是指使用压缩后的数据进行重构(或者叫做还原,解压缩),重构后的数据与原来的数据完全相同;无损压缩用于要求重构的信号与原始信号完全一致的场合。一个很常见的例子是磁盘文件的压缩。根据目前的技术水平,无损压缩算法一般可以把普通文件的数据压缩到原来的1/2~1/4。一些常用的无损压缩算法有霍夫曼(Huffman)算法和LZW(Lenpel-Ziv & Welch)压缩算法。
对称和不对称编码: 对称性(symmetric)是压缩编码的一个关键特征。对称意味着压缩和解压缩占用相同的计算处理能力和时间,对称算法适合于实时压缩和传送视频,如视频会议应用就以采用对称的压缩编码算法为好。而在电子出版和其它多媒体应用中,一般是把视频预先压缩处理好,尔后再播放,因此可以采用不对称(asymmetric)编码。 不对称或非对称意味着压缩时需要花费大量的处理能力和时间,而解压缩时则能较好地实时回放,也即以不同的速度进行压缩和解压缩。一般地说,压缩一段视频的时间比回放(解压缩)该视频的时间要多得多。例如,压缩一段三分钟的视频片断可能需要10多分钟的时间,而该片断实时回放时间只有三分钟。
有损压缩是指使用压缩后的数据进行重构,重构后的数据与原来的数据有所不同,但不会让人对原始资料表达的信息造成误解。有损压缩适用于重构信号不一定非要和原始信号完全相同的场合。例如,图像和声音的压缩就可以采用有损压缩,因为其中包含的数据往往多于我们的视觉系统和听觉系统所能接收的信息,丢掉一些数据而不至于对声音或者图像所表达的意思产生误解,但可大大提高压缩比。有损压缩是指使用压缩后的数据进行重构,重构后的数据与原来的数据有所不同,但不会让人对原始资料表达的信息造成误解。有损压缩适用于重构信号不一定非要和原始信号完全相同的场合。例如,图像和声音的压缩就可以采用有损压缩,因为其中包含的数据往往多于我们的视觉系统和听觉系统所能接收的信息,丢掉一些数据而不至于对声音或者图像所表达的意思产生误解,但可大大提高压缩比。 本章主要介绍目前用得最多和技术最成熟的无损压缩编码技术,包括包含霍夫曼编码、算术编码、RLE编码和词典编码。对于不打算开发压缩技术和编写压缩程序的读者可不必深究编译码的详细过程。
在多媒体信息中包含大量冗余的信息,把这些冗余的信息去掉,就实现了压缩。数据压缩技术有三个重要指标:在多媒体信息中包含大量冗余的信息,把这些冗余的信息去掉,就实现了压缩。数据压缩技术有三个重要指标: • 一是压缩前后所需要的信息存储量之比要大; • 二是实现压缩的算法要简单,压缩、解压速度快,尽可能地做到实时压缩和解压; • 三是要好,要尽可能的完全恢复原始数据。
Huffman编码 是对统计独立信源达到最小平均码长的编码方法 其基本原理是按信源符号出现的概率大小进行排序,出现概率大的分配短码,出现概率小的则分配长码。编码过程如下:
将信源符号按概率递减顺序排列; • 把两个最小的概率加起来,作为新符号的概率; • 重复前两步,直到概率和达到1为止; • 在每次合并消息时,将被合并的消息赋予1和0或0和1; • 寻找从每一信源符号到概率为1的路径,记录下路径上的1和0; • 对每一符号写出从码树的根到中节点1、0序列。
举例说明 例如:对信源 X1 X2 X3 X4 X5 X6 X= 0.250.250.20 0.15 0.10 0.05 对其进行编码,写出其码树、码长,并计算平均码长。
0 1 0.55 符号 概率 编码过程 X1 0.25 X2 0.25 X3 0.20 X4 0.15 X5 0.10 X6 0.05 所以, X1 =01、X2 =10、X3 =11、X4 =000、X5 =0010、X6 =0011、码长分别为:2,2,2,3,4,4。平均码长为2.83. 0 1 1 0.45 0 0 0 0.30 1 1 0.15
实例: • 将下图中的数据按Haffman规则编码 数据量绿:85青:53红:18紫:18黄:18橙:18 概率0.4050.2510.0860.0860.0860.086
0 1 0 1 0.595 0 0.172 1 1 0 0.344 0 1 0.172 1 • 绿:0.405 • 青: 0.251 • 红: 0.086 • 紫: 0.086 • 黄: 0.086 • 橙: 0.086 绿:0; 青:10 ; 红:1100 紫:1101 黄:1110; 橙:1111 编码总长度=1*85+2*53+4*18*4=479 等长编码总长度=(85+53+18*4)*3=630
预测编码是数据压缩的一个重要的方法。由于离散信号间存在一定关联性,因此可以根据前面的一个或多个信号对下一个信号进行预测,然后对实际值和预测值的差值进行编码。预测的越准确,则误差信号就越小,这样,就可以用较小的数码对误差信号进行编码,进而达到压缩的目的。 预测编码是数据压缩的一个重要的方法。由于离散信号间存在一定关联性,因此可以根据前面的一个或多个信号对下一个信号进行预测,然后对实际值和预测值的差值进行编码。预测的越准确,则误差信号就越小,这样,就可以用较小的数码对误差信号进行编码,进而达到压缩的目的。 我们常说的主要是线性预测。较典型的方法是自适应差分脉冲编码调制(ADPCM)和差分脉冲编码调制(DPCM)等。
变换编码是指对信号进行变换后,再编码。如将时域信号变换到频域信号,因为声音、图像大部分信号都是低频信号,在频域中信号的能量较集中,再进行采样、编码肯定可以压缩数据。其过程即系统构成为:信源序列→变换→变换域采样→量化编码→存储或传输→译码→填零→反变换→再现序列。变换编码是指对信号进行变换后,再编码。如将时域信号变换到频域信号,因为声音、图像大部分信号都是低频信号,在频域中信号的能量较集中,再进行采样、编码肯定可以压缩数据。其过程即系统构成为:信源序列→变换→变换域采样→量化编码→存储或传输→译码→填零→反变换→再现序列。
音频信号的压缩编码 音频信号编码的分类(主要是有损压缩):波形编码(主要有PCM、DPCM、ADPCM),参数编码(主要有预测性LPC),混合编码(主要有CELP、MP-LPC)。音频信号的压缩标准为G系列。
视频信号的压缩编码 比较常用的为有损压缩,包括预测编码、变换编码、模型编码、以及混合编码。其中最重要的是混合编码中的JPEG(多灰度静止图像的数字压缩编码标准)和MPEG(运动图像压缩标准)。
MPEG视频压缩技术是针对运动图像的数据压缩技术。通过帧运动补偿有效地压缩了数据的比特数,它采用了三种图像,帧内图、预测图和双向预测图,有效地减少了冗余信息。对于MPEG来说,帧间数据压缩、运动补偿和双向预测,这是和JPEG主要的不同之处。另外,MPEG中视频信号包含有静止图画和运动信息等不同的内容,量化器的设计比JPEG压缩算法中量化器的设计考虑的因素要多。MPEG视频压缩技术是针对运动图像的数据压缩技术。通过帧运动补偿有效地压缩了数据的比特数,它采用了三种图像,帧内图、预测图和双向预测图,有效地减少了冗余信息。对于MPEG来说,帧间数据压缩、运动补偿和双向预测,这是和JPEG主要的不同之处。另外,MPEG中视频信号包含有静止图画和运动信息等不同的内容,量化器的设计比JPEG压缩算法中量化器的设计考虑的因素要多。
无损数据压缩 RLE编码 现实中有许多这样的图像,在一幅图像中具有许多颜色相同的图块。在这些图块中,许多行上都具有相同的颜色,或者在一行上有许多连续的像素都具有相同的颜色值。在这种情况下就不需要存储每一个像素的颜色值,而仅仅存储一个像素的颜色值,以及具有相同颜色的像素数目就可以,或者存储一个像素的颜色值,以及具有相同颜色值的行数。
这种压缩编码称为行程编码,常用(run length encoding,RLE)表示,具有相同颜色并且是连续的像素数目称为行程长度。为了叙述方便,假定一幅灰度图像,第n行的像素值为:
用RLE编码方法得到的代码为:80315084180。代码中用黑体表示的数字是行程长度,黑体字后面的数字代表像素的颜色值。例如黑体字50代表有连续50个像素具有相同的颜色值,它的颜色值是8。用RLE编码方法得到的代码为:80315084180。代码中用黑体表示的数字是行程长度,黑体字后面的数字代表像素的颜色值。例如黑体字50代表有连续50个像素具有相同的颜色值,它的颜色值是8。
对比RLE编码前后的代码数可以发现,在编码前要用73个代码表示这一行的数据,而编码后只要用11个代码表示代表原来的73个代码,压缩前后的数据量之比约为7:1,即压缩比为7:1。这说明RLE确实是一种压缩技术,而且这种编码技术相当直观,也非常经济。RLE所能获得的压缩比有多大,这主要是取决于图像本身的特点。如果图像中具有相同颜色的图像块越大,图像块数目越少,获得的压缩比就越高。反之,压缩比就越小。对比RLE编码前后的代码数可以发现,在编码前要用73个代码表示这一行的数据,而编码后只要用11个代码表示代表原来的73个代码,压缩前后的数据量之比约为7:1,即压缩比为7:1。这说明RLE确实是一种压缩技术,而且这种编码技术相当直观,也非常经济。RLE所能获得的压缩比有多大,这主要是取决于图像本身的特点。如果图像中具有相同颜色的图像块越大,图像块数目越少,获得的压缩比就越高。反之,压缩比就越小。 译码时按照与编码时采用的相同规则进行,还原后得到的数据与压缩前的数据完全相同。因此,RLE是无损压缩技术。RLE压缩编码尤其适用于计算机生成的图像,对减少图像文件的存储空间非常有效。然而,RLE对颜色丰富的自然图像就显得力不从心,在同一行上具有相同颜色的连续像素往往很少,而连续几行都具有相同颜色值的连续行数就更少。
如果仍然使用RLE编码方法,不仅不能压缩图像数据,反而可能使原来的图像数据变得更大。请注意,这并不是说RLE编码方法不适用于自然图像的压缩,相反,在自然图像的压缩中还真少不了RLE,只不过是不能单纯使用RLE一种编码方法,需要和其他的压缩编码技术联合应用。如果仍然使用RLE编码方法,不仅不能压缩图像数据,反而可能使原来的图像数据变得更大。请注意,这并不是说RLE编码方法不适用于自然图像的压缩,相反,在自然图像的压缩中还真少不了RLE,只不过是不能单纯使用RLE一种编码方法,需要和其他的压缩编码技术联合应用。
词典编码 有许多场合,开始时不知道要编码数据的统计特性,也不一定允许你事先知道它们的统计特性。因此,人们提出了许许多多的数据压缩方法,企图用来对这些数据进行压缩编码,在实际编码过程中以尽可能获得最大的压缩比。这些技术统称为通用编码技术。词典编码(Dictionary Encoding)技术就是属于这一类,这种技术属于无损压缩技术。
词典编码的思想 词典编码(dictionary encoding)的根据是数据本身包含有重复代码这个特性。例如文本文件和光栅图像就具有这种特性。词典编码法的种类很多,归纳起来大致有两类。第一类词典法的想法是企图查找正在压缩的字符序列是否在以前输入的数据中出现过,然后用已经出现过的字符串替代重复的部分,它的输出仅仅是指向早期出现过的字符串的“指针”。这种编码概念如图4-06所示。
这里所指的“词典”是指用以前处理过的数据来表示编码过程中遇到的重复部分。这类编码中的所有算法都是以Abraham Lempel和Jakob Ziv在1977年开发和发表的称为LZ77算法为基础的,例如1982年由Storer和Szymanski改进的称为LZSS算法就是属于这种情况。
第二类算法的想法是企图从输入的数据中创建一个“短语词典(dictionary of the phrases)”,这种短语不一定是像“严谨勤奋求实创新”和“国泰民安是坐稳总统宝座的根本”这类具有具体含义的短语,它可以是任意字符的组合。编码数据过程中当遇到已经在词典中出现的“短语”时,编码器就输出这个词典中的短语的“索引号”,而不是短语本身。这个概念如图4-07所示。
J.Ziv和A.Lempel在1978年首次发表了介绍这种编码方法的文章。在他们的研究基础上,Terry A.Weltch在1984年发表了改进这种编码算法的文章,因此把这种编码方法称为LZW(Lempel-Ziv Walch)压缩编码,首先在高速硬盘控制器上应用了这种算法。
LZ77算法 为了更好地说明LZ77算法的原理,首先介绍算法中用到的几个术语: • 入数据流(input stream):要被压缩的字符序列。 • 字符(character):输入数据流中的基本单元。 • 编码位置(coding position):输入数据流中当前要编码的字符位置,指前向缓冲存储器中的开始字符。 • 前向缓冲存储器(Lookahead buffer):存放从编码位置到输入数据流结束的字符序列的存储器。 • 窗口(window):指包含W个字符的窗口,字符是从编码位置开始向后数也就是最后处理的字符数。 • 指针(pointer):指向窗口中的匹配串且含长度的指针。
LZ77编码算法的核心是查找从前向缓冲存储器开始的最长的匹配串。编码算法的具体执行步骤如下:1.把编码位置设置到输入数据流的开始位置。 2.查找窗口中最长的匹配串。 3.以“(Pointer, Length) Characters”的格式输出,其中Pointer是指向窗口中匹配串的指针,Length表示匹配字符的长度,Characters是前向缓冲存储器中的不匹配的第1个字符。 4.如果前向缓冲存储器不是空的,则把编码位置和窗口向前移(Length+1)个字符,然后返回到步骤2。
[例4.4] 待编码的数据流如表4-09所示,编码过程如表4-10所示。现作如下说明:“步骤”栏表示编码步骤。 “位置”栏表示编码位置,输入数据流中的第1个字符为编码位置1。 “匹配串”栏表示窗口中找到的最长的匹配串。 “字符”栏表示匹配之后在前向缓冲存储器中的第1个字符。 表4-10 表4-09
“输出”栏以“(Back_chars, Chars_length) Explicit_character”格式输出。其中,(Back_chars, Chars_length)是指向匹配串的指针,告诉译码器“在这个窗口中向后退Back_chars个字符然后拷贝Chars_length个字符到输出”,Explicit_character是真实字符。例如,表4-10中的输出“(5,2) C”告诉译码器回退5个字符,然后拷贝2个字符“AB”
(倒数0,长度0),A (倒数1,长度1),B (倒数0,长度0),C (倒数2,长度1),B 表4-10 编码过程 (倒数5,长度2),C
LZSS算法 LZ77通过输出真实字符解决了在窗口中出现没有匹配串的问题,但这个解决方案包含有冗余信息。冗余信息表现在两个方面,一是空指针,二是编码器可能输出额外的字符,这种字符是指可能包含在下一个匹配串中的字符。LZSS算法以比较有效的方法解决这个问题,它的思想是如果匹配串的长度比指针本身的长度长就输出指针,否则就输出真实字符。由于输出的压缩数据流中包含有指针和字符本身,为了区分它们就需要有额外的标志位,即ID位。
LZSS编码算法的具体执行步骤如下: 1.把编码位置置于输入数据流的开始位置。 2.在前向缓冲存储器中查找与窗口中最长的匹配串① Pointer :=匹配串指针。② Length :=匹配串长度。 3.判断匹配串长度Length是否大于等于最小匹配串长度(Length 3 MIN_LENGTH) ,如果“是”:输出指针,然后把编码位置向前移动Length个字符。如果“否”:输出前向缓冲存储器中的第1个字符,然后把编码位置向前移动一个字符。 4.如果前向缓冲存储器不是空的,就返回到步骤2。
[例4.5] 编码字符串如表4-11所示,编码过程如表4-12所示。现说明如下:“步骤”栏表示编码步骤。 “位置”栏表示编码位置,输入数据流中的第1个字符为编码位置1。 “匹配”栏表示窗口中找到的最长的匹配串。 “字符”栏表示匹配之后在前向缓冲存储器中的第1个字符。 “输出”栏的输出为: • ① 如果匹配串本身的长度Length>= MIN_LENGTH,输出指向匹配串的指针,格式为(Back_chars, Chars_length)。该指针告诉译码器“在这个窗口中向后退Back_chars个字符然后拷贝Chars_length个字符到输出”。② 如果匹配串本身的长度Length <= MIN_LENGTH,则输出真实的匹配串。
表4-12 编码过程(MIN_LENGTH = 2) 有匹配但长度<2 无匹配 有匹配但长度<2 无匹配 有匹配长度=2,(倒3,长2) 有匹配长度=3,(倒7,长3)
在相同的计算机环境下,LZSS算法比LZ77可获得比较高的压缩比,而译码同样简单。这也就是为什么这种算法成为开发新算法的基础,许多后来开发的文档压缩程序都使用了LZSS的思想。例如,PKZip, ARJ, LHArc和ZOO等等,其差别仅仅是指针的长短和窗口的大小等有所不同。
LZSS同样可以和熵编码联合使用,例如ARJ就与霍夫曼编码联用,而PKZip则与Shannon-Fano联用,它的后续版本也采用霍夫曼编码。 LZSS同样可以和熵编码联合使用,例如ARJ就与霍夫曼编码联用,而PKZip则与Shannon-Fano联用,它的后续版本也采用霍夫曼编码。
LZ78算法 在介绍LZ78算法之前,首先说明在算法中用到的几个术语和符号: • 字符流(Charstream):要被编码的数据序列。 • 字符(Character):字符流中的基本数据单元。 • 前缀(Prefix): 在一个字符之前的字符序列。 • 缀-符串(String):前缀+字符。 • 码字(Code word):码字流中的基本数据单元,代表词典中的一串字符。 • 码字流(Codestream): 码字和字符组成的序列,是编码器的输出。
词典(Dictionary): 缀-符串表。按照词典中的索引号对每条缀-符串(String)指定一个码字(Code word)。 • 当前前缀(Current prefix):在编码算法中使用,指当前正在处理的前缀,用符号P表示。 • 当前字符(Current character):在编码算法中使用,指当前前缀之后的字符,用符号C表示。 • 当前码字(Current code word): 在译码算法中使用,指当前处理的码字,用W表示当前码字,String.W表示当前码字的缀-符串。
编码算法 LZ78的编码思想是不断地从字符流中提取新的缀-符串(String),通俗地理解为新“词条”,然后用“代号”也就是码字(Code word)表示这个“词条”。这样一来,对字符流的编码就变成了用码字(Code word)去替换字符流(Charstream),生成码字流(Codestream),从而达到压缩数据的目的。
在编码开始时词典是空的,不包含任何缀-符串(string)。在这种情况下编码器就输出一个表示空字符串的特殊码字(例如“0”)和字符流中(Charstream)的第一个字符(例如A),并把这个字符添加到词典中作为一个由一个字符组成的缀-符串(string)。在编码过程中,如果出现类似的情况,也照此办理。在编码开始时词典是空的,不包含任何缀-符串(string)。在这种情况下编码器就输出一个表示空字符串的特殊码字(例如“0”)和字符流中(Charstream)的第一个字符(例如A),并把这个字符添加到词典中作为一个由一个字符组成的缀-符串(string)。在编码过程中,如果出现类似的情况,也照此办理。
在词典中已经包含某些缀-符串(String)之后,如果“当前前缀P +当前字符”已经在词典中,就用当前字符来扩展这个前缀,这样的扩展操作一直重复到获得一个在词典中没有的缀-符串(String)为止。此时就输出表示当前前缀P的码字(Code word)和当前字符,并把P+当前字符添加到词典中作为前缀(Prefix),然后开始处理字符流(Charstream)中的下一个前缀。
LZ78编码器的输出是码字-字符(W,C)对,每次输出一对到码字流中,与码字W相对应的缀-符串(String)用字符C进行扩展生成新的缀-符串(String),然后添加到词典中。LZ78编码的具体算法如下: LZ78编码器的输出是码字-字符(W,C)对,每次输出一对到码字流中,与码字W相对应的缀-符串(String)用字符C进行扩展生成新的缀-符串(String),然后添加到词典中。LZ78编码的具体算法如下:
步骤1: 在开始时,词典和当前前缀P都是空的。步骤2: 当前字符C :=字符流中的下一个字符。步骤3: 判断P+C是否在词典中:(1) 如果“是”:用C扩展P,让P := P+C ;(2) 如果“否”:① 输出与当前前缀P相对应的码字和当前字符C;② 把字符串P+C 添加到词典中。③ 令P :=空值。(3) 判断字符流中是否还有字符需要编码① 如果“是”:返回到步骤2。② 如果“否”:若当前前缀P不是空的,输出相应于当前前缀P的码字,然后结束编码。 (位置2串,C) (位置3串,A) (位置2串,A)
译码算法 在译码开始时译码词典是空的,它将在译码过程中从码字流中重构。每当从码字流中读入一对码字-字符(W,C)对时,码字就参考已经在词典中的缀-符串,然后把当前码字的缀-符串string.W 和字符C输出到字符流(Charstream),而把当前缀-符串(string.W+C)添加到词典中。在译码结束之后,重构的词典与编码时生成的词典完全相同。LZ78译码的具体算法如下:
步骤1: 在开始时词典是空的。步骤2: 当前码字W :=码字流中的下一个码字。步骤3: 当前字符C := 紧随码字之后的字符。步骤4: 把当前码字的缀-符串(string.W)输出到字符流(Charstream),然后输出字符C。 步骤5: 把string.W+C添加到词典中。步骤6: 判断码字流中是否还有码字要译(1) 如果“是”,就返回到步骤2。(2) 如果“否”,则结束。
[例4.6] 编码字符串如表4-13所示,编码过程如表4-14所示。现说明如下:“步骤”栏表示编码步骤。 “位置”栏表示在输入数据中的当前位置。 “词典”栏表示添加到词典中的缀-符串,缀-符串的索引等于“步骤”序号。 “输出”栏以(当前码字W, 当前字符C)简化为(W, C)的形式输出。表4-14 表4-14 表4-13