JPEGExifTIFF格式解读(1):JEPG图⽚压缩与存储原理分析JPEG⽂件简介
JPEG的全称是JointPhotographicExpertsGroup(联合图像专家⼩组),它是⼀种常⽤的图像存储格式, jpg/jpeg是24位的图像⽂件格式,也是⼀种⾼效率的压缩格式,⽂件格式是JPEG(联合图像专家组)标准的产物,该图像压缩标准是国际电信联盟(International Telecommunication Union,ITU)、国际标准化组织(International Organization for Standardization,ISO)和国际电⼯委员会(International Electrotechnical Commission,IEC)共同制定。JPEG标准正式地称为ISO/IEC IS(国际标准)10918-1:连续⾊调静态图像数字压缩和编码(Digital Compression and Coding of Continuous-tone Still Images)和ITU-T建议T.81。
JPEG是第⼀个国际图像压缩标准,⽤于连续⾊调静态图像(即包括灰度图像和彩⾊图像),其最初⽬的是使⽤64Kbps的通信线路传输720×576 分辨率压缩后的图像。通过损失极少的分辨率,可以将图像所需存储量减少⾄原⼤⼩的10%。由于其⾼效的压缩效率和标准化要求,⽬前已⼴泛⽤于彩⾊传真、静⽌图像、电话会议、印刷及新闻图⽚的传送上。但那些被删除的资料⽆法在解压时还原,所以* .jpg/.jpeg ⽂件并不适合放⼤观看,输出成印刷品时品质也会受到影响。
JPEG⽂件格式
JPEG的⽂件格式⼀般有两种⽂件扩展名:.jpg和.jpeg,这两种扩展名的实质是相同的,我们可以把.jpg
exif信息的⽂件改名为.jpeg,⽽对⽂件本⾝不会有任何影响。严格来讲,JPEG的⽂件扩展名应该为.jpeg,由于DOS时代的8.3⽂件名命名原则,就使⽤了.jpg的扩展名,这种情况类似于.htm和.html的区别。
JPEG标准不指定任何固有的⽂件格式。它只定义压缩⽐特流的语法。这就产⽣了⼀定数量的⽂件格式来存储JPEG压缩后的图像,例如JPEG⽂件交换格式(JPEG File Interchange Format,JFIF),JPEG推⼴到TIFF6.0、FlashPix等。但它们中的每⼀个都不能认为是由国际标准委员会⽀持的正式定义的国际标准。
JPEG格式可以分为标准JPEG、渐进式JPEG和JPEG2000三种格式。
标准JPEG:该类型的图⽚⽂件,在⽹络上应⽤较多,只有图⽚完全被加载和读取完毕之后,才能看到图⽚的全貌;它是⼀种很灵活的图⽚压缩⽅式,⽤户可以在压缩⽐和图⽚品质之间进⾏权衡。不过,通常来讲,其压缩⽐在10:1到40:1之间,压缩⽐越⼤,品质就越差,压缩⽐越⼩,品质就越好。JPEG格式压缩的主要是⾼频信息,对⾊彩的信息保留较好,适合应⽤于互联⽹,可减少图像的传输时间,可以⽀持24bit 真彩⾊,也普遍应⽤于需要连续⾊调的图像。JPEG由于可以提供有损压缩,因此压缩⽐可以达到其他传统压缩算法⽆法⽐拟的程度。其压缩模式有以下⼏种:
1. 顺序式编码(SequentialEncoding)
2. 递增式编码(ProgressiveEncoding)
3. ⽆失真编码(LosslessEncoding)
4. 阶梯式编码(HierarchicalEncoding)
JPEG的压缩步骤
1. 颜⾊转换:由于JPEG只⽀持YUV颜⾊模式,⽽不⽀持RGB颜⾊模式,所以在将彩⾊图像进⾏压缩之前,必须先对颜⾊模式进据转
换。转换完成之后还需要进⾏数据采样。⼀般采⽤的采样⽐例是2:1:1或4:2:2。由于在执⾏了此项⼯作之后,每两⾏数据只保留⼀⾏,因此,采样后图像数据量将压缩为原来的⼀半。
2. DCT变换:DCT(DiscreteConsineTransform)是将图像信号在频率域上进⾏变换,分离出⾼频和低频信息的处理过程。然后再对图
像的⾼频部分(即图像细节)进⾏压缩,以达到压缩图像数据的⽬的。⾸先将图像划分为多个8*8的矩阵。然后对每⼀个矩阵作DCT变换(变换公式此略)。变换后得到⼀个频率系数矩阵,其中的频率系数都是浮点数。
3. 量化:由于在后⾯编码过程中使⽤的码本都是整数,因此需要对变换后的频率系数进⾏量化,将之转换为整数。由于进⾏数据量化
后,矩阵中的数据都是近似值,和原始图像数据之间有了差异,这⼀差异是造成图像压缩后失真的主要原因。
4. 编码:编码采⽤两种机制:⼀是0值的⾏程长度编码;⼆是熵编码(EntropyCoding)。在JPEG中,采⽤曲徊序列,即以矩阵对⾓线
的法线⽅向作“之”字排列矩阵中的元素。这样做的优点是使得靠近矩阵左上⾓、值⽐较⼤的元素排列在⾏程的前⾯,⽽⾏程的后⾯所排列的矩阵元素基本上为0值。⾏程长度编码是⾮常简单和常⽤的编码⽅式,在此不再赘述。编码实际上是⼀种基于统计特性的编码⽅法。在JPEG中允许采⽤HUFFMAN编码或者算术编码。
更详细可以参看《》、《》
Baseline JPEG/基本JPEG:这种类型的JPEG⽂件存储⽅式是按从上到下的扫描⽅式,把每⼀⾏顺序的保存在JPEG⽂件中。打开这个⽂件显⽰它的内容时,数据将按照存储时的顺序从上到下⼀⾏⼀⾏的被显⽰出来,直到所有的数据都被读完,就完成了整张图⽚的显⽰。这种图⽚在web中,如果没有给图⽚指定宽⾼,会造成重绘。
progressive jpeg/渐进式JPEG:JPEG⽂件包含多次扫描,这些扫描顺寻的存储在JPEG⽂件中。打开
⽂件过程中,会先显⽰整个图⽚的模糊轮廓,随着扫描次数的增加,图⽚变得越来越清晰。该类型的图⽚是对标准JPEG格式的改进,当在⽹页上下载渐进式JPEG图⽚时,⾸先呈现图⽚的⼤概外貌,然后再逐渐呈现具体的细节部分,因⽽被称之为渐进式JPEG。这种通过HTTP2 多路复⽤传递渐进式JPEG的扫描图层来提⾼感知性能和速度指数的⽅式注意到了。他⼀直在实验协议,HTTP2的前⾝。
JPEG2000:⼀种全新的图⽚压缩发,压缩品质更好,并且改善了⽆线传输时,因信号不稳定⽽造成的马赛克及位置错乱等问题。另外,作为JPEG的升级版,JPEG2000的压缩率⽐标准JPEG⾼约30%,同时⽀持有损压缩和⽆损压缩。它还⽀持渐进式传输,即,先传输图⽚的粗略轮廓,然后,逐步传输细节数据,使得图⽚由模糊到清晰逐步显⽰。此外,JPEG2000还⽀持感兴趣区域,也就是说,可以指定图⽚上感兴趣区域的压缩质量,还可以选择指定的部分先进⾏解压。还有个优势就是,JPEG2000从⽆损压缩到有损压缩可以兼容
jpeg2000编码解码模块与过程
jpeg编码解码系统构成
压缩步骤
由于JPEG的有损压缩⽅式(Lossy mode of operation)并不⽐其他的压缩⽅法更优秀,
因此我们着重来看它的有损压缩中最常⽤的基线JPEG算法(baseline sequential)。以⼀幅24位彩⾊图像为例,JPEG的压缩步骤分为:
颜⾊转换
JPEG⽀持图像采⽤任何⼀个⾊彩空间,⽀持1~4个颜⾊分量。灰度图像颜⾊分量数为1。RGB、YUV、YCbCr等拥有3种颜⾊分量。4种颜⾊分量的例⼦是青、洋红、黄和⿊(Cyan,Magenta,Yellow,and Black,CMYK)。为了减少⾊度通道包含的⼤量的冗余信息,本例中采⽤YCbCr⾊彩空间。⾸先需要进⾏从RGB到YCbCr的⾊彩空间变换:
Y = 0.299000R + 0.587000G + 0.114000B
Cb = -0.168736R - 0.331264G + 0.500002B
Cr = 0.500000R - 0.418688G - 0.081312B
其中,Y表⽰亮度分量,Cb和Cr表⽰蓝红⾊度分量。
DC电平偏移
最初,在图像中的像素存储在⽆符号的整数中。对于数学计算,在图像中任何变换或数学计算开始之前,根本上是将这些采样转换成两个补
码表⽰。DC电平偏移的⽬的是保证输⼊图像的采样有近似地集中在零附近的动态范围。DC电平偏移执⾏的图像采样只通过⽆符号数表⽰。
⽅法:假设图⽚分量的采样精度为n,那么分量中的每个像素值应减去2的(n-1)次幂。
对于图像⽽⾔他的采样由⽆符号的整数表⽰,例如CT(X光断层成像)图像,动态范围已经集中于零附近,所以不需要DC电平偏移。
⼦采样
⾊彩空间转换之后,图像的⼤多数空间信息包含在亮度分量Y中。⾊度分量Cb和Cr包含⼤量冗余的颜⾊信息,所以我们运⽤⼦采样较少⾊度数据量以在丢失少量信息的情况下压缩图像。基线JPEG常⽤的⼦采样格式为4:2:0,同时⽀持4:2:2和4:4:4颜⾊格式。
DCT变换
DCT(DiscreteCosineTransform)是将图像信号在频率域上进⾏变换,分离出⾼频和低频信息的处理
过程。然后再对图像的⾼频部分(即图像细节)进⾏压缩,以达到压缩图像数据的⽬的。⾸先将图像划分为多个8*8的矩阵。然后对每⼀个矩阵作DCT变换。变换后得到⼀个频率系数矩阵,其中的频率系数都是浮点数。
量化
由于在后⾯编码过程中使⽤的码本都是整数,因此需要对变换后的频率系数进⾏量化,将之转换为整数。由于进⾏数据量化后,矩阵中的数据都是近似值,和原始图像数据之间有了差异,这⼀差异是造成图像压缩后失真的主要原因。
在这⼀过程中,质量因⼦的选取⾄为重要。值选得过⼤,可以⼤幅度提⾼压缩⽐,但是图像质量就⽐较差;反之,质量因⼦越⼩(最⼩为1),图像重建质量越好,但是压缩⽐越低。对此,ISO已经制定了⼀组供JPEG代码实现者使⽤的标准量化值。
右图的两个量化表的设计是根据由Lohscheller做的⼼理视觉实验来确定⼆维基函数的可见阈值。
编码
从前⾯过程我们可以看到,颜⾊转换完成到编码之前,图像并没有得到进⼀步的压缩,DCT变换和量化可以说是为编码阶段做准备。
编码采⽤两种机制:⼀是0值的⾏程长度编码;⼆是熵编码(EntropyCoding)。
之字形排序(Zig-zag ordering)
在JPEG中,采⽤曲徊序列,即以矩阵对⾓线的法线⽅向作“之”字排列矩阵中的元素。这样做的优点是使得靠近矩阵左上⾓、值⽐较⼤的元素排列在⾏程的前⾯,⽽⾏程的后⾯所排列的矩阵元素基本上为0值。
使⽤RLE对交流系数(AC)进⾏编码
⾏程长度编码是⾮常简单和常⽤的编码⽅式,在此不再赘述。
需要注意的是,AC系数的之字形序列编码中有两个特殊符号——(0,0)和(15,0)。第⼀个特殊符号指的是块的结束(end-of-block,EOB),⽤来表明在之字形块中剩余的元素都是零。另⼀个特殊符号是指零游程长度(zero-run-length,ZRL),⽤来表明16个零游程。基线JPEG允许的零游程最⼤长度是16个。如果这⾥的零超过16个,那么这个游程分成⼏个长度为16的零游程。
使⽤DPCM对直流系数(DC)进⾏编码
DCT系数量化之后,通过差分编码对量化后的DC系数编码。当前块的DC系数减去前个块的DC系数,然后对其差值进⾏编码,如右图所⽰。这就利⽤了邻接块DC值之间的空间相关性。
熵编码:编码实际上是⼀种基于统计特性的编码⽅法。在JPEG中允许采⽤HUFFMAN编码或者算术编码。⽽基线JPEG算法(baseline sequential)采⽤的是前者。
经过RLE编码的AC系数可以映射成两个标志(RUNLENGTH,CATEGORY)和(AMPLITUDE),前者采⽤的是霍夫曼编码,⽽后者采⽤的是VLI编码。同理经过DPCM编码的DC系数同样可以映射成两个标志(CATEGORY)和(AMPLITUDE),前者采⽤霍夫曼编码,后者采⽤VLI编码。
基线JPEG允许使⽤4个霍夫曼表,两个⽤于AC系数编码,两个⽤于DC系数编码。
如何识别JEPG⽂件的
其实很简单,就是判断前⾯3个字节是什么,如果发现是FF D8 FF开始,那就认为它是JEPG图⽚。
JPG⽂件是由⼀段段的数据构成的组成的(segment),段的多少和长度并不是⼀定的。只要包含了⾜够的信息,该JPEG⽂件就能够被打
JPEG格式和标记
JPEG图⽚格式组成部分:SOI(⽂件头)+APP0(图像识别信息)+ DQT(定义量化表)+ SOF0(图像基本信息)+ DHT(定义Huffman 表) + DRI(定义重新开始间隔)+ SOS(扫描⾏开始)+ EOI(⽂件尾)
以16进制模式打开JPG⽂件,就会发现
JPEG ⽂件中有⼀些形如 0xFF** 这样的数据,它们被称为“标志(Marker)”,它表⽰ JPEG 信息数据段。例如 0xFFD8 代表 SOI(Start of image), 0xFFD9 代表 EOI(End of image)。
标志 0xFFE0~0xFFEF 被称为 "Application Marker",它们不是解码 JPEG ⽂件必须的,可以被⽤来存储配置信息等。EXIF 也是利⽤这个标志段来插⼊信息的,具体来说,是 APP1(0xFFE1) Marker。所有的 EXIF 信息都存储在该数据段。
------------------
名称标记码说明
------------------
SOI  D8    ⽂件头
EOI  D9    ⽂件尾
SOF0  C0    帧开始(标准 JPEG)
SOF1  C1    同上
DHT  C4    定义 Huffman 表(霍夫曼表)
SOS  DA    扫描⾏开始
DQT  DB    定义量化表
DRI  DD    定义重新开始间隔
APP0  E0    定义交换格式和图像识别信息
DNL  DC    标记码
COM  FE    注释
段类型有30种,但只有10种是必须被所有程序识别的,其它的类型都可以忽略。
JPEG format and Marker
SOI Marker Marker XX size=SSSS Marker YY size=TTTT SOS Marker size=UUUU Image stream EOI Marker
FFD8FFXX FFYY FFDA I I FFD9
0xFFE0~0xFFEF之间的标记被叫做 "应⽤标记", 它们在JPEG图像解码中不是必须存在的. 它们被使⽤于⽤户的应⽤程序之中. 例如, ⽼款的olympus/canon/casio/agfa 数字相机使⽤ JFIF(JPEG⽂件交换格式/JPEG File Interchange Format)来存储图像. JFIF 使⽤ APP0(0xFFE0) 标记来插⼊数字相机的配置信息数据和缩略图.
Exif也使⽤应⽤标记来插⼊数据, 但是Exif 使⽤ APP1(0xFFE1)标记来避免与JFIF格式的冲突. 且每⼀个 Exif ⽂件格式都开始于它, 如
SOI 标记标记 XX 的⼤⼩=SSSS标记 YY 的⼤⼩=TTTT SOS 标记的⼤⼩=UUUU图像数据流EOI 标记
FFD8FFXXlo0p FFYY FFDA I I FFD9
Exif也使⽤应⽤标记来插⼊数据, 但是Exif 使⽤ APP1(0xFFE1)标记来避免与JFIF格式的冲突. 且每⼀个 Exif ⽂件格式都开始于它, 如;
Marker used by Exif
0xFF+Marker Number(1 byte)+Data size(2 bytes)+Data(n bytes)
SOI Marker APP1 Marker APP1 Data Other Marker
FFD8FFE1SSSS FFXX
该图像⽂件从SOI(0xFFD8) 标记开始, 因此它是⼀个 JPEG ⽂件. 后⾯马上跟着 APP1 标记. ⽽它的所有 Exif数据都被存储在 APP1 数据域中.上⾯的 "SSSS" 这部分表⽰ APP1 数据域 (Exif data area)的⼤⼩. 请注意这⾥的⼤⼩ "SSSS" 包含描述符本⾝的⼤⼩.
在 "SSSS"后⾯, 是 APP1 的数据. 其中第⼀个部分是⼀个特殊的数据,它⽤来标识是否是 Exif, 其值是ASCII 字符 "Exif" 和两个0x00字节的组合字符串.
在 APP1 标记域的后⾯是, 跟随着其他的 JPEG 标记
exif数据解析
如果图⽚图⽚是16进制数据,如下:
FF D8  FF E0 00 10 4A 46 49 46 00 01 02 01 00 60 00 60  00 00  FF E1 08 32 45 78 69 66 00 00 49 49 10 60 00 60  20 00 …… FFD9
那么FF D8为SOI标志位,FF E0为exif⽂件起始位,后⾯四位为exif marker信息的长度。取这个长度的数据解析为TIFFdata数据,exif直接解析为字符串貌似也没有问题。
FF E0 00 10 4A 46 49 46 00 01 02 01 00 60 00 60  00 00        mark0,00 10 =16位
FF E1 08 32 45 78 69 66 00 00 49 49 10 60 00 60  20 00 …… mark1,00 10 =2098位
……
Image stream
FFD9
jpeg⼆进制代码源码分析
每个段都是由FFxx开头,其中xx是段的标识,接着就是就是两位的端长度。后⾯跟着的就是数据。前⾯的元数据外读取完成后,后⾯的⼆进制数据就是图⽚数据。
数据⼤⼩描述符(2个字节) 是 "Motorola" 的字节顺序, 数据的低位被存放在⾼地址,也就是 BigEndian. 请注意上⾯中的 "数据内
容" 中包含他前⾯的数据⼤⼩描述符, 如果下⾯的是⼀个标记的话;
这个长度的表⽰⽅法是按照⾼位在前,低位在后的,与 Intel 的表⽰⽅法不同。⽐⽅说⼀个段的长度是0x12AB,那么它会按照0x12,0xAB 的顺序存储。但是如果按照Intel的⽅式:⾼位在后,低位在前的⽅式会存储成0xAB,0x12,⽽这样的存储⽅法对于JPEG是不对的。这样的话如果⼀个程序不认识JPEG⽂件某个段,它就可以读取后两个字节,得到这个段的长度,并跳过忽略它。
关于exif信息解码,请阅读《》
jpeg10中必须的段类型
这⾥列举10种必备的段类型
APP0图像识别信息
-------------------------------------------------
名称字节数值说明
-------------------------------------------------
段标识      1    FF
段类型      1    E0
段长度      2    0010              如果有RGB缩略图就=16+3n
  (以下为段内容)