图形图像您现在的位置是:首页 > 博客日志 > 图形图像

JPEG图片格式详解

<a href='mailto:'>微wx笑</a>的头像微wx笑2019-09-04 16:32:38图形图像人已围观关键字:JPEG,JPG

简介其实JPEG 和JPG没有区别,JPG的全名、正式扩展名是JPEG。但因DOS、Windows 95等早期系统采用的8.3命名规则只支持最长3字符的扩展名,为了兼容采用了.jpg。也因历史习惯和兼容性

其实JPEG 和JPG没有区别,JPG的全名、正式扩展名是JPEG。但因DOS、Windows 95等早期系统采用的8.3命名规则只支持最长3字符的扩展名,为了兼容采用了.jpg。也因历史习惯和兼容性考虑,.jpg目前更流行。xvG编程技术_踩坑日志_进阶指南 - 无知人生

总的来说:JPEG是文件格式,JPG是扩展名。xvG编程技术_踩坑日志_进阶指南 - 无知人生

JPG即使用JPEG文件交换格式存储的编码图像文件扩展名。 JPEG联合图象专家组,是一种压缩标准。两种文件应该没有区别,如果做文件扩展名严格地说应是JPG。xvG编程技术_踩坑日志_进阶指南 - 无知人生

JPEG是一个压缩标准,又可分为标准 JPEG、渐进式JPEG及JPEG2000三种:xvG编程技术_踩坑日志_进阶指南 - 无知人生

①标准JPEG:以24位颜色存储单个光栅图像,是与平台无关的格式,支持最高级别的压缩,不过,这种压缩是有损耗的。此类型图片在网页下载时只能由上而下依序显示图片,直到图片资料全部下载完毕,才能看到全貌。xvG编程技术_踩坑日志_进阶指南 - 无知人生

②渐进式 JPEG:渐进式JPG为标准JPG的改良格式,支持交错,可以在网页下载时,先呈现出图片的粗略外观后,再慢慢地呈现出完整的内容,渐进式JPG的文件 比标准JPG的文件要来得小。xvG编程技术_踩坑日志_进阶指南 - 无知人生

③JPEG2000:新一代的影像压缩法,压缩品质更好,其压缩率比标准JPEG高约30%左右,同时支持有损 和无损压缩。一个极其重要的特征在于它能实现渐进传输,即先传输图像的轮廓,然后逐步传输数据,让图像由朦胧到清晰显示。xvG编程技术_踩坑日志_进阶指南 - 无知人生

JPEG(Joint Photographic Experts Group)是联合图像专家小组的英文缩写。它由国际电话与电报咨询委员会CCITT(The International Telegraph and Telephone Consultative Committee)与国际标准化组织ISO于1986年联合成立的一个小组,负责制定静态数字图像的编码标准。xvG编程技术_踩坑日志_进阶指南 - 无知人生

JPEG专家组开发了两种基本的压缩算法、两种数据编码方法、四种编码模式。具体如下: 
压缩算法: 
(1)有损的离散余弦变换(Discrete Cosine Transform,DCT); 
(2)无损的预测技术压缩。 
数据编码方法: 
(1)哈夫曼编码; 
(2)算术编码; 
编码模式: 
(1)基于DCT顺序模式:编/解码通过一次扫描完成 
(2)基于DCT递进模式:编/解码需要多次扫描完成,扫描效果从粗糙到精细,逐级递进 
(3)无损模式:基于DPCM,保证解码后完全精确恢复到原图像采样值 
(4)层次模式:图像在多个空间多种分辨率进行编码,可以根据需要只对低分辨率数据作解码,放弃高分辨率信息xvG编程技术_踩坑日志_进阶指南 - 无知人生

1.JPEG文件结构介绍xvG编程技术_踩坑日志_进阶指南 - 无知人生

JPEG文件使用的数据存储方式有多种,最常用的格式称为JPEG文件交换格式(JPEG File Interchange Format,JFIF)。而JPEG文件大体上可以分成两个部分:标记码(Tag)和压缩数据。xvG编程技术_踩坑日志_进阶指南 - 无知人生

标记码由两个字节构成,其前一个字节是固定值0xFF,后一个字节则根据不同意义有不同数值。在每个标记码之前还可以添加数目不限的无意义的0xFF填充,也就说连续的多个0xFF可以被理解为一个0xFF,并表示一个标记码的开始。而在一个完整的两字节的标记码后,就是该标记码对应的压缩数据流,记录了关于文件的诸种信息。xvG编程技术_踩坑日志_进阶指南 - 无知人生

常用的标记有SOI、APP0、DQT、SOF0、DHT、DRI、SOS、EOI。xvG编程技术_踩坑日志_进阶指南 - 无知人生

注意,SOI等都是标记的名称。在文件中,标记码是以标记代码形式出现。例如SOI的标记代码为0xFFD8,即在JPEG文件中的如果出现数据0xFFD8,则表示此处为一个SOI标记。xvG编程技术_踩坑日志_进阶指南 - 无知人生

下面附录列出完整的JPEG定义的标记码表:xvG编程技术_踩坑日志_进阶指南 - 无知人生

(1)SOI,Start of Image,图像开始 
标记代码|2字节|固定值0xFFD8xvG编程技术_踩坑日志_进阶指南 - 无知人生

(2)APP0,Application,应用程序保留标记0 
标记代码|2字节|固定值0xFFE0 
包含9个具体字段: 
① 数据长度|2字节|①~⑨9个字段的总长度,即不包括标记代码,但包括本字段 
② 标识符|5字节|固定值0x4A46494600,即字符串“JFIF0” 
③ 版本号|2字节|一般是0x0102,表示JFIF的版本号1.2,可能会有其他数值代表其他版本 
④ X和Y的密度单位|1字节|只有三个值可选 
0:无单位; 
1:点数/英寸; 
2:点数/厘米 
⑤ X方向像素密度|2字节|取值范围未知 
⑥ Y方向像素密度|2字节|取值范围未知 
⑦ 缩略图水平像素数目|1字节|取值范围未知 
⑧ 缩略图垂直像素数目|1字节|取值范围未知 
⑨ 缩略图RGB位图|长度可能是3的倍数|缩略图RGB位图数据xvG编程技术_踩坑日志_进阶指南 - 无知人生

本标记段可以包含图像的一个微缩版本,存为24位的RGB像素。如果没有微缩图像(这种情况更常见),则字段⑦“缩略图水平像素数目”和字段⑧“缩略图垂直像素数目”的值均为0。xvG编程技术_踩坑日志_进阶指南 - 无知人生

(3)APPn,Application,应用程序保留标记n,其中n=1~15(任选) 
标记代码|2字节|固定值0xFFE1~0xFFF 
包含2个具体字段: 
① 数据长度|2字节|①~②2个字段的总长度,即不包括标记代码,但包括本字段 
② 详细信息|数据长度-2字节|内容不定xvG编程技术_踩坑日志_进阶指南 - 无知人生

(4)DQT,Define Quantization Table,定义量化表 
标记代码|2字节|固定值0xFFDB 
包含9个具体字段: 
① 数据长度|2字节|字段①和多个字段②的总长度,即不包括标记代码,但包括本字段 
② 量化表|数据长度|2字节 
a)精度及量化表ID|1字节| 
高4位:精度,只有两个可选值 
0:8位; 
1:16位 
低4位: 
量化表ID,取值范围为0~3 
b)表项|64×(精度+1))字节|例如8位精度的量化表,其表项长度为64×(0+1)=64字节xvG编程技术_踩坑日志_进阶指南 - 无知人生

本标记段中,字段②可以重复出现,表示多个量化表,但最多只能出现4次。xvG编程技术_踩坑日志_进阶指南 - 无知人生

(5)SOF0,Start of Frame,帧图像开始 
标记代码|2字节|固定值0xFFC0 
包含9个具体字段: 
① 数据长度|2字节|①~⑥六个字段的总长度,即不包括标记代码,但包括本字段 
② 精度|1字节|每个数据样本的位数,通常是8位,一般软件都不支持 12位和16位 
③ 图像高度|2字节|图像高度(单位:像素),如果不支持 DNL 就必须 >0 
④ 图像宽度|2字节|图像宽度(单位:像素),如果不支持 DNL 就必须 >0 
⑤ 颜色分量数|1字节|只有3个数值可选 
1:灰度图; 
3:YCrCb或YIQ; 
4:CMYK 
而JFIF中使用YCrCb,故这里颜色分量数恒为3 
⑥颜色分量信息|颜色分量数×3字节(通常为9字节) 
a)颜色分量ID|1字节 
b)水平/垂直采样因子|1字节| 
高4位:水平采样因子 
低4位:垂直采样因子 
c)量化表|1字节|当前分量使用的量化表的IDxvG编程技术_踩坑日志_进阶指南 - 无知人生

本标记段中,字段⑥应该重复出现,有多少个颜色分量(字段⑤),就出现多少次(一般为3次)。xvG编程技术_踩坑日志_进阶指南 - 无知人生

(6)DHT,Difine Huffman Table,定义哈夫曼表 
标记代码|2字节|固定值0xFFC4 
包含2个具体字段: 
①数据长度|2字节|字段①和多个字段②的总长度,即不包括标记代码,但包括本字段 
② 哈夫曼表|数据长度-2字节 
a)表ID和表类型|1字节| 
高4位:类型,只有两个值可选 
0:DC直流; 
1:AC交流 
低4位:哈夫曼表ID,注意,DC表和AC表分开编码 
b)不同位数的码字数量|16字节 
c)编码内容|16个不同位数的码字数量之和(字节)xvG编程技术_踩坑日志_进阶指南 - 无知人生

本标记段中,字段②可以重复出现(一般4次),也可以致出现1次。例如,Adobe Photoshop 生成的JPEG图片文件中只有1个DHT标记段,里边包含了4个哈夫曼表;而Macromedia Fireworks生成的JPEG图片文件则有4个DHT标记段,每个DHT标记段只有一个哈夫曼表。xvG编程技术_踩坑日志_进阶指南 - 无知人生

(7)DRI,Define Restart Interval,定义差分编码累计复位的间隔 
标记代码|2字节|固定值0xFFDD 
包含2个具体字段: 
①数据长度|2字节|固定值0x0004,①~②两个字段的总长度, 即不包括标记代码,但包括本字段 
②MCU块的单元中的重新开始间隔|2字节|设其值为n,则表示每n个MCU块就有一个,RSTn标记。第一个标记是RST0,第二个是RST1等,RST7后再从RST0重复。xvG编程技术_踩坑日志_进阶指南 - 无知人生

如果没有本标记段,或间隔值为0时,就表示不存在重开始间隔和标记RSTxvG编程技术_踩坑日志_进阶指南 - 无知人生

(8)SOS,Start of Scan,扫描开始 12字节 
标记代码|2字节|固定值0xFFDA 
包含2个具体字段: 
①数据长度|2字节|①~④两个字段的总长度,即不包括标记代码,但包括本字段 
②颜色分量数|1字节|应该和SOF中的字段⑤的值相同,即: 
1:灰度图是; 
3: YCrCb或YIQ; 
4:CMYK。 
而JFIF中使用YCrCb,故这里颜色分量数恒为3 
③颜色分量信息 
a) 颜色分量ID|1字节 
b) 直流/交流系数表号|1字节| 
高4位:直流分量使用的哈夫曼树编号 
低4位:交流分量使用的哈夫曼树编号 
④ 压缩图像数据 
a)谱选择开始|1字节|固定值0x00 
b)谱选择结束|1字节|固定值0x3F 
c)谱选择|1字节|在基本JPEG中总为00xvG编程技术_踩坑日志_进阶指南 - 无知人生

本标记段中,字段③应该重复出现,有多少个颜色分量(字段②),就出现多少次(一般为3次)。本段结束后,紧接着就是真正的图像信息了。图像信息直至遇到一个标记代码就自动结束,一般就是以EOI标记表示结束。xvG编程技术_踩坑日志_进阶指南 - 无知人生

(9)EOI,End of Image,图像结束 2字节 
标记代码|2字节|固定值0xFFD9xvG编程技术_踩坑日志_进阶指南 - 无知人生

这里补充说明一下,由于在JPEG文件中0xFF具有标志性的意思,所以在压缩数据流(真正的图像信息)中出现0xFF,就需要作特别处理。具体方法是,在数据0xFF后添加一个没有意义的0x00。换句话说,如果在图像数据流中遇到0xFF,应该检测其紧接着的字符,如果是 
1)0x00,则表示0xFF是图像流的组成部分,需要进行译码; 
2)0xD9,则与0xFF组成标记EOI,则图像流结束,同时图像文件结束; 
3)0xD0~0xD7,则组成RSTn标记,则要忽视整个RSTn标记,即不对当前0xFF和紧接的0xDn两个字节进行译码,并按RST标记的规则调整译码变量; 
3)0xFF,则忽视当前0xFF,对后一个0xFF再作判断; 
4)其他数值,则忽视当前0xFF,并保留紧接的此数值用于译码。xvG编程技术_踩坑日志_进阶指南 - 无知人生

2.JPEG图像编码xvG编程技术_踩坑日志_进阶指南 - 无知人生

在实际应用中,JPEG图像编码算法使用的大多是离散余弦变换、Huffman编码、顺序编码模式。这样的方式,被人们称为JPEG的基本系统。这里介绍的JPEG编码算法的流程,也是针对基本系统而言。基本系统的JPEG压缩编码算法一共分为11个步骤:颜色模式转换、采样、分块、离散余弦变换(DCT)、Zigzag 扫描排序、量化、DC系数的差分脉冲调制编码、DC系数的中间格式计算、AC系数的游程长度编码、AC系数的中间格式计算、熵编码。xvG编程技术_踩坑日志_进阶指南 - 无知人生

(1)颜色模式转换xvG编程技术_踩坑日志_进阶指南 - 无知人生

JPEG采用的是YCrCb颜色空间,而BMP采用的是RGB颜色空间,要想对BMP图片进行压缩,首先需要进行颜色空间的转换。YCrCb颜色空间中,Y代表亮度,Cr,Cb则代表色度和饱和度(也有人将Cb,Cr两者统称为色度),三者通常以Y,U,V来表示,即用U代表Cb,用V代表Cr。RGB和YCrCb之间的转换关系如下所示:xvG编程技术_踩坑日志_进阶指南 - 无知人生

Y = 0.299R+0.587G+0.114BxvG编程技术_踩坑日志_进阶指南 - 无知人生

Cb = -0.1687R-0.3313G+0.5B+128xvG编程技术_踩坑日志_进阶指南 - 无知人生

Cr = 0.5R=0.418G-0.0813B+128xvG编程技术_踩坑日志_进阶指南 - 无知人生

一般来说,C 值 (包括 Cb Cr) 应该是一个有符号的数字, 但这里通过加上128,使其变为8位的无符号整数,从而方便数据的存储和计算。反之:xvG编程技术_踩坑日志_进阶指南 - 无知人生

R = Y+1.402(Cr-128)xvG编程技术_踩坑日志_进阶指南 - 无知人生

G = Y-0.34414(Cb-128)-0.71414(Cr-128)xvG编程技术_踩坑日志_进阶指南 - 无知人生

B = Y+1.772(Cb-128)xvG编程技术_踩坑日志_进阶指南 - 无知人生

(2)采样xvG编程技术_踩坑日志_进阶指南 - 无知人生

研究发现,人眼对亮度变换的敏感度要比对色彩变换的敏感度高出很多。因此,我们可以认为Y分量要比Cb,Cr分量重要的多。在BMP图片中,RGB三个分量各采用一个字节进行采样,也就是我们常听到的RGB888的模式;而JPEG图片中,通常采用两种采样方式:YUV411和YUV422,它们所代表的意义是Y,Cb,Cr三个分量的数据取样比例一般是4:1:1或者4:2:2(4:1:1含义就是:在2x2的单元中,本应分别有4个Y,4个U,4个V值,用12个字节进行存储。经过4:1:1采样处理后,每个单元中的值分别有4个Y、1个U、1个V,只要用6个字节就可以存储了)。这样的采样方式,虽然损失了一定的精度但也在人眼不太察觉到的范围内减小了数据的存储量。当然,JPEG格式里面也允许将每个点的U,V值都记录下来。xvG编程技术_踩坑日志_进阶指南 - 无知人生

(3)分块xvG编程技术_踩坑日志_进阶指南 - 无知人生

由于后面的DCT变换是是对8x8的子块进行处理的,因此,在进行DCT变换之前必须把源图象数据进行分块。源图象中每点的3个分量是交替出现的,先要把这3个分量分开,存放到3张表中去。然后由左及右,由上到下依次读取8x8的子块,存放在长度为64的表中,即可以进行DCT变换。注意,编码时,程序从源数据中读取一个8x8的数据块后,进行DCT变换,量化,编码,然后再读取、处理下一个8*8的数据块。xvG编程技术_踩坑日志_进阶指南 - 无知人生

JPEG 编码是以每8x8个点为一个单位进行处理的. 所以如果原始图片的长宽不是 8 的倍数, 都需要先补成8的倍数, 使其可以进行一块块的处理。将原始图像数据分为8*8的数据单元矩阵之后,还必须将每个数值减去128,然后一一带入DCT变换公式,即可达到DCT变换的目的。图像的数据值必须减去128,是因为DCT公式所接受的数字范围是-128到127之间。xvG编程技术_踩坑日志_进阶指南 - 无知人生

(4)离散余弦变换xvG编程技术_踩坑日志_进阶指南 - 无知人生

DCT(Discrete Cosine Transform,离散余弦变换),是码率压缩中常用的一种变换编码方法。任何连续的实对称函数的傅里叶变换中只含有余弦项,因此,余弦变换同傅里叶变换一样具有明确的物理意义。DCT是先将整体图像分成N*N的像素块,然后针对N*N的像素块逐一进行DCT操作。需要提醒的是,JPEG的编码过程需要进行正向离散余弦变换,而解码过程则需要反向离散余弦变换。xvG编程技术_踩坑日志_进阶指南 - 无知人生

正向离散余弦变换计算公式:xvG编程技术_踩坑日志_进阶指南 - 无知人生

F(u,v)=c(u)c(v)N1i=0N1j=0f(i,j)cos[(2i+1)π2Nu]cos[(2j+1)π2Nv]xvG编程技术_踩坑日志_进阶指南 - 无知人生

c(u)=1N−−√,u=0 
c(u)=2N−−√,u0
xvG编程技术_踩坑日志_进阶指南 - 无知人生

反向离散余弦变换计算公式:xvG编程技术_踩坑日志_进阶指南 - 无知人生

f(i,j)=N1u=0N1v=0c(u)c(v)F(u,v)cos[(2i+1)π2Nu]cos[(2j+1)π2Nv]xvG编程技术_踩坑日志_进阶指南 - 无知人生

c(u)=1N−−√,u=0 
c(u)=2N−−√,u0
xvG编程技术_踩坑日志_进阶指南 - 无知人生

这里的N是水平、垂直方向的像素数目,一般取值为8。8 * 8的二维像素块经过DCT操作之后,就得到了8 * 8的变换系数矩阵。这些系数,都有具体的物理含义,例如,U=0,V=0时的F(0,0)是原来的64个数据的均值,相当于直流分量,也有人称之为DC系数或者直流系数。随着U,V的增加,相另外的63个系数则代表了水平空间频率和垂直空间频率分量(高频分量)的大小,多半是一些接近于0的正负浮点数,我们称之为交流系数AC。DCT变换后的8*8的系数矩阵中,低频分量集中在矩阵的左上角。高频成分则集中在右下角。xvG编程技术_踩坑日志_进阶指南 - 无知人生

由于大多数图像的高频分量比较小,相应的图像高频分量的DCT系数经常接近于0,再加上高频分量中只包含了图像的细微的细节变化信息,而人眼对这种高频成分的失真不太敏感,所以,可以考虑将这一些高频成分予以抛弃,从而降低需要传输的数据量。这样一来,传送DCT变换系数的所需要的编码长度要远远小于传送图像像素的编码长度。到达接收端之后通过反离散余弦变换就可以得到原来的数据,虽然这么做存在一定的失真,但人眼是可接受的,而且对这种微小的变换是不敏感的。xvG编程技术_踩坑日志_进阶指南 - 无知人生

(5)Zigzag扫描排序xvG编程技术_踩坑日志_进阶指南 - 无知人生

DCT 将一个 8x8 的数组变换成另一个 8x8 的数组. 但是内存里所有数据都是线形存放的, 如果我们一行行的存放这 64 个数字, 每行的结尾的点和下行开始的点就没有什么关系, 所以 JPEG 规定按如下图中的数字顺序依次保存和读取64 个DCT的系数值。xvG编程技术_踩坑日志_进阶指南 - 无知人生

这里写图片描述xvG编程技术_踩坑日志_进阶指南 - 无知人生

这样数列里的相邻点在图片上也是相邻的了。不难发现,这种数据的扫描、保存、读取方式,是从8*8矩阵的左上角开始,按照英文字母Z的形状进行扫描的,一般将其称之为Zigzag扫描排序。如下图所示:xvG编程技术_踩坑日志_进阶指南 - 无知人生

这里写图片描述xvG编程技术_踩坑日志_进阶指南 - 无知人生

(6)量化xvG编程技术_踩坑日志_进阶指南 - 无知人生

图像数据转换为DCT频率系数之后,还要进行量化阶段,才能进入编码过程。量化阶段需要两个8*8量化矩阵数据,一个是专门处理亮度的频率系数,另一个则是针对色度的频率系数,将频率系数除以量化矩阵的值之后取整,即完成了量化过程。当频率系数经过量化之后,将频率系数由浮点数转变为整数,这才便于执行最后的编码。不难发现,经过量化阶段之后,所有的数据只保留了整数近似值,也就再度损失了一些数据内容。在JPEG算法中,由于对亮度和色度的精度要求不同,分别对亮度和色度采用不同的量化表。前者细量化,后者粗量化。xvG编程技术_踩坑日志_进阶指南 - 无知人生

下图给出JPEG的亮度量化表和色度量化表,该量化表是从广泛的实验中得出的。当然,你也可以自定义量化表。xvG编程技术_踩坑日志_进阶指南 - 无知人生

JPEG亮度量化表 
JPEG亮度量化表xvG编程技术_踩坑日志_进阶指南 - 无知人生

JPEG色度量化表 
JPEG色度量化表xvG编程技术_踩坑日志_进阶指南 - 无知人生

这两张表依据心理视觉阀制作, 对 8bit 的亮度和色度的图象的处理效果不错。量化表是控制 JPEG 压缩比的关键,这个步骤除掉了一些高频量, 损失了很多细节信息。但事实上人眼对高频信号的敏感度远没有低频信号那么敏感。所以处理后的视觉损失很小,从上面的量化表也可以看出,低频部分采用了相对较短的量化步长,而高频部分则采用了相对较长的量化步长,这样做,也是为了在一定程度上得到相对清晰的图像和更高的压缩率。另一个重要原因是所有的图片的点与点之间会有一个色彩过渡的过程,而大量的图象信息被包含在低频率空间中,经过DCT处理后, 在高频率部分, 将出现大量连续的零。xvG编程技术_踩坑日志_进阶指南 - 无知人生

(7)DC系数的差分脉冲调制编码xvG编程技术_踩坑日志_进阶指南 - 无知人生

8*8的图像块经过DCT变换之后得到的DC系数有两个特点:xvG编程技术_踩坑日志_进阶指南 - 无知人生

(1)系数的数值比较大;xvG编程技术_踩坑日志_进阶指南 - 无知人生

(2)相邻的8*8图像块的DC系数值变化不大;xvG编程技术_踩坑日志_进阶指南 - 无知人生

根据这两个特点,DC系数一般采用差分脉冲调制编码DPCM(Difference Pulse Code Modulation),即:取同一个图像分量中每个DC值与前一个DC值的差值来进行编码。对差值进行编码所需要的位数会比对原值进行编码所需要的位数少了很多。假设某一个8*8图像块的DC系数值为15,而上一个8*8图像块的DC系数为12,则两者之间的差值为3。xvG编程技术_踩坑日志_进阶指南 - 无知人生

(8)DC系数的中间格式计算xvG编程技术_踩坑日志_进阶指南 - 无知人生

JPEG中为了更进一步节约空间,并不直接保存数据的具体数值,而是将数据按照位数分为16组,保存在表里面。这也就是所谓的变长整数编码VLI。即,第0组中保存的编码位数为0,其编码所代表的数字为0;第1组中保存的编码位数为1,编码所代表的数字为-1或者1……,如下面的表格所示,这里,暂且称其为VLI编码表:xvG编程技术_踩坑日志_进阶指南 - 无知人生

这里写图片描述xvG编程技术_踩坑日志_进阶指南 - 无知人生

前面提到的那个DC差值为3的数据,通过查找VLI可以发现,整数3位于VLI表格的第2组,因此,可以写成(2)(3)的形式,该形式,称之为DC系数的中间格式。xvG编程技术_踩坑日志_进阶指南 - 无知人生

(9)AC系数的行程长度编码(RLC)xvG编程技术_踩坑日志_进阶指南 - 无知人生

量化之后的AC系数的特点是,63个系数中含有很多值为0的系数。因此,可以采用行程编码RLC(Run Length Coding)来更进一步降低数据的传输量。利用该编码方式,可以将一个字符串中重复出现的连续字符用两个字节来代替,其中,第一个字节代表重复的次数,第二个字节代表被重复的字符串。例如,(4,6)就代表字符串“6666”。但是,在JPEG编码中,RLC的含义就同其原有的意义略有不同。在JPEG编码中,假设RLC编码之后得到了一个(M,N)的数据对,其中M是两个非零AC系数之间连续的0的个数(即,行程长度),N是下一个非零的AC系数的值。采用这样的方式进行表示,是因为AC系数当中有大量的0,而采用Zigzag扫描也会使得AC系数中有很多连续的0的存在,如此一来,便非常适合于用RLC进行编码。xvG编程技术_踩坑日志_进阶指南 - 无知人生

例如,现有一个字符串,如下所示:xvG编程技术_踩坑日志_进阶指南 - 无知人生

57,45,0,0,0,0,23,0,-30,-8,0,0,1,000…..xvG编程技术_踩坑日志_进阶指南 - 无知人生

经过RLC之后,将呈现出以下的形式:xvG编程技术_踩坑日志_进阶指南 - 无知人生

(0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-8) ; (2,1) ; (0,0)xvG编程技术_踩坑日志_进阶指南 - 无知人生

注意,如果AC系数之间连续0的个数超过16,则用一个扩展字节(15,0)来表示16连续的0。xvG编程技术_踩坑日志_进阶指南 - 无知人生

(10)AC系数的中间格式xvG编程技术_踩坑日志_进阶指南 - 无知人生

根据前面提到的VLI表格,对于前面的字符串:xvG编程技术_踩坑日志_进阶指南 - 无知人生

(0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-8) ; (2,1) ; (0,0)xvG编程技术_踩坑日志_进阶指南 - 无知人生

只处理每对数右边的那个数据,对其进行VLI编码: 查找上面的VLI编码表格,可以发现,57在第6组当中,因此,可以将其写成(0,6),57的形式,该形式,称之为AC系数的中间格式。xvG编程技术_踩坑日志_进阶指南 - 无知人生

同样的(0,45)的中间格式为:(0,6),45;xvG编程技术_踩坑日志_进阶指南 - 无知人生

(1,-30)的中间格式为:(1,5),-30;xvG编程技术_踩坑日志_进阶指南 - 无知人生

(11)熵编码xvG编程技术_踩坑日志_进阶指南 - 无知人生

在得到DC系数的中间格式和AC系数的中间格式之后,为进一步压缩图象数据,有必要对两者进行熵编码。JPEG标准具体规定了两种熵编码方式:Huffman编码和算术编码。JPEG基本系统规定采用Huffman编码(因为不存在专利问题),但JPEG标准并没有限制JPEG算法必须用Huffman编码方式或者算术编码方式。xvG编程技术_踩坑日志_进阶指南 - 无知人生

Huffman编码:对出现概率大的字符分配字符长度较短的二进制编码,对出现概率小的字符分配字符长度较长的二进制编码,从而使得字符的平均编码长度最短。Huffman编码的原理请参考数据结构中的Huffman树或者最优二叉树。xvG编程技术_踩坑日志_进阶指南 - 无知人生

Huffman编码时DC系数与AC系数分别采用不同的Huffman编码表,对于亮度和色度也采用不同的Huffman编码表。因此,需要4张Huffman编码表才能完成熵编码的工作。具体的Huffman编码采用查表的方式来高效地完成。然而,在JPEG标准中没有定义缺省的Huffman表,用户可以根据实际应用自由选择,也可以使用JPEG标准推荐的Huffman表。或者预先定义一个通用的Huffman表,也可以针对一副特定的图像,在压缩编码前通过搜集其统计特征来计算Huffman表的值。xvG编程技术_踩坑日志_进阶指南 - 无知人生

下面我们举例来说明8*8图像子块经过DCT及量化之后的处理过程:xvG编程技术_踩坑日志_进阶指南 - 无知人生

假设一个图像块经过量化以后得到以下的系数矩阵:xvG编程技术_踩坑日志_进阶指南 - 无知人生

15 0 -1 0 0 0 0 0 
-2 -1 0 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 0 0 0 0 0 0 0xvG编程技术_踩坑日志_进阶指南 - 无知人生

显然,DC系数为15,假设前一个8*8的图像块的DC系数量化值为12,则当前DC系统同上一个DC系数之间的差值为3,通过查找VLI编码表,可以得到DC系数的中间格式为(2)(3),这里的2代表后面的数字(3)的编码长度为2位;之后,通过Zigzag扫描之后,遇到第一个非0的AC系数为-2,遇到0的个数为1,AC系数经过RLC编码后可表示为(1,-2),通过查找VLI表发现,-2在第2组,因此,该AC系数的中间格式为(1,2)-2; 
其余的点类似,可以求得这个8*8子块熵编码的中间格式为 
(DC)(2)(3);AC(1,2)(-2),(0,1)(-1),(0,1)(-1),(0,1)(-1),(2,1)(-1),(EOB)(0,0) 
对于DC系数的中间格式(2)(3)而言,数字2查DC亮度Huffman表得到011,数字3通过查找VLI编码表得到其被编码为11; 
对于AC系数的中间格式(1,2)(-2)而言,(1,2)查AC亮度Huffman表得到11011,-2通过查找VLI编码表得到其被编码为01;xvG编程技术_踩坑日志_进阶指南 - 无知人生

对于AC系数的中间格式(0,1)(-1)而言,(0,1)查AC亮度Huffman表得到00,数字-1通过查找VLI编码表得到其被编码为0;xvG编程技术_踩坑日志_进阶指南 - 无知人生

对于AC系数的中间格式(2,1)(1)而言,(2,1)查AC亮度Huffman表得到11100,数字-1通过查找VLI编码表得到其被编码为0;xvG编程技术_踩坑日志_进阶指南 - 无知人生

对于AC系数的中间格式(0,0)而言,查AC亮度Huffman表得到1010; 
因此,最后这个8 * 8子块亮度信息压缩后的数据流为01111,1101101,000,000,000,111000,1010。总共31比特,其压缩比是64 * 8/31=16.5,大约每个像素用半个比特。xvG编程技术_踩坑日志_进阶指南 - 无知人生

JPEG解码过程在此不再赘述,与编码过程对称。xvG编程技术_踩坑日志_进阶指南 - 无知人生


xvG编程技术_踩坑日志_进阶指南 - 无知人生

很赞哦! () 有话说 ()

相关文章

站点信息

  • 建站时间:2018-10-24
  • 服务期限阿里云ECS 2027年到期
  • 主题模板:基于《今夕何夕》修改
  • 文章统计:210篇
  • 文章评论:15条
  • 文章阅读:2818次
  • 文章点赞:1026次
  • 微信公众号:扫描二维码,关注我们
  • 二维码-微信公众号-微wx笑