JPEG 格式的工作原理

JPEG 图像在我们的数字生活中无处不在,但在这种意识的表象背后是删除人眼无法感知的细节的算法。 结果是以最小的文件大小获得最高的视觉质量 - 但这一切到底是如何工作的呢? 让我们看看我们的眼睛看不到的到底是什么!

JPEG 格式的工作原理

人们很容易认为向朋友发送照片的能力是理所当然的,而不用担心他们使用的设备、浏览器或操作系统 - 但情况并非总是如此。 到 1980 世纪 XNUMX 年代初,计算机可以存储和显示数字图像,但对于实现这一目标的最佳方法存在许多相互竞争的想法。 您不能只是将图像从一台计算机发送到另一台计算机并希望它能起作用。

为了解决这个问题,1986年成立了一个由世界各地的专家组成的委员会,名为“摄影专家联合组»(联合图像专家组,JPEG)是国际标准化组织 (ISO) 和国际电工委员会 (IEC) 这两个总部位于瑞士日内瓦的国际标准组织共同努力成立的。

一群名为 JPEG 的人于 1992 年创建了 JPEG 数字图像压缩标准。 任何使用过 Internet 的人都可能遇到过 JPEG 编码的图像。 这是编码、发送和存储图像的最常见方式。 从网页到电子邮件再到社交媒体,JPEG 每天被使用数十亿次——几乎每次我们在线查看或发送图像时。 如果没有 JPEG,网络的色彩会更少、速度会更慢,而且猫的图片可能会更少!

本文介绍如何解码 JPEG 图像。 换句话说,需要将计算机上存储的压缩数据转换为屏幕上显示的图像。 这是值得了解的,不仅因为它对于理解我们每天使用的技术很重要,而且因为通过解锁压缩级别,我们可以更多地了解感知和视觉,以及我们的眼睛对哪些细节最敏感。

另外,这样玩弄图像也是非常有趣的。

JPEG 格式的工作原理

探寻 JPEG 内部

在计算机上,所有内容都存储为二进制数序列。 通常,这些位(零和一)以八个为一组组成字节。 当您在计算机上打开 JPEG 图像时,某些东西(浏览器、操作系统或其他东西)必须对字节进行解码,将原始图像恢复为可以显示的颜色列表。

如果你下载了这个甜蜜的 一只猫的照片 用文本编辑器打开它,你会看到一堆不连贯的字符。

JPEG 格式的工作原理
在这里,我使用 Notepad++ 检查文件的内容,因为 Windows 上的常规文本编辑器(如 Notepad)会在保存后损坏二进制文件,并且不再满足 JPEG 格式。

在文字处理程序中打开图像会使计算机感到困惑,就像当您揉眼睛并开始看到颜色斑点时会混淆您的大脑一样!

您看到的这些点被称为 光幻视,并且不是光刺激或心灵产生幻觉的结果。 它们的发生是因为您的大脑认为视神经中的任何电信号都传达有关光的信息。 大脑需要做出这些假设,因为无法知道信号是声音、视觉还是其他东西。 体内的所有神经都传输完全相同的电脉冲。 通过对眼睛施加压力,您会发送非视觉信号,但会激活眼睛的受体,您的大脑将其解释为视觉信号(在这种情况下是错误的)。 压力真的是看得见摸得着!

想想计算机与大脑有多么相似,这很有趣,但它也是一个有用的类比,可以说明数据的含义(无论是通过神经传递到身体还是存储在计算机上)在多大程度上取决于它的解释方式。 所有二进制数据均由 XNUMX 和 XNUMX 组成,这是可以传达任何类型信息的基本组成部分。 您的计算机通常会使用文件扩展名等线索来找出如何解释它们。 现在我们强制它将它们解释为文本,因为这是文本编辑器所期望的。

要了解如何解码 JPEG,我们需要查看原始信号本身 - 二进制数据。 这可以使用十六进制编辑器来完成,或者直接在 原创文章网页! 有一个图像,旁边的文本字段中是其所有字节(标题除外),以十进制形式呈现。 您可以更改它们,脚本将重新编码并即时生成新图像。

JPEG 格式的工作原理

通过使用这个编辑器,您可以学到很多东西。 例如,您能说出像素以什么顺序存储吗?

这个例子的奇怪之处在于,改变一些数字根本不会影响图像,但是,例如,如果你在第一行将数字 17 替换为 0,那么照片将完全毁掉!

JPEG 格式的工作原理

其他更改(例如将 7 行上的 1988 替换为数字 254)会更改颜色,但仅更改后续像素的颜色。

JPEG 格式的工作原理

也许最奇怪的是,有些数字不仅改变颜色,还改变图像的形状。 将第 70 行中的 12 更改为 2,然后查看图像的顶行以了解我的意思。

JPEG 格式的工作原理

而且无论您使用什么 JPEG 图像,在编辑字节时您总会发现这些神秘的国际象棋图案。

使用编辑器时,很难理解如何从这些字节重新创建照片,因为 JPEG 压缩由三种不同的技术组成,并按级别顺序应用。 我们将分别研究每一个,以揭开我们所看到的神秘行为。

JPEG 压缩的三个级别:

  1. 颜色子采样.
  2. 离散余弦变换和采样.
  3. 行程编码, 三角洲 и 霍夫曼

为了让您了解压缩的程度,请注意上图代表 79 个数字,即约 819 KB。 如果我们在不压缩的情况下存储它,每个像素将需要三个数字 - 分别代表红色、绿色和蓝色分量。 这将达到 79 个数字,或大约。 917 KB。 经过JPEG压缩后,最终文件缩小了700倍以上!

事实上,该图像还可以压缩得更多。 下面是并排的两张图片 - 右边的照片已被压缩至 16 KB,即比未压缩版本小 57 倍!

JPEG 格式的工作原理

如果你仔细观察,你会发现这些图像并不相同。 两张都是JPEG压缩的图像,但右边一张的体积要小得多。 它看起来也有点糟糕(看看背景颜色方块)。 这就是 JPEG 也称为有损压缩的原因。 在压缩过程中,图像会发生变化并丢失一些细节。

1. 颜色子采样

这是仅应用第一级压缩的图像。

JPEG 格式的工作原理
(互动版 - 在 原来的 文章)。 删除一个数字就会破坏所有颜色。 然而,如果恰好删除六个数字,则对图像几乎没有影响。

现在这些数字更容易解读了。 这几乎是一个简单的颜色列表,其中每个字节恰好改变一个像素,但同时它已经是未压缩图像大小的一半(在这种减小的大小下将占用大约 300 KB)。 你能猜出为什么吗?

您可以看到这些数字并不代表标准的红色、绿色和蓝色分量,因为如果我们用零替换所有数字,我们将得到绿色图像(而不是白色)。

JPEG 格式的工作原理

这是因为这些字节代表Y(亮度),

JPEG 格式的工作原理

Cb(相对蓝度),

JPEG 格式的工作原理

和 Cr(相对红度)图片。

JPEG 格式的工作原理

为什么不使用RGB? 毕竟,这就是大多数现代屏幕的工作原理。 您的显示器可以显示任何颜色,包括红色、绿色和蓝色,每个像素具有不同的强度。 通过以全亮度打开所有三个来获得白色,通过关闭它们来获得黑色。

JPEG 格式的工作原理

这也与人眼的工作方式非常相似。 我们眼睛里的颜色感受器被称为“锥体”,并分为三种类型,每种类型对红色、绿色或蓝色更敏感[S型视锥细胞对紫蓝色敏感(S来自英语Short - 短波光谱),M -型 - 位于光谱的绿黄色(M 来自英语 Medium - 中波)部分,L 型 - 位于光谱的黄红色(L 来自英语 Long - 长波)部分。 这三种视锥细胞(和视杆细胞,对光谱的翠绿色部分敏感)的存在赋予人色觉。 / 约。 译]。 ,我们眼睛中的另一种感光器,能够检测亮度的变化,但对颜色更敏感。 我们的眼睛大约有 120 亿个视杆细胞,而只有 6 万个视锥细胞。

这就是为什么我们的眼睛更擅长检测亮度变化而不是颜色变化。 如果将颜色与亮度分开,您可以去除一点颜色,而没有人会注意到任何东西。 色度子采样是以比亮度分量更低的分辨率表示图像颜色分量的过程。 在上面的示例中,每个像素恰好具有一个 Y 分量,并且每个单独的四个像素组恰好具有一个 Cb 和一个 Cr 分量。 因此,图像包含的颜色信息比原始图像少四倍。

YCbCr 色彩空间不仅用于 JPEG。 它最初是在 1938 年为电视节目而发明的。 并不是每个人都有彩色电视,因此将颜色和亮度分开可以让每个人都获得相同的信号,而没有颜色的电视则仅使用亮度分量。

因此,从编辑器中删除一个数字会完全破坏所有颜色。 组件以 YYYY Cb Cr 的形式存储(事实上,不一定按照该顺序 - 存储顺序在文件头中指定)。 删除第一个数字将导致 Cb 的第一个值被视为 Y,Cr 被视为 Cb,一般来说,您将产生切换图片所有颜色的多米诺骨牌效应。

JPEG 规范并不强制您使用 YCbCr。 但大多数文件都使用它,因为它可以生成比 RGB 更好的下采样图像。 但你不必相信我的话。 在下表中亲自查看每个单独分量的子采样在 RGB 和 YCbCr 中的样子。

JPEG 格式的工作原理
(互动版 - 在 原来的 文章)。

蓝色的去除不如红色或绿色的去除那么明显。 这是因为您的眼睛中有 64 万个视锥细胞,其中大约 32% 对红色敏感,2% 对绿色敏感,XNUMX% 对蓝色敏感。

Y 分量(左下)的下采样效果最为明显。 即使是很小的变化也是显而易见的。

将图像从 RGB 转换为 YCbCr 不会减小文件大小,但确实可以更轻松地找到可删除的不太明显的细节。 有损压缩发生在第二阶段。 它基于以更可压缩的形式呈现数据的想法。

2. 离散余弦变换和采样

在很大程度上,这种级别的压缩就是 JPEG 的全部内容。 将颜色转换为 YCbCr 后,各个分量被单独压缩,因此我们可以只关注 Y 分量。这是应用该层后 Y 分量字节的样子。

JPEG 格式的工作原理
(互动版 - 在 原来的 文章)。 在交互式版本中,单击像素会将编辑器滚动到代表该像素的行。 尝试从末尾删除数字或向某个数字添加几个零。

乍一看,它看起来压缩得很糟糕。 图像中有 100 个像素,需要 000 个数字来表示它们的亮度(Y 分量)——这比根本不压缩更糟糕!

但请注意,这些数字大部分为零。 此外,可以在不改变图像的情况下删除行末尾的所有零。 大约还剩下 26 个号码,这几乎少了 000 倍!

这一关包含了国际象棋图案的秘密。 与我们见过的其他效果不同,这些图案的出现并不是故障。 它们是整个图像的构建块。 编辑器的每一行恰好包含 64 个数字,即与 64 个独特模式的强度相对应的离散余弦变换 (DCT) 系数。

这些图案是根据余弦图形成的。 以下是其中一些的外观:

JPEG 格式的工作原理
8 赔率中的 64 赔率

下图显示了所有 64 种模式。

JPEG 格式的工作原理
(互动版 - 在 原来的 文章)。

这些图案特别重要,因为它们构成了 8x8 图像的基础。 如果您不熟悉线性代数,这意味着任何 8x8 图像都可以由这 64 个图案组成。 DCT 是将图像划分为 8x8 块并将每个块转换为这 64 个系数的组合的过程。

任何图像都可以由 64 种特定图案组成,这似乎很神奇。 然而,这等于说地球上的任何地方都可以用两个数字来描述——纬度和经度[表示半球/大约。 译]。 我们通常认为地球表面是二维的,所以我们只需要两个数字。 8x8 图像有 64 个维度,因此我们需要 64 个数字。

目前尚不清楚这对压缩有何帮助。 如果我们需要 64 个数字来表示 8x8 图像,为什么这比仅存储 64 个亮度分量更好? 我们这样做的原因与将三个 RGB 数字转换为三个 YCbCr 数字的原因相同:它允许我们删除微妙的细节。

由于 JPEG 将 DCT 应用于 8x8 块,因此很难准确看出在此阶段删除了哪些细节。 然而,没有人禁止我们把它应用到整个画面上。 以下是应用于整个图片的 Y 分量的 DCT 的样子:

JPEG 格式的工作原理

可以从末尾删除超过 60 个数字,而照片几乎没有明显变化。

JPEG 格式的工作原理

但请注意,如果我们将前五个数字归零,差异将很明显。

JPEG 格式的工作原理

开头的数字代表图像中的低频变化,我们的眼睛最能捕捉到这些变化。 接近末尾的数字表示更难以注意到的高频变化。 为了“看到眼睛看不到的东西”,我们可以通过将前 5000 个数字归零来隔离这些高频细节。

JPEG 格式的工作原理

我们可以看到图像中每个像素发生最大变化的所有区域。 猫的眼睛、胡须、毛圈毯和左下角的阴影都很引人注目。 您可以进一步将前 10 个数字清零:

JPEG 格式的工作原理

20 000:

JPEG 格式的工作原理

40 000:

JPEG 格式的工作原理

60 000:

JPEG 格式的工作原理

这些高频细节在压缩阶段被 JPEG 删除。 将颜色转换为 DCT 系数不会造成任何损失。 损失发生在采样步骤,其中高频或接近零的值被删除。 当您降低 JPEG 保存质量时,程序会增加删除值数量的阈值,这会减小文件大小,但会使图片更加像素化。 这就是为什么第一部分中的图像(小了 57 倍)看起来像这样。 与更高质量的版本相比,每个 8x8 块由少得多的 DCT 系数表示。

您可以创建像渐变流图像这样很酷的效果。 您可以显示模糊的图片,随着下载的系数越来越多,该图片会变得越来越详细。

这里只是为了好玩,仅使用 24 个数字即可得到以下结果:

JPEG 格式的工作原理

或者只是 5000:

JPEG 格式的工作原理

虽然很模糊,但还是能认出来!

3.游程编码、delta和Huffman

到目前为止,压缩的所有阶段都是有损的。 相反,最后一个阶段没有损失地进行。 它不会删除信息,但会显着减小文件大小。

如何在不丢失信息的情况下压缩某些内容? 想象一下我们如何描述一个简单的黑色矩形 700 x 437。

JPEG 为此使用 5000 个数字,但可以获得更好的结果。 您能想象一种编码方案可以用尽可能少的字节描述这样的图像吗?

我能想到的最小方案使用四个:三个表示颜色,第四个表示该颜色有多少个像素。 以这种压缩方式表示重复值的想法称为游程编码。 它是无损的,因为我们可以将编码数据恢复为其原始形式。

带有黑色矩形的 JPEG 文件远大于 4 字节 - 请记住,在 DCT 级别,压缩应用于 8x8 像素块。 因此,至少每 64 个像素需要一个 DCT 系数。 我们需要一个,因为游程长度编码不是存储一个 DCT 系数后跟 63 个零,而是允许我们存储一个数字并指示“所有其他数字都是零”。

增量编码是一种技术,其中每个字节包含与某个值的差异,而不是绝对值。 因此,编辑某些字节会更改所有其他像素的颜色。 例如,不是存储

12 13 14 14 14 13 13 14

我们可以从 12 开始,然后简单地指出需要加或减多少才能得到下一个数字。 增量编码中的序列采用以下形式:

12 1 1 0 0 -1 0 1

转换后的数据并不比原始数据小,但更容易压缩。 在行程编码之前应用增量编码可以提供很大帮助,同时仍然是无损压缩。

Delta 编码是 8x8 块之外使用的少数技术之一。 在 64 个 DCT 系数中,有一个只是常数波函数(纯色)。 它代表亮度分量的每个块的平均亮度,或者Cb分量的平均蓝色度,等等。 每个 DCT 块的第一个值称为 DC 值,每个 DC 值都相对于前一个 DC 值进行增量编码。 因此,改变第一个块的亮度将影响所有块。

最后的谜团仍然存在:改变单数如何完全破坏整个画面? 到目前为止,压缩级别还没有这样的属性。 答案就在 JPEG 标头中。 前 500 个字节包含有关图像的元数据 - 宽度、高度等,但我们尚未使用它们。

如果没有标头,则几乎不可能(或非常困难)解码 JPEG。 看起来好像我正在试图向你描述这幅画,并且我开始发明词语来传达我的印象。 描述可能会非常简洁,因为我可以发明具有我想要传达的含义的单词,但对其他人来说它们没有意义。

这听起来很愚蠢,但事实确实如此。 每个 JPEG 图像都使用特定的代码进行压缩。 代码字典存储在标头中。 这种技术称为霍夫曼码,词汇称为霍夫曼表。 在标头中,该表用两个字节标记 - 255,然后是 196。每个颜色分量都可以有自己的表。

对表格的更改将从根本上影响任何图像。 一个很好的例子是将第 15 行更改为 1。

JPEG 格式的工作原理

发生这种情况是因为表指定了应如何读取各个位。 到目前为止,我们只处理了十进制形式的二进制数。 但这掩盖了这样一个事实:如果您想将数字 1 存储在一个字节中,它将看起来像 00000001,因为每个字节必须恰好有 XNUMX 位,即使只需要其中一位。

如果您有很多小数字,这可能会浪费大量空间。 霍夫曼码是一种技术,可以让我们放宽每个数字必须占用八位的要求。 这意味着如果您看到两个字节:

234 115

然后,根据霍夫曼表,这些可能是三个数字。 要提取它们,您需要首先将它们分解为单独的部分:

11101010 01110011

然后我们查看表格找出如何对它们进行分组。 例如,这可能是前六位 (111010) 或十进制的 58,后跟五位 (10011) 或 19,最后是最后四位 (0011) 或 3。

因此,理解这个压缩阶段的字节是非常困难的。 字节并不代表它们看起来的样子。 我不会在本文中详细介绍如何使用该表,但是 物料 网上关于这个问题 够了.

利用这些知识,您可以做的一个有趣的技巧是将标头与 JPEG 分开并单独存储。 事实上,事实证明只有您可以读取该文件。 Facebook 这样做是为了让文件变得更小。

还可以做的就是对霍夫曼表进行相当大的更改。 对于其他人来说,它看起来就像一张破碎的图片。 只有您知道修复它的神奇方法。

我们总结一下:那么解码 JPEG 需要什么? 必要的:

  1. 从标头中提取霍夫曼表并解码位。
  2. 提取每个 8x8 块的每个颜色和亮度分量的离散余弦变换系数,执行逆游程长度和增量编码变换。
  3. 根据系数组合余弦以获得每个8x8块的像素值。
  4. 如果执行了子采样,则缩放颜色分量(此信息位于标题中)。
  5. 将每个像素的 YCbCr 值转换为 RGB。
  6. 在屏幕上显示图像!

只是为了看一张与猫的照片而做的认真的工作! 然而,我喜欢它的是它展示了 JPEG 技术是如何以人为本的。 它基于我们感知的特殊性,使我们能够实现比传统技术更好的压缩。 现在我们了解了 JPEG 的工作原理,我们可以想象如何将这些技术转移到其他领域。 例如,视频中的增量编码可以显着减小文件大小,因为通常存在帧与帧之间不发生变化的整个区域(例如背景)。

文章中使用的代码,已打开,包含有关如何用自己的图片替换图片的说明。

来源: habr.com

添加评论