JPEG 是 Joint Photographic Experts Group 的缩写,即 ISO 和 IEC 联合图像专家组,负责静态图像压缩标准的制定,这个专家组开发的算法就被称为 JPEG 算法。使用这个算法压缩的图片就叫做.JPEG/.JPG。
一、JPEG核心原理
JPEG核心原理是利用了人眼对色彩不敏感,且对高频信息不敏感的特性。舍弃了人眼不易察觉到的部分。因此JPEG是有损压缩。
人眼中有两种感光细胞,视杆细胞Rods和视锥细胞Cones。视杆细胞对明暗变化敏感,对颜色不敏感;视锥细胞对颜色敏感。每只眼睛有1亿个视杆细胞,而视锥细胞只有600万个。因此,人眼对图像的明暗程度的感知能力要强的多。视锥细胞还另外分为绿红蓝三种,比例为40:20:1。因此人眼对蓝光极不敏感。这也导致我们不易察觉蓝光对人眼的伤害。
二、JPEG原理详细分析
具体步骤:
- DCT (Discrete Cosine Transform 离散余弦变换)
- Quantization(量化)
- Run Length and Huffman coding(游程编码和霍夫曼编码)
1、颜色空间转换。RGB->YCbCr
根据三基色原理,人们发现红绿蓝三种颜色所贡献的亮度是不同的,绿色的“亮度”最大,蓝色最暗,设红色所贡献的亮度的份额为KR,蓝色贡献的份额为KB,那么亮度为
根据经验,未经伽玛校正(计算机色彩空间)的矩阵,KR=0.299,KB=0.114,那么
蓝色和红色的色差的定义如下
最终可以得到RGB转换为YCbCr的数学公式为
可以明显看到,亮度图的细节更加丰富。JPEG把图像转换为YCbCr之后,就可以针对数据得重要程度的不同做不同的处理。这就是为什么JPEG使用这种颜色空间的原因。
2、色彩下采样。按照4:2:0色度抽样
在 YUV 采样的时候可以对 U、V 分量进行色度采样,在 JPEG 压缩算法采用的是 YUV 4:2:0 的色度抽样方法。Y分量不压缩,UV分量分别压缩到原来的1/4。整张图就变为原来的1/2大小了
YCbCr 4:2:0 subsampling
For the top row, the CbCr signals of only two pixels are recorded. No CbCr signals are recorded from the pixels in the second row.
3、离散余弦变换。DCT(Discrete Cosine Transform)
DCT是针对分量单独去做的,也就是说对于YCbCr的图片,我们先要对Y做一次DCT,然后再对Cb做一次DCT,最后对Cr做一次DCT。
以Y分量为例:
将Y分量的像素点按照8×8的矩阵进行分割,每个8×8是一个MCU(最小编码单元),
8×8的原始图像:
推移128后,使其范围变为 -128~127:
使用离散余弦变换,并四舍五入取最接近的整数:
DCT从频率域来解释更容易理解。将这64个像素点按照Y值展开成一条函数曲线F(y),通过DCT,将其离散为64个不同频率的cosine函数。变换后的矩阵不再是亮度矩阵,而是64个基础余弦波的系数矩阵,即64个基础图像的系数矩阵。
4、量化:
量化过程实际上就是对 DCT 系数的一个优化过程。它是利用了人眼对高频部分不敏感的特性来实现数据的大幅简化。量化过程是有损运算,量化是图像质量下降的最主要原因。
量化过程实际上是简单地把频率领域上每个成份,除以一个对于该成份的常数,且接着四舍五入取最接近的整数。
因为人眼对亮度信号比对色差信号更敏感,因此使用了两种量化表:亮度量化值和色差量化值。
使用亮度量化矩阵对前面得到的 DCT 系数矩阵进行量化:
如,使用−415(DC系数)且四舍五入得到最接近的整数
最终,整张表量化后的结果如下:
总体上来说,DCT 变换实际是空间域的低通滤波器。对 Y 分量采用细量化,对 UV 采用粗量化。
量化表是控制 JPEG 压缩比的关键,这个步骤除掉了一些高频量;另一个重要原因是所有图片的点与点之间会有一个色彩过渡的过程,大量的图像信息被包含在低频率中,经过量化处理后,在高频率段,将出现大量连续的零。
5、“Z”字形编排
量化后的数据,有一个很大的特点,就是直流分量相对于交流分量来说要大,而且交流分量中含有大量的0。这样,对这个量化后的数据如何来进行简化,从而再更大程度地进行压缩呢。
这就出现了“Z”字形编排,如图:
对于前面量化的系数所作的 “Z”字形编排结果就是:
底部 −26,−3,0,−3,−3,−6,2,−4,1 −4,1,1,5,1,2,−1,1,−1,2,0,0,0,0,0,−1,−1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 顶部
这样做的特点就是会连续出现多个0,这样很有利于使用简单而直观的行程编码(RLE:Run Length Coding)对它们进行编码。
8×8图像块经过 DCT 变换之后得到的 DC 直流系数有两个特点,一是系数的数值比较大,二是相邻8×8图像块的 DC 系数值变化不大。根据这个特点,JPEG 算法使用了差分脉冲调制编码(DPCM)技术,对相邻图像块之间量化 DC 系数的差值(Delta)进行编码。即充分利用相邻两图像块的特性,来再次简化数据。
即上面的 DC 分量-26,需要单独处理。而对于其他63个元素采用zig-zag(“Z”字形)行程编码,以增加行程中连续0的个数。
6、行程编码
Run Length Coding,行程编码又称“运行长度编码”或“游程编码”,它是一种无损压缩编码。
例如:5555557777733322221111111
这个数据的一个特点是相同的内容会重复出现很多次,那么就可以用一种简化的方法来记录这一串数字,如
(5,6)(7,5)(3,3)(2,4)(l,7)
即为它的行程编码。
行程编码的位数会远远少于原始字符串的位数。
对经过“Z”字形编排过的数据,即可以用行程编码来对其进行大幅度的数据压缩。
我们来用一个简单的例子来详细说明一下:
57,45,0,0,0,0,23,0,-30,-16,0,0,1,0,0,0,0 ,0 ,0 ,0,..,0
可以表示为
(0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-16) ; (2,1) ; EOB
霍夫曼编码中,在 JPEG 有个 EOB(End Of Block) 字段,表示从字段开始后面全为0,然后再根据霍夫曼编码再进行压缩。
即每组数字的头一个表示0的个数,而且为了能更有利于后续的处理,必须是 4 bit,就是说,只能是 0~15,这是的这个行程编码的一个特点。
7、范式 Huffman 编码
直流 DC 系数经过上面的 DPCM 编码,交流 AC 系数经过 RLE 编码后,得到的数据,还可以再进一补压缩。
对zigzag扫描后的RLE进行熵编码,比较典型的是采用huffman编码,huffman编码是一种变长编码,也就是高概率出现的码字使用短编码,低概率出现的码字使用长编码。
如果是双平面色彩格式(Y和CrCb)(需要看资料确认是否和平面有关),一般JFIF的Huffman table有4张
Y的DC表
CrCb的DC表
CrCb的AC表
我们需要使用对应的Huffman table来对RLE进行编码。
对于8*8 block(MCU)来说,最左上角的是DC因子,其余63个都是AC因子,因此在RLE中,第一个元素必然是DC因子,如果这个RLE保存的是Y数据,那么就要用Huffman table(Y DC)来编码,下面讲述一下编码过程
在谈Huffman编码前先要引入一个Catagory Value Table(CVT)
对上面的例子中 RLC 后的结果,对它的存储,JPEG 里并不直接保存这个数值,这样主要是为了提高效率。
还是以(0,57)这个pair为例,需要先将57放到CVT里面,这样就得到57对应的Catagory(组)和bits of value(实际保存值)
57 为第 6 组的,实际保存值为 111001,编码为 (6,111001)。
备注:catagory=6, bits=111001,6表示bits有6位,而bits=111001则是二进制的57。
同理,
57 -> (6, 111001)
45 -> (6,101101)
23 -> (5,10111)
-30 -> (5,00001)
-8 -> (4,0111)
1 -> (1,1)
这个时候前面的例子就变为如下格式:
(0,6),111001 ; (0,6),101101 ; (4,5),10111; (1,5),00001; (0,4) ,0111 ; (2,1),1 ; (0,0)
这样,括号里的数值正好再合成一个字节,高4位是前面0的个数,低4位描述了后面数字的位数;后面被编码的数字表示范围是 -32767..32767。
还是以(0,6),111001 为例,(0,6)中的0放在高4bit,6放在低4bit,组合起来就是一个8bit的 0000 0110 -> 6,然后在Huffman Table找到 码字6 对应的 二进制编码(huffman code),假如这里 6 -> 111000,则 (0,6),111001 最终的编码是 111000 111001
同理,
6 = (0,6) — 111000
6 = (0,6) — 111000
69 = (4,5) (for example) we have 1111111110011001
21 = (1,5) — 11111110110
4 = (0,4) — 1011
33 = (2,1) — 11011
0 = EOB = (0,0) — 1010
所以最终的编码是:
111000 111001 111000 101101 1111111110011001 10111 11111110110 00001 1011 0111 11011 1 1010
参考链接:
https://blog.csdn.net/han2529386161/article/details/109777211
https://zhuanlan.zhihu.com/p/600252083
版权共享,随意转载:云破天开 » JPEG图像压缩原理