JPEG原理详细2

21 篇文章 2 订阅

如06对应 Huffman 表的111000,那么

  69 = (4,5) --- 1111111110011001 (69=0x45=4*16+5 )

  21 = (1,5) --- 11111110110

  从而得到最后的结果:

  111000 111001 ; 111000 101101 ; 1111111110011001 10111 ; 11111110110 00001…

  使用范式 Huffman 编码表的好处就是使得出现频率高的数字小于8位,而出现频率低的数字大于8位,这样对整体而言,就会极大地减少数据量。

  需要注意的是,在 JPG 文件中,一般有两个 Huffman 表,一个是 DC 用,一个是 AC 用,它们是类似的。

  对 DC 编码的部分是单独来处理的,并且是放在上面这个串的最前面。

  总体来说,到目前为止,我们就得到了最后需要真正存储用的简化后,也即压缩后的数据了。

  四、JPEG文件存储格式

  介绍了 JPEG 的原理,我们再来结合一个具体的实例来详细讨论上面所涉及到的细节。

  我们先来制作一个简单的8X8大小的像素图,然后把它存成JPEG格式。

  方法是用 windows 的画图工具,定义一个8X8大小的图,用一些色块填充进去,然后另存为 JPEG 格式,如 test8x8.jpg。如下图所示:

保存成的文件后缀为 jpg,但按标准来说,它是一种 JFIF 格式标准的文件,里面的图像的压缩方式是 JPEG。

  JFIF 是一个文件格式标准,JPEG 是一个压缩标准,总体来说它们不是一个概念。

  JFIF 是 JPEG File Interchange Format 的缩写,也即 JPEG 文件交换格式。JFIF 是一个图片文件格式标准,它是一种使用 JPEG 图像压缩技术存储摄影图像的方法。JFIF 代表了一种"通用 语言 "文件格式,它是专门为方便用户在不同的计算机和应用程序间传输 JPEG 图像而设计的语言。

JFIF 文件格式定义了一些内容是 JPEG 压缩标准未定义的,如 resolution/aspect ratio,color space 等。

  

 我们可以打开 JPEG 文件查看里面的内容,即可看到上面的各个标记段:

从图上可以看出:

  在头部有 FFD8 ,表示图像的开始;结束部分有 FFD9 ,表示图像的结束。

  在中间有两个量化表 DQT 对应的标记 FFDB ;

  还有图像大小信息对应的 FFC0

  再后面有四个 Haffman 表对应的 FFC4 ;

  一般一个 JPG 文件里会有 2 类 Haffman 表:一个用于 DC 一个用于 AC ,也即实际有 4个表,亮度的 DC,AC 两个,色度的 DC,AC 两个。

  然后是图像数据段标记 FFDA;

  我们再来看看各个标记的细部,具体分析一下各个部分的含义。

  1、图片的识别信息

上面的内容,在标记 FFE0 后,即为长度16。然后是5字节的 JFIF 标识符号,说明这是一个 JPEG 压缩的文件。然后是主/次版本号码。下一个为 XY 像素的单位,这里为1,表示单位为点数/英寸。然后是 XY 方向的像素密度,这里是 96DPI,最后是缩略图有关信息,这里为0。

  2、量化表的实例

上面这个内容,FFDB 标记后的长度值为67,接下来的是 QT 信息,占一个字节;这里是0,表示这个 QT 表编号为0,并且精度是8bit。然后后面就是64个8x8的 QT 表的各个 item 了。

  也即第一个 DQT 量化表的内容表示为十进制是:

这个表即为 JPEG 亮度量化表。

  第二个量化表的内容为:

这个表的内容即为 JPEG 色度量化表。

  当你打开不同的 JPEG 文件,你会看到这两个表可能也是会有区别的。这个主要是使用了不同的量化方式的结果。

  3、图像信息段  

上面这个内容,FFC0 标记后即是长度,为17,然后是一个字节的数据精度,通常是为8,代表样本位数。接下来是图片的高度,占两字节,这里即为8,然后是图片的宽度,也为8,这也就是我们定义的8x8的内容。然后是 component 的个数,这里是3,表示 YUV。接下来是三组数据,每组数据里,第一个是 component ID,第二个是采样系数,这里 Y 的采样系数为22,说明垂直是2,水平是2。再后面就是量化表的编号了。
4、Haffman 表的实例
上面这个内容,FFC4 标记后的内容为数据长度,再接着的1字节为 Huffman Table 的信息,低4位是 HT ID 号,第5位是 HT 表类型标记,再高三位是为0。

  第一个 DHT 表,00,类型为 DC table,HT ID 号为 0;

  第二个 DHT 表,10,类型为 AC table,HT ID 号也为 0;

  第三个 DHT 表,01,类型为 DC table,HT ID 号为 1;

  第四个 DHT 表,11,类型为 AC table,HT ID 号为 1;

  即前两个表为Y亮度分量的 DC/AC 表,后两个为 UV 色度分量的 DC/AC 表。

  以第一个表为例,因为长度只有 31,那么 00 后面的 16 字节,即绿色部分:

  

组号为 1 的组中,代码有 0 个;

  组号为 2 的,代码有 1 个;

  组号为 3 的代码有 5 个;

  组号为 4/5/6/7/8/9 的代码各 1 个。

  总共 12 个。

  再看后续的数据:

  00 01 02 03 04 05 06 07 08 09 0A 0B

  即对应:

其他未出现的组号,对应的数据未使用到。也就是说前面提到过的范式 Huffman 编码里,目前只使用部分数据即可,原因是这个 8x8 的图像数据很小。

第二个 DHT 表就更复杂些了,长度有 181。

  5、图像数据段

这里 SOS 段,长度为 12,后面所含有的 component 数量为 3 个,也即 Y UV。然后后面是各 component 的编号,及对应所使用的 Huffman 表的 ID 是多少。

  在这个段的后面就是所有压缩后的数据。直到结束的问题,即 FFD9,EOI(End Of Image)。

  五、JPEG 压缩过程的优化

  JPEG 在目前的应用范围是非常广泛的,各种嵌入式系统中也大量地使用了 JPEG 压缩,如 IPCAM 摄像头、数字相机、移动存贮等。在这些领域由于传输数据的带宽限制或者是存贮数据的容量的限制,常常需要使用图像压缩技术来将原始大量的图像数据压缩后在进行传输或存贮,以充分利用带宽与存贮空间,达到更好的利用效率。这样,在嵌入系统中,就会使用到 JPEG 压缩。而且由于嵌入系统的资源有限的特点,在很多情况下,很需要再对 JPEG 编码压缩的过程做更进一步的优化,我们这里详细讨论一下如何实现这些优化。

  浮点运算的优化

  我们回头查看一下 JPEG 压缩中的 DCT 变换过程,公式:

由于公式中有两个 i/j=0~7 的部分,这样要获得一个 DCT 系数,需要做 8 x 8=64 次乘法和 8 x 8=64 次加法, 而完成整个 8 x 8 像素的 DCT 需要 8 x 8 x 8 x 8=4096 次乘法和 8 x 8 x 8 x 8=4096 次加法. 计算量是相当的大。
对于有些无浮点运算的嵌入式系统或无专门的数学运算协处理器的系统,会造成大量的运算,极大地占用CPU的资源。

  上面的公式属于 DCT 的二维计算方式,经过简化,可以将其简化为两个一维的公式:

这样,上面的过程就可以简化为分别计算行和列的 DCT 变换。

  对于一行来说需要计算的是 (8 x 8) 次乘法和 (8 x 8) 次加法,8 行就是 8 x (8 x 8) 次乘法和 8 x (8 x 8) 次加法,然后列也是相同,那么总数就为 2 x (8 x (8 x 8))=1024 次乘法和 2 x (8 x (8 x 8))=1024 次加法, 运算量变为二维计算的1/4。

  但是这样的运算数量还是太大,还需要进一步优化。

  在很多嵌入系统中,很多情况下需要不使用浮点运算,这样就需要再找出一维 DCT 的一些规律,然后对其进行进一步的优化。

  在对一维 DCT 的运算中,还可以分为奇数列/行和偶数列/行

对上面的处理,就又出现了多种优化:ChenDCT,LeeDCT,AAN 算法和 LLM 算法。

  其中 AAN 算法只需要 29 次加法和 5 次乘法。(注意,它是指每次一维运算要 29 次加法和 5 次乘法,一共是需要 29*8*2 次加法和 5*8*2 次乘法的)。

其中 Y[0]-Y[7] 都是 1*8 的矩阵,X[1]-X[7] 也都是 1*8 的矩阵。

  {a, b, c, d, e, f, g} = 1/2 { cos(pi/4), cos(pi/16), cos(pi/8), cos(3pi/16), cos(5pi/16), cos(3pi/8), cos(7pi/16) }

  再对上面的含有 pi 的系数进行整数优化,从而避免浮点运算,就会得到:

其中:

  3/8=1/4+1/8

  5/8=1/2+1/8

  7/8=1-1/8

  上面的除以 2,除以 8,都可以通过移位来实现,即右移一位和右移三位。即总数为 30 次加法,12 次移位即可。

  这样就在很大程度上将原本需要使用乘法,浮点运算的过程全部转换成了简单的加法和移位处理了,这样使用数学的方法,用近似的值来完成整个转换过程,会有很好的 性能 和处理效果。

  在处理上面的数据中,可以使用一些中间变量来记录中间结果,这样就可以减少反复计算中间值,而直接使用已经计算得到了的中间值。

  tmp0 = x[0] + x[7];

  tmp7 = x[0] - x[7];

  tmp1 = x[1] + x[6];

  tmp6 = x[1] - x[6];

  tmp2 = x[2] + x[5];

  tmp5 = x[2] - x[5];

  tmp3 = x[3] + x[4];

  tmp4 = x[3] - x[4];

  tmp10 = tmp0 + tmp3;

  tmp13 = tmp0 - tmp3;

  tmp11 = tmp1 + tmp2;

  tmp12 = tmp1 - tmp2;

  /* 对偶数项进行运算 X 0,4,6,2 */

  X[0]=tmp1+tmp11;

  X[4]=tmp10 /2 - tmp11

  X[6]=tmp12-(tmp13/4+ tmp13/8);

  X[2]=tmp12/4+tmp12/8-tmp13;

  其他的各个值也是类似处理的。

六、JPEG 在本嵌入式 Linux 应用中遇到的问题

  在本系统中,提供给用户一些播放图片和预览图片的功能,在这个过程中就需要使用到对 JPEG 的处理。

  1、JPEG 出错的处理

  在对图片做预览处理的时候,有些图片原始尺寸很大,那么就需要将其转换成较小的缩略图,在转换为缩略图进行显示时,遇到了一个问题,即有时需要显示的图片,会导致系统无响应。

  后来查找原因,定位到 JPEG 文件的数据不完整,才导致 jpeg decoder 出现无响应。

  在前面的部分,有说到 JPEG 文件的格式中,JPEG 结束的标记 EOI (End Of Image) 为“FFD9”。

  如果需要显示的图片,在传输过程中,或转换过程中,出现了没有 EOI 数据,那么应该在程序中,将其废弃,避免出现系统无响应。

  2、JPEG 解码的效率优化

  在解码 JPEG 时,可以使用 software decode 或 hardware decode 来处理。Hardware decode 的优点是充分利用 DSP 所提供的硬件解码功能,其解码速度会较 software decode 有数量级的提高。但有时使用 hardware decode 有一些限制,如各种 DSP 提供的 SDK 会是直接访问硬件,将 jpeg 直接输出到显示设备,从而会导致 hardware decode 与应用系统集成的麻烦。

  而使用 software decode,就能在应用层完全掌握 jpeg decode 的数据缓冲结果,并可做一些图片的叠加效果或对其进行半透明混合处理,从而会有较高的灵活性。并且使用 decode buffer cache,来将已经解码的数据进行保存,在 UI 后续的使用中,就可不必反复去解码 JPEG 图片,从而也能有效提高绘图效率。

  七、总结

  上面的内容是本人对 JPEG 原理做的一个详细的实例分析,还介绍了 JPEG 编码过程中对浮点运算的优化处理,它特别适用于在资源有限的嵌入系统中避免大量的浮点运算。

  在对 JPEG 原理做了一个详细的分析后,大家会对 JPEG 涉及到的各个细节有了一个更加明确的认识。当你自己动手结合 JPEG 编码过程来分析时,将会有一个清楚的全局观。

  本文结合应用实例,对在嵌入式 Linux 应用中遇到的 JPEG 有关的问题,做了一个说明,大家在自己的设计过程中也可以作为参考。

  现在,你如果再回头去看 JPEG 的原理,你现在应该能看懂它整个过程的来龙去脉了。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值