【Codecs】JPEG原理详解

###Date: 2018.4.22

===========================================================


JPEG 是 Joint Photographic Experts Group 的缩写,即 ISO 和 IEC 联合图像专家组,负责静态图像压缩标准的制定,这个专家组开发的算法就被称为 JPEG 算法,并且已经成为了大家通用的标准,即 JPEG 标准。 JPEG 压缩是有损压缩,但这个损失的部分是人的视觉不容易察觉到的部分,它充分利用了人眼对计算机色彩中的高频信息部分不敏感的特点,来大大节省了需要处理的数 据信息。 
  人眼对构成图像的不同频率成分具有不同的敏感度,这个是由人眼的视觉生理特性所决定的。如人的眼睛含有对亮度敏感的柱状细胞1.8亿个,含有对色彩敏感的椎状细胞0.08亿个,由于柱状细胞的数量远大于椎状细胞,所以眼睛对亮度的敏感程度要大于对色彩的敏感程度。
  总体来说,一个原始图像信息,要对其进行 JPEG 编码,过程分两大步:
  1、 去除视觉上的多余信息,即空间冗余度
  2、 去除数据本身的多余信息,即结构(静态)冗余度
  1、去除视觉上的多余信息
  当你拿到一个原始未经处理的图像,是由各种色彩组成的,即在一个平面上,有各种色彩,而这个平面是由水平和垂直方向上的很多点组成的。实际上,每个点 的色彩,也即计算机能表示的每个像素点的色彩,能分解成红、绿、蓝,即 RGB 三元色来表示,即这三种颜色的一定比例的混合就能得到一个实际的色彩值。

所以,实际上,这个平面的图像,可以理解为除了水平 X 和垂直 Y 以外,还有一个色彩值的 Z 的三维的系统。Z 代表了三元色中各个分支 R/G/B 的混合时所占的具体数值大小,每个像素的 RGB 的混合值可能都有所不同,各个值有大有小,但临近的两个点的 R/G/B 三个值会比较接近。

由于这个原始图像是由很多个独立的像素点组成的,也就是说它们都是分散的,离散的。比如有些图像的尺寸为640X480,就表示水平有640个像素点,垂直有480个像素点。
  从上面的内容,我们可以知道两个相邻的点,会有很多的色彩是很接近的,那么如何能在最后得到的图片中,尽量少得记录这些不需要的数据,也即达到了压缩的效果。
  这个就要涉及到图像信号的频谱特性了。
  图像信号的频谱线一般在0-6MHz范围内,而且一幅图像内,包含了各种频率的分量。但包含的大多数为低频频谱线,只在占图像区域比例很低的图像边缘的信号中才含有高频的谱线。这个是对 JPEG 图像压缩的理论依据。
  因此具体的方法就是,在对图像做数字处理时,可根据频谱因素分配比特数:对包含信息量大的低频谱区域分配较多的比特数,对包含信息量低的高频谱区域分配较少的比特数,而图像质量并没有可察觉的损伤,达到数据压缩的目的。
  将原始图像这个色彩空间域,转换为频谱域,怎么转呢,这个就用到了数学上的离散余弦变换,即 DCT(Discrete Cosine Transform) 变换。
  DCT 是可逆的、离散的正交变换。变换过程本身虽然并不产生压缩作用,但是变换后的频率系数却非常有利于码率压缩。即这个变换过程得到一个 DCT 变换系数,而对这个系数可以再进行更进一步的处理,即所谓的量化。经过量化,就能达到数据压缩的作用了。
总体说来,这第一步,对图像进行编码,去除多余的信息,要用到 DCT 变换中的正向 DCT(FDCT),然后再对变换的系数做量化(Quantization),这个过程就是依据的经验值,来处理人眼视觉系统所不敏感的高频数据,从而极 大地减少了需要处理的数据量,这个是结合数学方法与经验值而做的处理。 
  2、去除数据本身的多余信息
  利用 Huffman 编码,来将最后的数据用无损的方式做压缩,这个是纯数学上的处理方式。
  总体来说,上面的两步即:
  如果处理的是彩色图像,JPEG 算法首先将 RGB 分量转化成亮度分量和色差分量,同时丢失一半的色彩信息(空间分辨率减半)。然后,用 DCT 来进行块变换编码,舍弃高频的系数,并对余下的系数进行量化以进一步减小数据量。最后,使用 RLE 行程编码和 Huffman 编码来完成压缩任务。 
  三、JPEG 原理详细分析
  下面将更加详细地介绍这两步中的各个细节。
  JPEG 编码中主要涉及到的内容主要包括:
  1. Color Model Conversion (色彩模型)
  2. DCT (Discrete Cosine Transform 离散余弦变换)
  3. 重排列 DCT 结果
  4. 量化
  5. RLE 编码
  6. 范式 Huffman 编码
  7. DC 的编码

1、色彩空间 color space 
  在图像处理中,为了利用人的视角特性,从而降低数据量,通常把 RGB 空间表示的彩色图像变换到其他色彩空间。
  现在采用的色彩空间变换有三种:YIQ,YUV 和 YCrCb。
  每一种色彩空间都产生一种亮度分量信号和两种色度分量信号,而每一种变换使用的参数都是为了适应某种类型的显示设备。 


YUV 不是哪个英文单词的缩写,而只是符号,Y 表示亮度,UV 用来表示色差,U、V 是构成彩色的两个分量;
  YUV 表示法的重要性是它的亮度信号(Y)和色度信号(U、V)是相互独立的,也就是 Y 信号分量构成的黑白灰度图与用 U、V 信号构成的另外两幅单色图是相互独立的。由于 Y、U、V 是独立的,所以可以对这些单色图分别进行编码。此外,黑白电视能接收彩色电视信号也就是利用了 YUV 分量之间的独立性。
  举例来说明一下:
  要存储 RGB 8∶8∶8的彩色图像,即 R、G 和 B 分量都用8位二进制数(1个字节)表示,图像的大小为640×480像素,那么所需要的存储容量为640×480×(1+1+1)=921 600字节,即900KB,其中(1+1+1)表示 RGB 各占一个字节。 


如果用 YUV 来表示同一幅彩色图像,Y 分量仍然为640×480,并且 Y 分量仍然用8位表示,而对每四个相邻像素(2×2)的 U、V 值分别用相同的一个值表示,那么存储同样的一幅图像所需的存储空间就减少到640×480×(1+1/(2*2)+1/(2*2))=460 800字节,即450KB。也就是把数据压缩了一半。


无论是用 YIQ、YUV 和 YCrCb 还是其他模型来表示的彩色图像,由于现在所有的显示器都采用 RGB 值来驱动,这就要求在显示每个像素之前,须要把彩色分量值转换成 RGB 值。
对电视机,在考虑人的视觉系统和电视阴极射线管(CRT)的非线性特性之后,RGB 和 YUV 的对应关系可以近似地用下面的方程式表示: 


即:
  Y=0.3R+0.59G+0.11B
  U=B-Y
  V=R-Y
  对计算机而言,计算机用的数字域的色彩空间变换与电视模拟域的色彩空间变换不同,它们的分量使用 Y、Cr 和 Cb 来表示,与 RGB 空间的转换关系如下:


从这里,就可以看出,计算出来的 Y、Cr 和 Cb 分量,会出现大量的小数,即浮点数,从而导致了在 JPEG 编码过程中会出现大量的浮点数的运算,当然经过一定的优化,这些浮点数运算可以用移位与加法这些计算机能更快速处理的方式来对其进行编码。
  RGB 与 YCrCb 之间的逆变换关系可写成如下的形式:


总体来说,上面讲的这些内容,主要就是对原始图片,可以先进行色彩空间的处理,使采集到的图像数据有所减少。
  请注意,实际上,JPEG 算法与色彩空间无关,色彩空间是涉及到图像采样的问题,它和数据的压缩并没有直接的关系。
  因此“RGB 到 YUV 变换”和“YUV 到 RGB 变换”不包含在 JPEG 算法中。JPEG 算法处理的彩色图像是单独的彩色分量图像,因此它可以压缩来自不同色彩空间的数据,如 RGB,YcbCr 和 CMYK。 
2、色彩深度 color depth
  在图像中,它是由很多个点来组成的,那么存储每个像素点所用的位数就叫做像素深度。对一个图片,这个值是可以有所不同的,从而会使得图片的数据有多和少的区别。
  一幅彩色图像的每个像素用 R,G,B 三个分量表示,若每个分量用8位,那么一个像素共用3X8=24位表示,就说像素的深度为24 bit,每个像素可以是2的24次方=16 777 216种颜色中的一种。表示一个像素的位数越多,它能表达的颜色数目就越多。
  在用二进制数表示彩色图像的像素时,除 R,G,B 分量用固定位数表示外,往往还增加1位或几位作为属性(Attribute)位。例如,RGB 5∶5∶5表示一个像素时,用2个字节共16位表示,其中 R,G,B 各占5位,剩下一位作为属性位。在这种情况下,像素深度为16位,而图像深度为15 位。
  在用32位表示一个像素时,若 R,G,B 分别用8位表示,剩下的8位常称为 alpha 通道(alpha channel)位,或称为覆盖(overlay)位、中断位、属性位。它的用法可用一个预乘 α 通道(premultiplied alpha)的例子说明。假如一个像素(A,R,G,B)的四个分量都用归一化的数值表示,(A,R,G,B)为(1,1,0,0)时显示红色。当像素为 (0.5,1,0,0)时,预乘的结果就变成(0.5,0.5,0,0),这表示原来该像素显示的红色的强度为1,而现在显示的红色的强度降了一半。
  这个 alpha 值,在这里就用来表示该像素如何产生特技效果。
  总体来说,图像的宽高、分辨率越高,就是组成一幅图的像素越多,则图像文件越大;像素深度越深,就是表达单个像素的颜色和亮度的位数越多,图像文件就越大。
  只有黑白两种颜色的图像称为单色图像(monochrome),每个像素的像素值用1位存储,它的值只有“0”或者“1”,一幅640×480的单色图像需要占据37.5 KB的存储空间。
而灰度图像,即有色深的黑白图像,如果每个像素的像素值用一个字节表示,而不是仅仅只有一位,那么灰度值级数就等于256级,每个像素可以是0~255之间的任何一个值,一幅640×480的灰度图像就需要占用300 KB的存储空间,类似上面说到过的 Y 分量。 
  3、离散余弦变换 DCT
  将图像从色彩域转换到频率域,常用的变换方法有:


DCT变换的公式为:

f(i,j) 经 DCT 变换之后,F(0,0) 是直流系数,其他为交流系数。
  还是举例来说明一下。
  8x8的原始图像: 


推移128后,使其范围变为 -128~127:

使用离散余弦变换,并四舍五入取最接近的整数:

上图就是将取样块由时间域转换为频率域的 DCT 系数块。
DCT 将原始图像信息块转换成代表不同频率分量的系数集,这有两个优点:其一,信号常将其能量的大部分集中于频率域的一个小范围内,这样一来,描述不重要的分量 只需要很少的比特数;其二,频率域分解映射了人类视觉系统的处理过程,并允许后继的量化过程满足其灵敏度的要求。
  当u,v = 0 时,离散余弦正变换(DCT)后的系数若为F(0,0)=1,则离散余弦反变换(IDCT)后的重现函数 f(x,y)=1/8,是个常 数值,所以将 F(0,0) 称为直流(DC)系数;当 u,v≠0 时,正变换后的系数为 F(u,v)=0,则反变换后的重现函数 f(x,y) 不是常数,此时 正变换后的系数 F(u,v) 为交流(AC)系数。
  DCT 后的64个 DCT 频率系数与 DCT 前的64个像素块相对应,DCT 过程的前后都是64个点,说明这个过程只是一个没有压缩作用的无损变换过程。
  单独一个图像的全部 DCT 系数块的频谱几乎都集中在最左上角的系数块中。
  DCT 输出的频率系数矩阵最左上角的直流 (DC)系数幅度最大,图中为-415;以 DC 系数为出发点向下、向右的其它 DCT 系数,离 DC 分量越远,频率越高,幅度值越小,图中最右下角为2,即图像信息的大部分集中于直流系数及其附近的低频频谱上,离 DC 系数越来越远的高频频谱几乎不含图像信息,甚至于只含杂波。
  DCT 本身虽然没有压缩作用,却为以后压缩时的"取"、"舍" 奠定了必不可少的基础。 
  4、量化
  量化过程实际上就是对 DCT 系数的一个优化过程。它是利用了人眼对高频部分不敏感的特性来实现数据的大幅简化。
  量化过程实际上是简单地把频率领域上每个成份,除以一个对于该成份的常数,且接着四舍五入取最接近的整数。
  这是整个过程中的主要有损运算。
以这个结果来说,经常会把很多高频率的成份四舍五入而接近0,且剩下很多会变成小的正或负数。
  整个量化的目的是减小非“0”系数的幅度以及增加“0”值系数的数目。
  量化是图像质量下降的最主要原因。
  因为人眼对亮度信号比对色差信号更敏感,因此使用了两种量化表:亮度量化值和色差量化值。


使用这个量化矩阵与前面所得到的 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
  即每组数字的头一个表示0的个数,而且为了能更有利于后续的处理,必须是 4 bit,就是说,只能是 0~15,这是的这个行程编码的一个特点。 
  7、范式 Huffman 编码
  在直流 DC 系数经过上面的 DPCM 编码,交流 AC 系数经过 RLE 编码后,得到的数据,还可以再进一补压缩,即使用 Huffman 编码来处理。
  范式 Huffman 编码即 Canonical Huffman Code,现在流行的很多压缩方法都使用了范式哈夫曼编码技术,如 GZIB、ZLIB、PNG、JPEG、MPEG 等。
  对上面的例子中 RLC 后的结果,对它的存储,JPEG 里并不直接保存这个数值,这样主要是为了提高效率。 

对上面的例子内容,就可以得到:
  57 为第 6 组的,实际保存值为 111001,编码为 (6,111001)
  45编码为 (6,101101)
  23为(5,10111)
  -30为(5,00001)
  这个时候前面的例子就变为:
  (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。


参考:

http://www.360doc.com/content/12/0606/19/10144181_216456484.shtml

原文地址:https://www.cnblogs.com/SoaringLee/p/10532508.html