ImageSharp源码详解之JPEG编码原理(1)JPEG介绍
最近在看GitHub上的⼀个很⽕的项⽬是:。这是⼀个纯 core的图像处理库,没有使⽤其他的任何依赖。在看这个项⽬过程中激发了我对图像⽂件编码解码的兴趣。于是从最简单的BMP图像开始看,到GIF格式卡了⼀段时间(主要卡在lzw编码过程和数据块中),到最后的JPEG格式(PNG格式不打算看了),经历了半个⽉时间才梳理出个⼤概。趁着这个热乎劲,我想写下关于JPEG格式的系列⽂章,⽂章⽬录暂定如下:
ImageSharp源码详解之JPEG压缩原理(4)量化
ImageSharp源码详解之JPEG压缩原理(6)C#源码解析及调试技巧
1.JPEG介绍
JPEG(Joint Photographic Experts Group)是联合图像专家⼩组的英⽂缩写。它由国际电话与电报咨询委员会CCITT(The International Telegraph and Telephone Consultative Committee)与国际标准化组织ISO于1986年联合成⽴的⼀个⼩组,负责制定静态数字图像的编码标准。
⼩组⼀直致⼒于标准化⼯作,开发研制出连续⾊调、多级灰度、静⽌图像的数字图像压缩编码⽅法,即JPEG算法。JPEG算法被确定为国际通⽤标准,其适⽤范围⼴泛,除⽤于静态图像编码外,还推⼴到电
视图像序列的帧内图像压缩。⽽⽤JPEG算法压缩出来的静态图⽚⽂件称为JPEG⽂件,扩展名通常为*.jpg、*.jpe*.jpeg。
JPEG专家组开发了两种基本的压缩算法、两种数据编码⽅法、四种编码模式。具体如下:
图片下载站源码压缩算法:
1有损的离散余弦变换(Discrete Cosine Transform,DCT);
2 ⽆损的预测技术压缩。
数据编码⽅法:
1哈夫曼编码;
2算术编码;
编码模式:
1基于DCT顺序模式:编/解码通过⼀次扫描完成;
2基于DCT递进模式:编/解码需要多次扫描完成,扫描效果从粗糙到精细,逐级递进;
3⽆损模式:基于DPCM,保证解码后完全精确恢复到原图像采样值;
4层次模式:图像在多个空间多种分辨率进⾏编码,可以根据需要只对低分辨率数据作解码,放弃⾼分辨率信息。
在我阅读的源码中,我关注的是离散余弦变换、哈夫曼编码、基于DCT顺序模式的编码,这也是JPRG图像常⽤的技术。
整体⽂件的⼤致结构如下:
SOI(0xFFD8)
APP0(0xFFE0)
[APPn(0xFFEn)]可选
DQT(0xFFDB)
SOF0(0xFFC0)
DHT(0xFFC4)
SOS(0xFFDA)
压缩数据
EOI(0xFFD9)
我们解码的时候⼤致都是按照上⾯顺序进⾏解码,关于上⾯这些标记,⼤家可以从⽂章结尾参考资料中看到他们的详细信息,这⾥我不对这些标记展开描述,在后⾯⽤到的时候会提到。
2.JPEG压缩的⼤致过程
2.1 编码
对于⼀副图像,编码器⾸先需要填充这个图像的⼀些头信息,量化表,霍夫曼表。我们可以看ImageSharp中JpegEncoderCore这个类⾥⾯的的Encode⽅法如下:
1 ...
2// Write the Start Of Image marker.
3this.WriteApplicationHeader(metadata);
4// Write Exif and ICC profiles
5this.WriteProfiles(metadata);
6// Write the quantization tables.
7this.WriteDefineQuantizationTables();
8// Write the image dimensions.
9this.WriteStartOfFrame(image.Width, image.Height, componentCount);
10// Write the Huffman tables.
11this.WriteDefineHuffmanTables(componentCount);
12// Write the image data.
13this.WriteStartOfScan(image);
14// Write the End Of Image marker.
15this.buffer[0] = JpegConstants.Markers.XFF;
16this.buffer[1] = JpegConstants.Markers.EOI;
17 stream.Write(this.buffer, 0, 2);
18 stream.Flush();
19 }
View Code
这⼀系列都是围绕着WriteStartOfScan这个⽅法展开,这个⽅法就是对于图像数据进⾏编码,过程如下图:
注意我们看到过程中YUV采样后⾯是DCT变换、量化、熵编码。实际过程中,YUV采样过程中就包含后⾯DCT变换、量化、熵编码这三个过程,只不过我们在描述的时候将其分开。在ImageSharp源码中我们可以看到它使⽤的是标准霍夫曼表来进⾏编码,这也是⼀般JPEG编码器常⽤的⽅法,但这样就和常规的霍夫曼编码不⼀致,我们可以通过其他资料学习到霍夫曼编码需要对原始数据遍历两次,⼀次构建霍夫曼树,⼀次进⾏编码。我在⾕歌的项⽬中看到了针对不同图像数据,构建不同霍夫曼树结构的⽅法。
2.2 解码
作为编码的互逆过程,⼤致流程如下:
虽然我们了解了如何编码,就能⼤致知道如何解码,但是ImageSharp源码中,对于解码和编码在代码实现还是有区别的,后续我只分析JPEG的编码过程。
3.后续
后⾯计划是先把量化和熵编码的相关⽂章写完,然后把imagesharp这个项⽬中调试技巧做⼀下分析解读,最后再写DCT变换。DCT涉及到傅⾥叶变
换,如果要深⼊理解,其背后复杂的数学知识不是我所能讲解的,在这⼀章尽量讲解代码技巧,数学公式不敢牵涉太多。
参考⽂献:
学习JPEG编码需要参考⼤量的资料,这些资料侧重点都不⼀样,需要相互印证。对我来说看代码⽐看⽂献更快,我的⽅法就是通过调试代码来验证我的猜想,下⾯是我看过的⼀些资料,后⾯⽂章不在赘述:
1. JPEG⽂件格式,标准的霍夫曼编码参考的是这个资料,在ImageSharp源码中可以下载获取。
2.这个⽹站⾥⾯可以到⼀个叫JPEGsnoop的开源软件,可以分析JPEG各个标记的具体数值,同时这个⽹站⾥⾯很多教程都是关于JPEG的编码和解码,我⽂章⾥⾯⼀些图⽚都来⾃上⾯。
3.,⼀位⼤⽜的博客,值得⼀看。
4. 这个源码只针对JPEG格式进⾏编码与解析,所以看起来相对ImageSharp简单很多,我前期就是先对照资料看的这个源码,后⾯换成ImageSharp。
5.数据压缩导论(第4版)这本书很好,理论讲解的很深⼊,例⼦举的也很容易看懂。
6.实⽤数字信号处理-从原理到应⽤这本书关于DFT的讲解很深⼊,值得⼀看。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论