各位老铁们,大家好,今天由我来为大家分享深入解析JPEG文件格式:解码算法与关键技术详解,以及的相关问题知识,希望对大家有所帮助。如果可以帮助到大家,还望关注收藏下本站,您的支持是我们最大的动力,谢谢大家了哈,下面我们开始吧!
(2) 压缩数据;完整的两字节标记码后面是该标记码对应的压缩数据,记录了文件的一些信息。
一些典型的标记代码及其含义如下:
SOI,Start Of Image,图像开始,标记码为固定值0XFFD8,用2个字节表示;
APP0,应用程序0,应用程序保留标记0,标记码为固定值0XFFE0,用2个字节表示;标记代码包含9个特定字段:
(1)数据长度:2字节,用于表示(1)-(9)9个字段的总长度,即不包括标签码但包括该字段;
(2)标识符:5个字节,固定值为0X4A6494600,代表字符串“JFIF0”;
(3)版本号:2字节,通常为0X0102,表示JFIF版本号为1.2;但也可以是其他值,从而代表其他版本号;
(4)X、Y方向的密度单位:1字节,只有三个值,0:无单位; 1:每英寸点数; 2:每厘米点数;
(5) X方向像素密度:2字节,取值范围未知;
(6) Y方向像素密度:2字节,取值范围未知;
(7)缩略图水平像素数:1字节,取值范围未知;
(8)缩略图垂直像素数:1字节,取值范围未知;
(9)缩略图RGB位图:长度可以是3的倍数,保存24位RGB位图;如果没有缩略图位图(这个比较常见),字段(7)的值(8)的值都为0;
APPn,应用程序n,应用程序保留标记n(n=1---15),标记代码为2字节,值为0XFFE1--0XFFFF;它包含两个字段:
(1)数据长度,2字节,表示(1)(2)两个字段的总长度;即不包含标签代码,但包含该字段;
(2)详细信息:数据长度-2字节,内容可变;
DQT,Define Quantization Table,定义量化表;标记码为固定值0XFFDB;它包含9个特定字段:
(1)数据长度:2字节,表示(1)和多个(2)字段的总长度;即不包含标签代码,但包含该字段;
(2)量化表:数据长度——2字节,包括以下内容:
(a)精度和量化表ID,1字节,高4位代表精度,只有两个可选值,0:8位; 1:16位;低4位表示量化表ID,取值范围为0-- 3;
(b) 表条目,64(精度值+1)字节。例如,8位精度量化表的表项长度为64(0+1)=64字节;
在该标签部分中,(2)可以重复出现,表示多个量化表,但最多只能出现4次;
SOFO,Start Of Frame,帧图像的开始,标记码为固定值0XFFC0;它包含9个特定字段:
(1)数据长度:2字节,(1)-(6)6个字段总长度;即不包含标签代码,但包含该字段;
(2)精度:1字节,表示每个数据样本的位数;通常为8 位;
(3)图像高度:2字节,表示图像高度,以像素为单位。如果不支持DNL,则必须大于0;
(4)图像宽度:2字节,表示图像宽度,以像素为单位。如果不支持DNL,则必须大于0;
(5)颜色分量数:1字节。由于JPEG使用YCrCb色彩空间,因此这里始终为3;
(6)颜色分量信息:颜色分量个数*3字节,这里通常为9字节;并据此表达以下信息:
(a)颜色分量ID:1字节;
(b)水平/垂直采样因子:1字节,高4位代表水平采样因子,低4位代表垂直采样因子;
(c) 量化表:1字节,当前组件使用的量化表ID;
在这个标签部分,字段(6)应该重复3次,因为有3个颜色分量;
DHT,Define Huffman Table定义哈夫曼表,标签代码为0XFFC4;它包含2 个字段:
(1)数据长度,2字节,表示(1)-(2)的总长度,即不包括标签码,但包括该字段;
(2)哈夫曼表,数据长度-2字节,包含以下字段:
(a)表ID和表类型,1字节,高4位表示表的类型,只有两个值; 0:DC直流电; 1:交流交流;低4位,哈夫曼表ID;需要提醒的是,DC表和AC表是分开编码的;
(b) 不同位数的码字数量,16字节;
(c)编码内容,16位不同数字的码字数(字节)之和;
在该标签部分中,字段(2)可以重复出现,一般需要重复4次。
DRI,Define Restart Interval,定义差分编码累积复位的时间间隔,标志码为固定值0XFFDD;
包含2个特定字段:
(1)数据长度:2字节,值为固定值0X0004,表示(1)(2)两个字段的总长度;即不包含标签代码,但包含该字段;
(2) 以MCU块为单位的重启间隔:2字节。如果值为n,则表示每n个MCU块有一个RSTn标记;第一个标记是RST0,第二个标记是RST1、RST7,然后从RST0开始重复;如果没有这个标记段,或者间隔值为0,则表示没有重启间隔,标记RST;
SOS,Start Of Scan,扫描开始;标记代码为0XFFDA,其中包含2个特定字段:
(1)数据长度:2字节,表示(1)-(4)字段的总长度;
(2)颜色分量数量:1字节,只有3个可选值,1:灰度图像; 3:YCrCb或YIQ; 4:四色;
(3)颜色成分信息:包括以下字段,
(a)颜色分量ID:1字节;
(b) DC/AC系数表ID,1字节,高4位表示DC分量的哈夫曼表的ID;低4位表示AC分量的哈夫曼表的ID;
(4) 压缩图像数据
(a) 频谱选择起始:1字节,固定值为0X00;
(b) 频谱结束选择:1字节,固定值0X3F;
(c) 频谱选择:1字节,固定值0X00;
在这个标记部分,(3)应该重复出现,出现的次数与颜色分量的数量一样多;本节结束后,就是真实的图像信息;图像信息直到遇到EOI标记为止;
EOI,End Of Image,图像结束;标记代码为0XFFD9;
另外,需要注意的是,0XFF在JPEG中具有标记的含义,因此在压缩数据流(真实图像信息)中,如果出现0XFF,则需要进行特殊处理。方法是,如果在图像数据流中遇到0XFF,则应该检测紧跟其后的字符,如果是:
(1)0X00,表示0XFF是图像流的一个组成部分;需要解码;
(2)0XD9,代表与0XFF组成的标记EOI,即代表图像流的结束和图像文件的结束;
(3)组成RSTn标记的0XD0--0XD7,需要忽略整个RSTn标记,即不对当前0XFF及后面的0XDn字节进行解码,并根据RST标记的规则调整解码变量;
(4)0XFF,忽略当前的0XFF,判断下一个0XFF;
(5)其他值,突然当前值为0XFF,保留后面的值进行解码;
需要注意的是,JPEG文件格式中,一个字(16位)的存储采用的是Motorola格式,而不是Intel格式。也就是说,一个字的高字节(高8位)在数据流的前面,低字节(低8位)在数据流的后面,这与通常的Intel格式不同。这个字节顺序问题的根源在于早期的硬件开发。在8位CPU时代,很多8位CPU都可以处理16位数据,但显然是处理了两次。这时候就出现了是先处理高位字节还是先处理低位字节的问题。以Intel为代表的厂家生产的CPU采用先低字节后高字节的方式;而以Motorola、IBM为代表的厂家生产的CPU则采用先高字节后低字节的方式。 Intel的字节顺序也称为little-endian,而Motorola的字节顺序称为big-endian。 JPEG/JFIF 文件格式使用大端格式。以下函数实现了intel格式到motorora格式的转换
USHORT Intel2Moto(USHORT val)
{
字节高位=字节(val/256);
字节低位=字节(val % 256);
返回低位* 256 + 高位;
}
解码
1) 读取JPEG/JFIF文件的相关信息
根据JFIF文件格式,将JPEG文件相关的字段信息一一读出并进行相应分析。例如图像宽度、高度、量化表、哈夫曼表、水平/垂直采样因子等。一般来说,JFIF格式文件的读取顺序是:
SOI领域;
APP0 字段;
APPn 字段;
DQT 字段;
SOFO领域;
DHT领域;
求救场;
压缩数据字段;
意向书字段;
在阅读JPEG文件相关信息时,有两点需要特别注意:
(a)由于0XFF在JPEG中被用作特殊标记,如果某个像素的值为0XFF,那么在保存时实际上将其保存为0XFF00,从而避免了它与特殊标记0XFF的混淆。出现混乱。因此,在读取文件信息时,如果遇到0XFF00,必须去掉后面的00;即把0XFF00当作0XFF处理;
(b) 在JPEG 文件中,一个字(16 位)以Motorola 格式(big-endian)存储,而不是我们常用的Intel 格式(little-endian)。因此,如有必要,请在进程之间执行顺序的高低字节转换。
(2)读取哈夫曼表
在标签代码DHT之后,包含一张或多张哈夫曼表(通常是4张表)。对于哈夫曼表来说,它包含以下三个部分:
(a) 表ID 和表类型; 1字节;只有4个可选值,0X00、0X01、0X10、0X11,分别代表DC表号0、DC表号1、AC AC表号0、AC AC表号1;
(b) 不同数字的码字的数量;前面提到,JPEG中的霍夫曼编码表是按照编码长度中的位数来存储的,而霍夫曼编码表的位数只能是1--16位,因此,使用了16个字节这里表示哈夫曼树中从1到16位的每个位长编码的个数。
(c) 编码内容;该字段记录了哈夫曼树中每个叶子节点的权重。前一个字段中的16个值(不同位数的码字数量)之和就是这个字段的长度,也就是哈夫曼树中的叶子。节点数量。
这里,我们不妨以如下哈夫曼表中的数据为例来说明情况(均以十六进制表示):
11 00 02 02 00 05 01 06 01 00 00 00 00 00 00 00 00
00 01 11 02 21 03 31 41 12 51 61 71 81 91 22 13 32
上述数据串中的第一行代表哈夫曼表ID、表类型以及不同位数的码字数量;
第一行第一个字节0X11表示表的ID和类型,为AC AC表1号;
第一行的字节2至17表示不同位码字的数量。即第二个字节为00表示没有数字为1的代码;第3、4个字节中的02表示有两个数字为2的代码和一个代码为3的代码;第5 个字节00 表示没有5 位代码。另外,通过这些数据我们发现这棵哈夫曼树有0+2+2+0+5+1+6+1=17个叶子节点。
第二行编码内容显示,17个叶子节点按照从小到大的顺序排列,即权重分别为0,1,11,2,21,3,31,41……
(3) 构造哈夫曼树
从霍夫曼表中读取数据后,需要构建霍夫曼树。具体规则如下
(a) 第一个编码数必须为0;如果第一位编码数字为1,则编码为0;如果第一位编码数字为2,则编码为00;如果第一位编码数字为2,则编码为00;如果第一位编码数字为2,则编码为00;如果代码的位数为3,则编码为000。
(b) 从第二个代码开始,如果与前一个代码位数相同,则当前代码为前一个代码加1;如果它的码位数大于前面的码位数,则当前编码在编码时,在前面的编码上加1,然后在末尾添加几个0,直到满足编码位数的长度。
还是以上面的数据为例:
第一行第二个字节00表示没有数字1的编码;
第一行第三个字节02表示有2个数字为2的代码;由于没有数字为1的代码,所以这里的数字为2的代码中第一个是00,第二个是00+1=01;
第一行第四个字节02表示有2个3位数的代码;因此,这里的3位代码的第一个是01+1=10,然后加上1个“0”,得到100; 3位代码中的第二位是100+1=101;
依此类推,我们可以得到如下哈夫曼树
Snip20161124_1.png 特别提醒,如果中间缺少某位数字代码,例如没有4位代码,则应在3位代码后面加1,并添加2个“00”来补足5位数字,组成下面的A 5位代码。
(4) DC系数的霍夫曼解码
在JPEG编码阶段,我们提到DC系数以(A,B)的中间形式进行编码。 A表示B的二进制编码位数,B使用VLI进行编码。另外,对88位图像块进行DCT变换后得到的88位系数矩阵进行Huffman编码和RLE编码。当写入编码数据时,DC系数也被写入数据流的前面。因此,在解码时,也先读出DC系数。假设我们一次读入几个字节的数据。第一个字节表示DC系数的霍夫曼码。通过查找DC系数的霍夫曼表(亮度表或色度表),得到霍夫曼码的组号。这个数字就是DC系数中间格式(A,B中的A)是B中的位数。例如A=2表示B使用2位二进制数进行编码。这样,读取下一个A位二进制数,解码成十进制,就可以得到DC系数的差值。将该差值与之前的DC 系数值相加,即可得到当前的实际DC 系数值。
(5)AC系数的霍夫曼解码
处理完DC系数后,下一步就是对AC系数进行解码。显然,这里还是需要读一个哈夫曼码。通过查找AC系数的哈夫曼编码表并解码,得到(A,B)的数据对,A代表0的个数,B代表后面数据的位数。例如,(2,3)表示当前AC系数前有2个0,接下来要读取的二进制数据为3位。需要提醒的是,(0,0)代表EOB,即块88编码结束。然后,读取B位二进制数据并解码,即可得到AC系数的值。重复这个循环,直到遇到EOB或者读取到63个AC系数,我们就完成了88块系数矩阵的解码。
(6) 反量化
解码得到88的系数矩阵后,我们需要进行反量化工作。这一步是将上一步得到的88个系数矩阵乘以8*8的量化矩阵。
(7) 防锯齿扫描
在JPEG编码过程中,为了编码方便,采用Zig-zag扫描。因此,需要进行逆Zig-zag扫描,重新排列88逆量化系数矩阵。 anti-Zig-zag扫描的输入是88的矩阵,输出仍然是8*8的矩阵,只是数据的排列方式不同。
(8) DCT逆变换
DCT变换将原始图像变换到频域,而逆DCT变换将数据从频域变换回时域。
DCT逆变换的计算公式为:
![正在上传1345131501_6624_203673.png。]DCT逆变换的公式可以改写为:
1345131501_6624.png 其中A 是矩阵:
1345131617_8476.png1345131629_6848.png1345131650_4581.png 左边是Rank转换前的数据顺序,右边是Rank转换后的数据顺序。
END,本文到此结束,如果可以帮助到大家,还望关注本站哦!
【深入解析JPEG文件格式:解码算法与关键技术详解】相关文章:
2.米颠拜石
3.王羲之临池学书
8.郑板桥轶事十则
用户评论
终于明白 JPEG 格式是怎么让图片这么小的了!
有6位网友表示赞同!
学习一下解码算法,也许能自己写个 JPEG 查看器?
有11位网友表示赞同!
想试试用别的软件打开 JPEG 文件看看效果区别。
有11位网友表示赞同!
我一直以为 JPEG 就是 JPG 的缩写,原来还有详细的介绍和算法啊!
有7位网友表示赞同!
以前没注意过图片格式,现在才知道这么多细节隐藏着。
有6位网友表示赞同!
JPEG 处理技术真是厉害,还能压缩成这么小文件。
有7位网友表示赞同!
学习了 JPEG 文件格式知识,能更好地选择合适的图片格式。
有10位网友表示赞同!
原来照片压缩是用算法决定的啊!感觉很神奇!
有11位网友表示赞同!
解码算法太复杂了,我只能看着这个介绍慢慢理解。
有8位网友表示赞同!
想知道 JPEG 格式还有什么别的优缺点 besides 图片大小?
有8位网友表示赞同!
我想知道不同类型 JPEG 文件的差异?
有13位网友表示赞同!
这篇文章写的很详细,很好理解!
有20位网友表示赞同!
以后上传图片的时候能根据需要选择合适的 JPEG 格式了。
有16位网友表示赞同!
了解这些知识以後,对数字图像处理更有兴趣了。
有8位网友表示赞同!
这篇文章很有帮助,感谢作者的分享!
有14位网友表示赞同!
我平时做平面设计经常用 JPEG 文件格式,现在更了解它了!
有7位网友表示赞同!
希望以后还能学到更多关于图片格式的知识!
有6位网友表示赞同!
学习图片压缩算法很有趣,可以尝试去自己实现一下!
有9位网友表示赞同!