跳至内容

JPEG - 想法与实践 / 压缩与编码

来自维基教科书,开放的书籍,开放的世界

文件的压缩

[编辑 | 编辑源代码]

对于每个 sxs 方块和三个 YCbCr 坐标(或分量),在完成余弦变换和量化后,我们得到一个按之字形原则排序的 s2 个整数序列。在每个序列中,我们将第一个数字 - DC 系数 - 用它与前一个 DC 系数的差值来代替(即前一个 sxs 方块的相同分量)。然而,由于这些整数中的大多数(当方块遍历图像时)通常为零,因此将它们以特定方式引入文件是可取的,即让每隔一个整数为真实数字,而其他整数为零的数量(连续的)。这些整数(在新序列中)可以为负数,并且可以是任意大小,现在我们的任务是将这些整数转换为尽可能短的比特序列。由于文件由字节组成,因此我们必须将所得的比特流分成 8 比特块,并将这些比特块转换为字节。

由于允许整数为任意大小,因此我们必须将每个整数表示为两个比特序列对,第一个序列以某种方式(可能以编码形式)对应于一个自然数,该自然数表示第二个序列的长度,第二个序列是该数字的二进制表达式。第一个比特序列可以简单地是自然数的二进制表达式,但这些序列必须具有相同的长度,例如 4。由于 4 比特可以表示从 1 到 16 的自然数,并且通过使用不超过 16 个比特,我们可以表示高达 216-1 = 65535 的整数,因此这种方法可用于颜色变化很大或不是太大的图片。如果你正在编写 JPEG 程序,你应该从这种方法开始,并在程序工作后,再引入下面描述的方法之一,因为它是一种简单的方法,可以将合适的照片压缩到其 BMP 尺寸的 15%。但是,如果程序要能够处理各种图片,则必须将 4 比特扩展到 5 比特,即使 4 比特对于表示这些长度来说也是太多了,因为大多数长度都相当短。如果我们有一种方法,可以使这些对的第一序列(长度)可变,那就更好了。

我们的数字(表示比特数)是自然数,我们希望以这样的方式用比特序列来表示它们:最常用的数字对应于最短的序列,并且我们必须有一种方法能够确定何时一个序列终止。第一个描述了一种原理,该原理可以将给定集合的元素(在我们的案例中是自然数集合)与比特序列一一对应,使序列的长度与元素的使用频率成反比,这是香农和法诺在 1949 年提出的编码方法。

香农-法诺编码

[编辑 | 编辑源代码]

假设我们有一个过程,其结果是信息的长串,这些信息使用给定集合的元素来表达。我们希望用由比特序列组成的集合来代替这个集合,这样最常用的序列是最短的。为此,你可以执行以下操作:将集合分成两部分,使每部分中的元素使用频率大致相同。对于第一部分中的元素,让序列以 0 开头,对于第二部分中的元素,让序列以 1 开头。将这两部分中的每部分再分成两部分,使每部分中的元素使用频率大致相同,并让下一个比特对于第一部分中的元素为 0,对于第二部分中的元素为 1,依此类推。

在我们的案例中,集合是自然数集合,此类数字的含义是它表示一个整数的二进制表达式长度。自然数的使用频率与其大小成反比,我们应该对频率进行理论化,或者测试一些随机图片并取平均值。但是,在这种情况下,我们只会根据我们想要获得一个简单公式的愿望来进行猜测:我们假设 {1, 2, 3}(的元素)使用频率与其他元素相同,{1} 的使用频率与 {2, 3} 相同,{4, 5} 的使用频率与 {6, 7, ...} 相同,{6, 7} 的使用频率与 {8, 9, ...} 相同,依此类推。在这些假设下,自然数的编码将如下所示

1        00
2        010
3        011
4        100
5        101
6        1100
7        1101
8        11100
9        11101
10      111100
11      111101
12      1111100
13      1111101
等等。

注意,对于大于 3 的 n,第一个 0 之前的 1 的数量是 n/2 的整数部分减 1,并且在这个 0 之后,只有一个比特:n 为偶数时为 0,n 为奇数时为 1。当(在比特流中)我们知道一些后面的比特形成这样的比特块时,我们可以很容易地确定它何时终止,以及确定相应的自然数:如果第一个比特是 0,则后面会跟一个比特;如果它是 0,则数字是 1,如果它是 1,则后面会跟一个比特;如果它是 0,则数字是 2,如果它是 1,则数字是 3。如果第一个比特是 1,我们统计第一个 0 之前的 1 的数量,我们知道序列在这个 0 之后立即终止。我们将 1 加到 1 的数量上,并将这个数字乘以 2。然后,如果最后一个比特是 0,则自然数是这个数字,如果最后一个比特是 1,则自然数是下一个数字。

余弦变换和量化产生的整数(每个 sxs 方块和每个分量 s2 个整数),当方块遍历图像时,以特定方式写入,即让每隔一个整数为真实数字,而其他整数表示零的数量(可能是零)。此外,我们将这些整数写成比特序列,每个序列都有两个部分:第一部分以编码形式写入,对应于一个自然数,该自然数的目的是表示第二部分的比特数,即该整数的二进制表达式。但由于整数(“真实”类型)可以为负数,因此我们必须以某种方式表示这一点。你可能认为我们必须为此使用一个额外的比特,但实际上没有必要:数字表达式的第一个数字(即最高有效位)始终为 1,我们可以通过将这个 1 替换为 0 来表示该数字为负数。所得的比特流最终被分成 8 比特块,并作为字节写入文件 - 可能扩展最后一个块(用 0 或 1)使其成为 8 比特块。

我们在演示程序中使用了这种简单的编码方法,由于它可以将合适的照片压缩到其原始尺寸的 6-12%,因此我们在这里没有看到选择使用更复杂的编码方法的理由。不过,我们现在将简单介绍一下 JPEG 使用的编码方法(将在“第二部分”中详细说明)。

霍夫曼编码

[编辑 | 编辑源代码]

如果我们花更多时间研究频率,我们可以得到一个更有效的程序。然而,香农-法诺方法并不是最好的方法。最有效的编码方法是霍夫曼方法,该方法由霍夫曼于 1951 年发明。这种方法在 JPEG 过程中几乎是通用的。我们将在“第二部分”中对其进行描述,读者将了解为什么我们在这里回避它:它不容易描述和说明,编码和解码需要更多操作。此外,在 JPEG 过程中,DC 数和 AC 数以不同的方式进行霍夫曼编码,并且 Y 分量和颜色分量使用不同的霍夫曼表。

霍夫曼编码方法可以被证明是最有效的,但这种优越性假设所有数据都以相同的方式进行编码,而 JPEG 压缩并非如此。因此,JPEG 委员会除了霍夫曼编码之外,还规定了所谓的“算术”编码,它可以压缩图片更多。然而,算术编码速度较慢,并且使用得不多 - 部分原因是它已获得专利。

华夏公益教科书