之前一直很好奇图片和视频是如何压缩的,由于视频格式会更复杂,所以先从JPEG下手

因为网上资料太难找太分散,有些又看不太懂,所以根据自己的理解整理了一下

JPEG简介

JPEG(Joint Photographic Experts Group),全称为联合图像专家小组,同时也是我们生活中很常见的一种图像格式,一般以.jpg作扩展名。JPEG采用了多种方法来对图像进行有损压缩,从而使得观感相差不大的情况下减小了较多的文件体积


压缩流程

常见的JPEG图像数据按照如下流程进行压缩:

flowchart TD
原始图像 --> 8x8分块 --> DCT变换 --> 量化 --> Z字形扫描 --> 对系数编码 --> 熵编码 --> 压缩数据
subgraph 对系数编码
对AC系数游程编码
对DC系数差分脉冲编码
end

1.分块

JPEG中会首先对图像以8x8的块为单位划分,不足8x8的会填充剩余部分。不过具体填充什么我没研究过,但是解码显示出来的时候会忽略掉这部分,所以应该是无所谓的。

对图像进行8x8分块也是为了方便下一步进行DCT变化

2.DCT变换

DCT(Discrete Cosine Transform,离散余弦变换)是一种把数据从时域转化到频域的数学方法,把图像数据转换到频域之后,我们就可以从中分离出各种频率的信息。

DCT变换过后数据按照不同频率进行划分,得到的数据实际上是不同频率余弦波的系数,把这些系数乘上对应频率的余弦函数就能得到原来的数据

但要注意的是DCT变换过后数据的大小也不会发生改变,相当于把数据用另一种方式表示,就好像同一句话你用普通话和方言讲出来就是两种表达方式。

3.量化

DCT变换后我们就能区分不同频率的信息了,其中高频信息是图像中的一些细节,将变换后的高频部分系数置0则可以去除这些细节。因为人眼对高频信息不是很敏感,所以观感差距不会很大,就像你有轻度的近视,但不影响你看清一个物体。

比如下图

我们会发现,假如只保留DCT变换后左上角的低频部分,还原出来的图像其实和原图差距不大;而如果看保留高频后还原出来的图像,仔细看会发现只留下了物体边缘等细节部分的一些痕迹(也就是高频部分)

此时选择去除哪些频率的信息就成了关键点,我们要给图片选择一个“近视程度”来让减少高频信息。好在JPEG标准已经准备好了几种量化表,对应了不同的图像质量,我们只需要把DCT变换后的数据除以量化表中的对应项就完成了量化操作。

4.Z字形扫描

对数据进行过量化之后仍然没有减小体积,因为去除的高频系数只是被替换成了0,占用的空间还是不变,这时候就轮到Z字形扫描(Zig-Zag Scan)出场了。

Z字形扫描就如同字面意思一样,按照上图顺序重新排序顺序。因为高频信息聚集在右下角,按照这种方式扫描后就可以把被替换成0的高频系数连续排列了

顺带一提,知名音视频编解码工具FFmpeg的图标就来源于Z字形扫描

5.对DC和AC系数编码

什么是DC系数和AC系数?

简单地说,DC系数就是一个块中第一个数,而AC系数就是剩余的数



(图源网络)

上图中1就是DC系数,2-9就是AC系数

对AC系数编码

前面的Z字形扫描完成了准备操作,真正压缩则是交给游程编码(Run Length Encode, RLE)

游程编码以两个数为一组,第一个数表示第二个数的重复次数,对于压缩经过Z字形扫描过后,存在大量连续的0的数据来说再合适不过了

假如直接舍弃后面一半的信息,对画质影响不大的情况下,减少了差不多一半的数据量!

对DC系数编码

对于DC系数,采用的是一种叫差分脉冲编码调制(Differential Pulse code modulation,DPCM)的编码方式

听起来很高深,实际上就是把DC系数换成这一个块和上一个块的DC系数的差值。比如上一个块的DC系数是20,这一个块的DC系数是10,那就写入-10。如果是第一个块,那就不用变(或者也可以看作前面有一个不存在的DC系数为0)。

JPEG中DC系数和AC系数的存储格式:

在实际存储的数据中,一个系数分成两部分

第一部分长度为一个byte。

对于AC系数来说采用了游程编码,低四位表示第二部分的长度(以bit为单位),高四位表示这一数据前0的个数;

对于DC系数来说这一整个byte就表示第二部分数据的长度(也是以bit为单位)

第二部分的第1位是符号位,0表示负数,1表示正数。如果是正数,无需处理;如果是负数,则是对原数包括符号位在内的每一位取反的结果

6.熵编码

最后是对所有的数据进行熵编码,一般用的是范式霍夫曼编码(Canonical Huffman Code)。

范式霍夫曼编码基于霍夫曼编码,霍夫曼编码核心思想是为出现频率更高的数据分配更短的编号,为出现频率低的数据分配更长的编号,这样就可以实现无损压缩数据。而由于霍夫曼编码以bit为单位,长度又不确定,读取时无法区分,所以采用了范式霍夫曼编码。

JPEG中范式霍夫曼编码的存储格式:

首先用一个大小为16个字节的数组存储编码后数据中对应长度为1bit~16bit的原始数据的种类数,后面按同样的顺序紧跟所有种类的原始数据

而编码后的数据要通过如下方式得到:

数从长度为1bit的0开始,长度相同时每编码一个数就+1,长度每增加1bit就要左移1位

当然,JPEG标准中也给出了参考的范式霍夫曼编码的对照表

参考资料

JPEG解码系列博客:多媒体-编解码 - 随笔分类 - OnlyTime_唯有时光 - 博客园 (cnblogs.com)

JPEG标准:Microsoft Word - T081E.DOC (w3.org)

白话文理解DCT离散余弦变换 - 乂墨EMO - 博客园 (cnblogs.com)

一个Rust写的JPEG解码器:MROS/jpeg_tutorial: 跟我寫 JPEG 解碼器 (Write a JPEG decoder with me) (github.com)

友情链接

我学习过程中写的JPEG图片查看器:Ryan1202/my-tiny-jpeg-viewer: A Tiny Jpeg Viewer (github.com)

JPEG格式研究——(1)压缩原理及流程的更多相关文章

  1. JPEG格式 介绍

    JPEG格式 jpeg是有损压缩格式, 将像素信息用jpeg保存成文件再读取出来,其中某些像素值会有少许变化.在保存时有个质量参数可在[0,100]之间选择,参数越大图片就越保真,但图片的体积也就越大 ...

  2. 图像JPEG格式介绍

    1 JPG格式介绍 JPEG (Joint PhotographicExperts GROUP)是由国际标准组织和国际电话电报咨询委员会为静态图像所建立的第一个国际数字图像压缩标准,也是至今一直在使用 ...

  3. Java 详解 JVM 工作原理和流程

    Java 详解 JVM 工作原理和流程 作为一名Java使用者,掌握JVM的体系结构也是必须的.说起Java,人们首先想到的是Java编程语言,然而事实上,Java是一种技术,它由四方面组成:Java ...

  4. Linux可插拔认证模块(PAM)的配置文件、工作原理与流程

    PAM的配置文件: 我们注意到,配置文件也放在了在应用接口层中,他与PAM API配合使用,从而达到了在应用中灵活插入所需鉴别模块的目的.他的作用主要是为应用选定具体的鉴别模块,模块间的组合以及规定模 ...

  5. InnoDB 数据表压缩原理与限制

    http://liuxin1982.blog.chinaunix.net/uid-24485075-id-3523032.html 压缩理念 通过提高CPU利用率和节约成本,降低数据库容量及I/O负载 ...

  6. hadoop深入研究:(七)——压缩

    转载请标明出处:hadoop深入研究:(七)——压缩 文件压缩主要有两个好处,一是减少了存储文件所占空间,另一个就是为数据传输提速.在hadoop大数据的背景下,这两点尤为重要,那么我现在就先来了解下 ...

  7. 嵌入式Linux基于framebuffer的jpeg格式本地LCD屏显示

    在基于Linux的视频监控采集系统中,摄像头采集到的一帧视频图像数据一般都是经过硬件自动压缩成jpeg格式的,然后再保存到摄像头设备的缓冲区.如果要把采集到的jpeg格式显示在本地LCD屏上,由于我们 ...

  8. HTTP协议:从原理到流程|乐字节

    这次给大家带来的是HTTP协议:从原理到流程的详解 一.HTTP 协议 HTTP 协议(Hypertext Transfer Protocol, 超文本传输协议),是一个客户端请求和回应的 标准协议, ...

  9. C++ 图片格式转化和压缩

    在做人脸识别底库图片导入的时候,需要支持主流的图片的格式,如jpeg.bmp.png等格式.所以需要对图片进行格式转化.图片过大的话,还有进行缩放等.本文介绍的是利用cximage开源库,来进行对图片 ...

  10. 【5】肿瘤DNA甲基化数据分析原理及流程

    目录 导论 DNA甲基化基本概论 检测DNA甲基化的方法 DNA甲基化数据分析流程及方法 DNA甲基化在肿瘤研究中的应用 导论 表观遗传:非DNA决定的基因表达,或表型改变中可遗传因素的研究 DNA水 ...

随机推荐

  1. 火山引擎VeDI赋能小城酒店业,助力“流量”向“留量”转化

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群.   今年,"去小城过假期"正悄然流行.根据途牛旅游发布的<2024年上半年度旅游消费报 ...

  2. Angular Material 18+ 高级教程 – 大杂烩

    前言 本篇记入一些 Angular Material 的小东西. Override Material Icon Button Size 参考:Stack Overflow – Change size ...

  3. Figma 学习笔记 – Scroll and Position Fixed

    Scroll Scroll 属于 prototype 的一部分. 当一个 Frame 的内容超出 Frame 的高度或宽度时, Frame 就具备了 scroll 的能力. 通过 uncheck cl ...

  4. DML—对表中的数据进行增删改

    一.添加数据 1.给指定列添加数据 insert into 表名(列名1,列名2,...) values(值1,值2...); 执行给指定列添加数据前: -- 给指定列添加数据 insert into ...

  5. Filter——过滤器

    Filter       Filter 快速入门    Filter 执行流程           1.放行前,对 request 数据进行处理     2.放行后,对 response 数据进行处理 ...

  6. 为什么用 AWS CLI?因为我懒得点鼠标!

    在这篇博客中,我们一起深入探索 AWS CLI 的世界,从零开始,逐步构建在云端的家园.将介绍 AWS CLI 的基本功能和使用场景,如何创建 IAM 用户.VPC.子网.安全组.EC2 实例等,甚至 ...

  7. USB ncm虚拟网卡

    NCM介绍 1 功能 USB NCM,属于USB-IF定义的CDC(Communication Device Class)下的一个子类:Network Control Model,用于Host和Dev ...

  8. 使用SourceTree管理仓库代码

    1.首先我们需要下载sourcetree,你可以去官网下载自己需要的版本. 2.安装完毕之后,我们需要获取ssh密钥与github关联上才能使用 按下面的操作开始执行.确定之后,会出现一个字符界面,输 ...

  9. Xcode 12 引用缺失包:libstdc++.tbd libstdc++.6.tbd libstdc++.6.0.9.tbd引发的一系列问题解析

    升级到xcode12后会有libstdc++.tbd libstdc++.6.tbd libstdc++.6.0.9.tbd 等库缺失的情况,并引发一些列的 Undefined symbols for ...

  10. 数组 Array 的属性 和 方法总结

    1. Array 的属性 2. Array 的方法 2.1 增加数组单元 参数一半都是数组单元 a)unshift 方法 在数组的最前面添加数组元素 <script> const arr ...