转载请注明出处:(http://www.jianshu.com/p/934269064bfb)
本篇文章翻译自谷歌出的优化视频里面的光头佬(Colt McAnlis),原文地址需翻墙, 以下正文:
JPG格式是1992年出现的最早进的图片紧缩技术之1。尔后,它就成为互联网图片的主力。这固然和JPG背后的技术有关,JPG的工作原理异常复杂,它需要深入理解人眼是如何调剂对色采和图象边沿的感知。
在研究这些东西前(你也1样,如果你在浏览此文),我想把JPG的编码原理分解成几部份,这样我们就能够更好的理解怎样制作更小的JPG文件。
JPG的紧缩方案被分成几个步骤,下图很好的把它们展现出来,我们接下来会对每一个步骤作详细介绍。
有损数据紧缩的1个关键原则是:人类的感知能力没有计算机的精确。科学证明,人的眼睛只能辨别1000万种不同的色彩。但是,还有很多东西会影响人眼对色采的感知,明显的突出色采错觉,又或你应当还记得去年这件衣服把互联网都炸开了。这里的重点是人眼可以很好的控制它所感知的色彩。
量化是有损紧缩种的1种情势,不过JPG使用的是1种不同的方式:色彩模型。1个色采空间是1个特定的色彩组织,它的色彩模型代表了这些色彩表示的数学公式。(例如3色彩RGB,或CMYK)
这个进程的强大的地方是,你可以把1个色彩模型转换成另外1个,这意味着你可以将1个给定色彩的数学表达式转成1组完全不同的值。
例如,下面这类的色彩,它可以用RGB和CMYK两张不同的色彩模型指替,它们对人眼来讲是1样的色彩,但却可以被表示成不同的数值集。
将JPG从RGB色彩模型转换成Y,Cb,Cr色彩模型,包括亮度(Y)、色度蓝(CB)和色度红(CR)。这样做的缘由,是心理视觉实验(又名:大脑处理如何处理眼睛看到的信息)表明,人眼对亮度比色度更敏感,这意味着我们会疏忽掉较大的色度变化,而不影响我们对图片的感知。因此,我们可以在人眼发觉前对CbCr通道用力的紧缩。
YCbCr色彩空间其中1个有趣的细节是,Cb/Cr通道有比较少的颗粒度细节,也就是说它们包括的信息没有Y通道的多。所以JPG的算法就把Cb和Cr通道的大小缩减到原来的1/4(注意,在具体的处理上会有些细微的差别,但我这里就不展开了…),这类做法就叫做缩减取样。
有1件很重要的事需要说明,缩减取样是1个有损紧缩进程(紧缩过后你没法恢复回原来的色彩,只能得到1个近视的值),但对人类视觉皮层的可视化组件的整体影响是最小的。由于我们没有对亮度(Y)做处理,只对CbCr通道做缩减,所以对人的视觉系统的影响较低。
从现在开始,在JPG上做的所有操作都是基于8x8像素块。这样做是由于我们通常认为8x8像素块里没有太多的差异,即便是很复杂的图片,局部区域的像素也常常类似,这类类似性有助于以后我们对它紧缩。
在这里我们需要注意1点,我们要介绍JPG编码的常见”神器”之1。”色采渗透”是沿着锋利边沿的色彩可以”渗透”到另外一边。这是由于色度通道,它代表像素的色彩,平均到单个色彩需要4个像素1块,而有些块穿过了锋利边沿。
到现在为止,这些步骤都平淡无奇。色采空间,缩减取样,分块处理在图片数据紧缩领域都是小儿科。但是现在…真实的数学要上场了。
DTC(离散余弦转换)的关键是,它假定任何1个数字信号都可以被1个余弦组合函数重建。
例如,如果我们有下面这个坐标图:
你可以看到它实际上是cos(x)+cos(2x)+cos(4x)相加的结果
也许更好的展现这个进程,是在1个平面上给定1组余弦函数来真实的解码1张图片。为了展现这个进程,我贴了互联网上最惊人之1的GIF图片:在1个平面上用余弦函数来编码1块8x8像素。
上面是1张正在重建的图片(最左侧那个区域)。每帧我们都使用右边面版新的基准值,来乘1个权重值(右边区域的文字)来产生图片(中间区域)。
如你所见,靠着带权重的不同余弦值相加,我们可以重构出我们的原图。(这多屌啊~)
这个的基础背景知识是离散余弦变换原理。核心思想是,在不同频率上,8x8块都可以由1组权重余弦变化的和代表。这里的重点是算出要输入的余弦值,和它们的权重。
想要得出”使用甚么余弦值”是很容易的,经过大量的测试以后,选出1组最好的余弦值,它们是我们的基础函数,下图是形象化的进程。
而”它们怎样被加权在1起”的问题也很简单,直接套用下面的公式。
我就不介绍这些值得含义了,你可以在这个维基页面查看它们含义。
每一个色采通道的8x8像素块都会用上面这个公式和基础函数生成新的1个8x8矩阵,表示在这个进程中使用的权重。下面是1张表示这个进程的图片:
这个矩阵G,用来代表重建图片的基础权重(在动画右边上方的小10进制数)。对每一个基础余弦值,我们都将它乘与矩阵里的权重,然后全部相加,得到我们终究的图片。
基于这点,我们就不再操作色彩空间而直接处理G矩阵(基础权重),以后所有的紧缩操作都直接在这个矩阵上做。
这里的问题是我们现在将字节对齐的整数转成真实的数字。这样会很容易膨胀我们的信息(从1byte变成1个float(4个字节))。为了解决这问题,紧缩得更极致,我们将进入量化阶段。
我们不想紧缩浮点数据,它会膨胀我们的信息流,并且不高效。因此,我们要找1种方法来将权重矩阵转换到0⑵55这范围里。我们可以直接在矩阵里将最小/最大值(分别是⑷15.38和77.13)除以这个范围来得到1个在0⑴的值,再将这个值乘以255得到最后的值。
例如:[34.12- ⑷15.38] / [77.13 — ⑷15.38] *255= 232
这样做可以,但代价是精度会显著降落。这类缩放将产生1个散布不均匀的值,其结果是会致使图片质量的降落。
JPG用了另外1种方法。不同于使用矩阵的范围来作为缩放值,JPG用了1个可量化的预矩阵。这类可量化矩阵不需要成为数据流的1部份,它们可成为编码的1部份。
这个例子展现了对每张图片使用的量化因子矩阵:
现在我们使用Q和G矩阵,来计算我们的量化DCT系数矩阵:
例如,用G矩阵的[0,0]=⑷15.37和Q[0,0]=16这两个数字:
得到最后的矩阵是:
你看现在这个矩阵多变成多简单,它现在包括了大量的小整数或0,这会有助于紧缩。
简单点说,我们把这个进程分别利用在Y,CbCr通道,这样我们需要两个不同的矩阵,1个是Y通道,另外一个是C通道:
量化紧缩有两种重要的方式:
1. 限制可用范围的权重,减少数字的位数和替换它们。
2. 将大部份的权重变成同1个数字或0,提高第3步紧缩,熵编码。
这样的量化方式主要来源于JPEG。由于图象的右下方常常有最大的量化因子,JPEG偏向于将这些图象组合。量化因子矩阵可以通过改变JPEG的’质量值’直接控制。(稍后介绍)
现在我们可以回到整数世界了,将眼光转移到对色彩块做有损紧缩阶段。当看我们的转化数据,你应当会注意到1些有趣的现象:
从左上角到右下角,0出现的数量急速上升。但主行和主列的顺序其实不理想,由于这些0都交织在1起,而不是放在1起。
相反,我们可以从左上角开始以Z字形来回穿梭直到右下角的方式遍历全部矩阵。
我们的亮度矩阵的顺序变成:
−26,−3,0,−3,−2,−6,2,−4,1,−3,1,1,5,1,2,−1,1,−1,2,0,0,0,0,0,⑴,⑴,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
1旦数据变成这个格式,下1步就简单了:按顺序履行RLE,然后对结果进行统计编码(霍夫曼/算术/ANS)。
Boom.你的数据块变成JPG编码了。
现在你已理解JPG文件是怎样创建的,是该重新审视图片质量参数这个概念了,你通常会在PhotoShop导出JPG图片时会看到。(或在其他地方)
这个参数我们称之为q,是1个从1到100的整数。你应当把q当作1个丈量图片质量的值:q越大表示图片的质量越高,固然文件就越大。
这个质量值用在量化阶段,用来缩放适合的量化因子。因此对每一个基准权重,量化阶段现在类似于* round(Gi,k / alpha*Qi,k)。*
其中alpha符号用来当作质量参数。
当alpha或Q[x,y]越大(当alpha的值越大那末q参数的值就越小),更多信息是丢失,文件就越小。
所以,如果你想要靠更多的视觉假象来得到1张更小的图片,那末你可以在到处图片阶段设置1个更小的质量值。
注意上图,那张质量为1的图片里,我们可以清晰的看到在成块阶段和量化阶段的痕迹。
更重要的是质量参数大小取决于具体的图片。由于每张图片都是唯1的,它们都有不同的展现效果,那末Q值也是唯1的。
由于你已理解了JPG的算法工作原理,1些事情就变得清晰了:
如果你想要自己处理这么多东西,那末这个1000行不到文件可以帮你弄定这些问题。
PS:由于本文触及到的数学算法比较多,本人水平有限,如有译错,请留言讨论。
下一篇 复杂链表的复制