JPEG/Exif/TIFF格式解读(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的文件改名为.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由于可以提供有损压缩,因此压缩比可以达到其他传统压缩算法无法比拟的程度。其压缩模式有以下几种:
-
顺序式编码(SequentialEncoding)
-
递增式编码(ProgressiveEncoding)
-
无失真编码(LosslessEncoding)
-
阶梯式编码(HierarchicalEncoding)
JPEG的压缩步骤
-
颜色转换:由于JPEG只支持YUV颜色模式,而不支持RGB颜色模式,所以在将彩色图像进行压缩之前,必须先对颜色模式进据转换。转换完成之后还需要进行数据采样。一般采用的采样比例是2:1:1或4:2:2。由于在执行了此项工作之后,每两行数据只保留一行,因此,采样后图像数据量将压缩为原来的一半。
-
DCT变换:DCT(DiscreteConsineTransform)是将图像信号在频率域上进行变换,分离出高频和低频信息的处理过程。然后再对图像的高频部分(即图像细节)进行压缩,以达到压缩图像数据的目的。首先将图像划分为多个8*8的矩阵。然后对每一个矩阵作DCT变换(变换公式此略)。变换后得到一个频率系数矩阵,其中的频率系数都是浮点数。
-
量化:由于在后面编码过程中使用的码本都是整数,因此需要对变换后的频率系数进行量化,将之转换为整数。由于进行数据量化后,矩阵中的数据都是近似值,和原始图像数据之间有了差异,这一差异是造成图像压缩后失真的主要原因。
-
编码:编码采用两种机制:一是0值的行程长度编码;二是熵编码(EntropyCoding)。在JPEG中,采用曲徊序列,即以矩阵对角线的法线方向作“之”字排列矩阵中的元素。这样做的优点是使得靠近矩阵左上角、值比较大的元素排列在行程的前面,而行程的后面所排列的矩阵元素基本上为0值。行程长度编码是非常简单和常用的编码方式,在此不再赘述。编码实际上是一种基于统计特性的编码方法。在JPEG中允许采用HUFFMAN编码或者算术编码。
更详细可以参看《色彩空间RGB/CMYK/HSL/HSB/HSV/Lab/YUV基础理论及转换方法:RGB与YUV》、《视频采样,量化,编码,压缩,解码相关技术原理学习笔记 》
Baseline JPEG/基本JPEG:这种类型的JPEG文件存储方式是按从上到下的扫描方式,把每一行顺序的保存在JPEG文件中。打开这个文件显示它的内容时,数据将按照存储时的顺序从上到下一行一行的被显示出来,直到所有的数据都被读完,就完成了整张图片的显示。这种图片在web中,如果没有给图片指定宽高,会造成重绘。
progressive jpeg/渐进式JPEG:JPEG文件包含多次扫描,这些扫描顺寻的存储在JPEG文件中。打开文件过程中,会先显示整个图片的模糊轮廓,随着扫描次数的增加,图片变得越来越清晰。该类型的图片是对标准JPEG格式的改进,当在网页上下载渐进式JPEG图片时,首先呈现图片的大概外貌,然后再逐渐呈现具体的细节部分,因而被称之为渐进式JPEG。这种通过HTTP2 多路复用传递渐进式JPEG的扫描图层来提高感知性能和速度指数的方式已经早在2012年被Google的John Mellor 注意到了。他一直在实验SPDY协议,HTTP2的前身。
JPEG2000:一种全新的图片压缩发,压缩品质更好,并且改善了无线传输时,因信号不稳定而造成的马赛克及位置错乱等问题。另外,作为JPEG的升级版,JPEG2000的压缩率比标准JPEG高约30%,同时支持有损压缩和无损压缩。它还支持渐进式传输,即,先传输图片的粗略轮廓,然后,逐步传输细节数据,使得图片由模糊到清晰逐步显示。此外,JPEG2000还支持感兴趣区域,也就是说,可以指定图片上感兴趣区域的压缩质量,还可以选择指定的部分先进行解压。还有个优势就是,JPEG2000从无损压缩到有损压缩可以兼容
压缩步骤
由于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 | ||||||
FFD8 | FFXX | SSSS | DDDD...... | FFYY | TTTT | DDDD...... | FFDA | UUUU | DDDD.... | I I 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 标记 | ||||||
FFD8 | FFXXlo0p | SSSS | DDDD...... | FFYY | TTTT | DDDD...... | FFDA | UUUU | DDDD.... | I I 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 |
FFD8 | FFE1 | SSSS 457869660000 TTTT...... | FFXX SSSS DDDD...... |
该图像文件从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 D8
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
每个段都是由FFxx开头,其中xx是段的标识,接着就是就是两位的端长度。后面跟着的就是数据。前面的元数据外读取完成后,后面的二进制数据就是图片数据。
数据大小描述符(2个字节) 是 "Motorola" 的字节顺序, 数据的低位被存放在高地址,也就是 BigEndian. 请注意上面中的 "数据内容" 中包含他前面的数据大小描述符, 如果下面的是一个标记的话;
这个长度的表示方法是按照高位在前,低位在后的,与 Intel 的表示方法不同。比方说一个段的长度是0x12AB,那么它会按照0x12,0xAB的顺序存储。但是如果按照Intel的方式:高位在后,低位在前的方式会存储成0xAB,0x12,而这样的存储方法对于JPEG是不对的。这样的话如果一个程序不认识JPEG文件某个段,它就可以读取后两个字节,得到这个段的长度,并跳过忽略它。
关于exif信息解码,请阅读《JPEG/Exif/TIFF格式解读(2):图片元数据保存及EXIF详解》
jpeg10中必须的段类型
这里列举10种必备的段类型
APP0图像识别信息
------------------------------------------------- 名称 字节数 值 说明 ------------------------------------------------- 段标识 1 FF 段类型 1 E0 段长度 2 0010 如果有RGB缩略图就=16+3n (以下为段内容) 交换格式 5 4A46494600 “JFIF”的ASCII码 主版本号 1 次版本号 1 密度单位 1 0=无单位;1=点数/英寸;2=点数/厘米 X像素密度 2 水平方向的密度 Y像素密度 2 垂直方向的密度 缩略图X像素 1 缩略图水平像素数目 缩略图Y像素 1 缩略图垂直像素数目 (如果“缩略图X像素”和“缩略图Y像素”的值均>0,那么才有下面的数据) RGB缩略图 3×n n=缩略图像素总数=缩略图X像素×缩略图Y像素
说明:
-
JFIF是JPEG File Interchange Forma的缩写,即JPEG文件交换格式,另外还有TIFF等格式,很少用
-
“如果有RGB缩略图就=16+3n”是什么意思呢?比如说“缩略图X像素”和“缩略图Y像素”的值均为48,就表示有一个48×48像素的缩略图(n=48×48),缩略图是24位真彩位图,用3个字节来表示一个像素,所以共占用3n个字节。但大多数JPG文件都没有这个“鸡肋”缩略图。
DQT定义量化表
-------------------------------------------------------------------------- 名称 字节数 值 说明 -------------------------------------------------------------------------- 段标识 1 FF 段类型 1 DB 段长度 2 43 其值=3+n(当只有一个QT时) (以下为段内容) QT信息 1 0-3位:QT号 4-7位:QT精度(0=8bit,1字节;否则=16bit,2字节) QT n n=64×QT精度的字节数
说明:
-
JPEG文件一般有2个DQT段,为Y值(亮度)定义1个, 为C值(色度)定义1个。
-
一个DQT段可以包含多个QT, 每个都有自己的信息字节
参考资料:
图片文件Exif信息详细说明 blog.sina.com.cn/s/blog_651251e60102uz3d.html#AboutExif
图像Exif信息 元数据(Metadata) https://www.jianshu.com/p/a6d67df60e7e
关于图片文件旋转JPEG与EXIF信息 https://blog.csdn.net/yulimin/article/details/102827865
https://www.media.mit.edu/pia/Research/deepview/exif.html
https://baike.baidu.com/item/Exif/422825?fr=aladdin
读取JPG图片的Exif属性(一) - Exif信息简介 https://blog.csdn.net/fioletfly/article/details/53605959
读取JPG图片的Exif属性(二) - C代码实现 https://blog.csdn.net/fioletfly/article/details/54094940
读取JPG图片的Exif属性(三) - Exif属性读取GPS信息代码(C/C++实现)https://blog.csdn.net/fioletfly/article/details/54133422
在jpg图片添加Exif信息的C程序实现 https://blog.csdn.net/psy6653/article/details/79658144
JPEG添加EXIF https://blog.csdn.net/weixin_43549602/article/details/84654965
jpeg图片格式详解 https://blog.csdn.net/yun_hen/article/details/78135122
压缩算法——JPEG2000 编解码原理 https://blog.csdn.net/ytang_/article/details/76571635
PNG、JPEG、BMP等几种图片格式详解 https://www.jianshu.com/p/f5557c0e689e
使用HTTP2和渐进式JPEG图片更快的加载图像 https://www.zcfy.cc/article/performance-calendar-raquo-even-faster-images-using-http2-and-progressive-jpegs-2216.html
转载本站文章《JPEG/Exif/TIFF格式解读(1):JEPG图片压缩与存储原理分析》,
请注明出处:https://www.zhoulujun.cn/html/theory/multimedia/CG-CV-IP/8396.html