前言:在接触文本隐写研究领域时了解到这本书。本书可算作《数据压缩》的入门书籍之一,这本书对熵编码、变长编码、统计编码、自适应统计编码、字典编码、上下文编码等常用编码方式的定义及来源进行介绍,对不同场景下不同格式的压缩数据有针对性地分析,笔风幽默,强烈推荐!本书中共有15个章节,本人主要阅读了前9个章节,以下是阅读本书过程中的一些笔记,供大家参考。
无损方法
• 去掉重复数据(LZ算法)
• 熵压缩(哈夫曼编码、算术编码)
有损方法
• 降低精度(截断或降采样)
• 图像 / 视频压缩
• 音频压缩
数据压缩无非是用最紧凑的方式来表示数据。
数据压缩算法有5类:变长编码(variable-length codes,VLC)、统计压缩(statistical compression)、字典编码(dictionary encodings)、上下文模型(context modeling)和多上下文模型(multicontext modeling)。所有这5类算法都有很多变种。
1948年,香农又发表了《通信的数学理论》,在这篇论文中他详细论述了发送者怎样对要发送的信息进行编码才能达到最佳效果,由此开创了信息论(information theory)这一全新的学术领域。对消息进行编码有多种方式,“字母表”与“摩尔斯码”只是其中常见的两种。但是对每一个特定的消息来说,都有一个最佳的编码方式,这里的“最佳”指的是传递消息时用到的字母或者符号(也可以说是二进制位,即信息的单位)最少。至于这里说的“最少”到底是多少,则取决于消息所包含的信息内容。香农发明了一种度量消息所携带信息内容的方法,并称之为信息熵(information entropy)。数据压缩其实是香农的研究工作的一项实际应用,它所研究的问题是,“在保证信息能恢复的前提下,我们能将消息变得多么紧凑”。
对数据进行压缩,通常有两个思路:
60年来的数据压缩研究都可以归结到上面两个重要思路上,数据压缩中的每一个算法都聚焦于解决这两件事情中的一件。每一个压缩算法,要么通过打乱符号或减少符号的数量,将数据转换得更便于压缩;要么利用其中一些符号比其他符号更常见的事实,通过用最少的位数编码最常见的符号,实现压缩的目的。
虽然数据压缩的思路简单明了,但在实际应用中数据压缩很复杂。其原因在于,由于要压缩的数据的类型不同,针对上述两条思路中的每一条,能采用的方法都有很多。因此,进行实际的数据压缩时,需要综合考虑以下因素。
互联网诞生的那一年,也就是1978年。
在很长一段时间内,莱娜图是用来测试图像压缩算法的标准测试图。幸运的是,从此以后,很少再出现这样有争议性的图像语料库。(我们两位作者则更喜欢使用柯达公司的图像测试集。)然而即使是今天,仍然有很多图像压缩方面的论文将莱娜图用作检验算法的标准。
数据压缩所做的无非就是尽可能减少表示特定数据集时所需的二进制位数量。
根据信息论的观点,一个数值所包含的信息内容等于,为了在一个集合中唯一地确定这个数值,需要做出的二选一(是/否)决定的次数。
给定任意一个整数,我们都能将它转换为二进制形式。然而令人遗憾的是,给定一个整数,如果不经过二进制转换这一过程,我们很难直接知道它需要占几个二进制位。转换过程很无趣,但好在数学家已准备了下面的公式,让我们可以更轻松地处理这个问题:
L
O
G
2
(
x
)
=
c
e
i
l
(
l
o
g
(
x
+
1
)
/
l
o
g
(
2
)
)
LOG2(x) = ceil(log(x+1)/log(2))
LOG2(x)=ceil(log(x+1)/log(2)) : 表示一个数所需要的二进制位数

给定任意一个十进制整数,通过计算它对应的LOG2函数的值,我们就能知道用二进制来表示这个数最少需要多少二进制位。香农将一个变量对应的LOG2函数的值定义为它的熵(entropy),也就是用二进制来表示这个数所需的最少二进制位数。
数值的LOG2表示形式虽然高效,但对于制造计算机元件的方式来说并不实用。这其中的问题在于,如果用最少的二进制位数来表示一个数,在解码相应的二进制字符串时会产生混乱(因为我们并不知道该数对应的LOG2长度),会与硬件的执行性能相冲突,两者不能兼顾。现代计算机采用了折中的方案,用固定长度的二进制位数来表示大小不同的整数。最基本的存储单元是一个字节,由8个二进制位组成。在现代编程语言中,通常可用的整数的存储类型包括:短整型16个二进制位、整型32个二进制位、长整型64个二进制位。因此,对于十进制数10,虽然其对应的二进制数为1010,但在实际存储中是短整型,在计算机中的实际表示为0000000000001010。显然,这样做浪费了很多的二进制位。

https://rosettacode.org/wiki/Entropy 熵的各种语言实现。
为了使表示某个数据集所需的二进制位数最少,数据集中的每个符号平均所需的最小二进制位数就是熵。
从本质上来说,香农所定义的熵,是以一种倒排序的方式建立在数据流中每个符号出现概率的估算之上的。
总的来说,一个符号出现得越频繁,它对整个数据集包含的信息内容的贡献就会越少,这看起来似乎完全违背直觉。
数据集中包含的总体信息很少,因此对应的熵值也很小。
突破熵的关键在于,通过利用数据集的结构信息将其转换为一种新的表示形式,而这种新表示形式的熵比源信息的熵小。
需要记住的是,熵定义的只是在对数据流进行编码时,每个符号平均所需的最小二进制位数。这就意味着,有些符号需要的二进制位数比熵小,而有些符号需要的二进制位数则比熵大。
柯尔莫哥洛夫复杂性(Kolmogorov complexity),度量的是确定一个对象所需要的计算资源。
摩尔斯码根据各个符号在英语中出现的概率来为其分配点和划。一个符号出现得越频繁,其对应的编码就越短。即使是追溯到19世纪,这也是对符号分配变长编码(variable-length codes,VLC)的最初实现之一,其目的则在于减少传输信息过程中所需要的总工作量。
为了进行数据压缩,我们的目的很简单:给定一个数据集中的符号,将最短的编码分配给最可能出现的符号。
设计VLC集的码字时,必须考虑两个原则:一是越频繁出现的符号,其对应的码字越短;二是码字需满足前缀性质。
统计编码算法通过数据集中符号出现的概率来进行编码使结果尽可能与熵接近。
哈夫曼编码:
算术编码:

主流的统计编码方法有哈夫曼编码和算术编码,但ANS(非对称数字系统编码)改变了一切。虽然它在数据压缩领域里出现的时间还不长,但是已开始取代过去20多年里占据主流地位的哈夫曼编码和算术编码。例如,ZHuff、LZTurbo、LZA、Oodle和LZNA这些压缩工具已开始使用ANS。鉴于其速度和性能,ANS成为主要的编码方法似乎只是时间问题。实际上,在2013年,这一算法又出现了一个被称为有限状态熵(Finite State Entropy,FSE)的更注重性能的版本,它只使用加法、掩码和移位运算,使ANS对开发人员更具吸引力。它的性能是如此强大,以至于2015年推出了一款名为LZFSE的GZIP变种,作为苹果下一代iOS版本的核心API。


给定一组相邻的符号集,对它们进行某种方式的变换使其更容易压缩。我们通常称这样的变换为“上下文变换”(contextual transform),因为在思考数据的理想编码方式时,这些方法考虑到了邻近符号的影响。
这些变换的目标是一致的,即通过对这些信息进行某种方式的变换,使统计编码算法对其进行压缩时更高效。
变换数据的方法有很多种,但其中有3种对现代的数据压缩来说最为重要,即行程编码(run-length encoding,RLE)、增量编码(delta coding)和伯罗斯–惠勒变换(Burrows-Wheeler transform,BWT)。
增量编码的目的就是缩小数据集的变化范围。更确切地说,是为了减少表示数据集中的每个值所需要的二进制位数。
(其中,游程编码(Run-Length Encoding)比较适合针对数据中冗余部分比较多的情况)
相关资料