Web 优化:WebP 参数分析
发布时间:
最后更新:
WebP 是 Google 出品的图片编码,作为新一代编码(其实也不新了),通常能提供更好的压缩质量。可是 WebP 编码器的参数有数十种之多,默认的就是最好的吗?有没有更佳的参数?这些问题一直环绕在我的脑海中。
最初我也是没加任何参数就用,但渐渐地发现一些图片的转换效果很不理想,为了搞清楚 WebP 的效果到底如何,我专门写了一个测试各种参数效果的工具 ICAnalyzer(介绍见 ICAnalyzer 开发小记)。
本文记录了我用该工具对 WebP 参数的分析过程,希望能对 WebP 格式的使用者有所帮助。
测试说明 #
WebP 所有的选项见 Google的官网,它的转换工具也有很多,Squoosh 就是其中最方便的之一,所以本文所分析的选项与 Squoosh 一致。另外各种第三方 WebP 转换库也都是用的 同一套核心代码 ,所以本文也适用于其它 WebP 转换工具。
样本 #
通常分析需要大量的样本,但数量一多就会变得复杂,难以展示,所以本文选取了几个具有代表性的图片:
这三张图代表了三类来源:
-
照片来自于相机的拍摄,存在自然噪声。
-
插画是由人通过软件在计算机上绘制的。
-
代码截图则是完全由计算机生成,只包含简单的图形和规整的文字。
这几张图也是 ICAanalyzer 的示例图片,本文的所有结果都可以在 ICAanalyzer 里复现。
质量指标 #
质量指标选用 PSNR 和 Butteraugli 两个。PSNR 是数据层面的,用于判断图片数据有多大的变动;Butteraugli 是专用于图片的相似度算法,它考虑了人眼多不同颜色的敏感度,比起 PSNR 更精确;还有一个 SSIM 因为跟 Butteraugli 差不多就没有选。
注意事项 #
-
为了节约篇幅,部分参数并未贴上全部样本的图表,仅挑选有代表性的,压缩后的图片也不会全部贴上。
-
本文虽然只选了少数样本,不能涵盖所有场景,如果有能力,在优化前应当自己做测试。
-
没有单独测试针对 Alpha 通道的参数,比如
-alpha_q
、-alpha_method
、-exact
等等。 -
在测试每个参数时,其它参数都保持默认,这无法得知参数组合的效果。
-
WebP 编码器仍在维护中,可能出现改动导致本文的结论失效,请注意本文的发布日期。
有损模式 #
Quality (-q) #
首先是最常用压缩质量设置,对应-q <0-100>
参数,越大质量越好但压缩率更差,该参数只在有损压缩模式下生效,默认值 75。
基本上跟这个参数的描述一致,而且对编码时间没有影响,但有两个点需要注意:
第一个是在 75 的位置压缩率的增长趋势有明显的改变,大于该值时体积会迅速增大,而小于该值则压缩率收益降低,可以认为如果要在质量和体积重选择一个平衡的点,quality = 75
是最佳的, 这也是 cwebp 的默认值。为什么在 75 处会有变动呢,从源码里可以看到,它是人为设置的,为了模仿 JPEG?
第二个是 0,在此处图片的质量大幅降低,已经没法看了,所以使用中请勿将quality
降到 0.
Compression method (-m) #
-m <0-6>
这个参数影响质量和速度的取舍,根据文档该值越大转换速度越慢,但是产生的图片质量和体积都更好,默认值为 4,但实际如何呢?
比起前面的quality
,method
参数对质量和体积的影响要小许多(Y 轴幅度较小),随着值的增大文件的大小逐渐降低,但并不明显。图片的质量时高时低,并且波动幅度不大,不过还是能看到一些趋势:
-
在最大值 6 的位置压缩时间显著增加,但质量和体积的收益很少。
-
在小于 3 时文件体积会增大,压缩时间也很短,3-5 范围内时间没什么变化,压缩率的变化也很小。
总的来说,这个参数对结果的影响并不显著,默认值 4 是可以接受的,如果要选出最佳值的话应该是 5, 此处的压缩时间与 4 差不多,而且对于大部分图片质量比 4 稍高一点。
Sharp YUV #
非常多的图片压缩算法都使用了一个RGB -> YUV
色彩空间转换,WebP 也不例外,这个转换有各种各样实现。cwebp
默认使用的算法对于照片插画之类图来说这种失真不容易察觉,但像文字截图这样的图效果就不理想了,对此cwebp
提供了-sharp_yuv
参数,开启后将使用精度更高的算法,有效地减少色彩失真。
可以看到它对不同的图片作用差别较大,在照片这种色彩丰富边缘平滑的图片上表现不明显,压缩率增加0.3%,Butteraugli 降低0.41,到了样本2里面 Butteraugli 反而增加了 0.36,这点差距基本可以忽略。
值得注意的是如果图片有鲜艳的红色且边缘明显,sharp_yuv
的作用就十分显著。在样本 3 中,开启后文件体积增加了 10%,Butteraugli 降低了 6.7,这个质量提升见下图,左边色彩失真肉眼可见,右边是开启了的:
那么这个选项要不要开?如果是照片插画这样的就没必要;如果是纯图形和文字这样的,其实也没必要,后面会提到无损模式更好。但是如果这两类混合在一起呢?
我的博客列表页的截图就是典型的混合图片,其中大部分是文字和图形,但同时 banner 部分却是插画。该图中左上角的 logo 如果不启用sharp_yuv
则会变暗,色彩失真很严重。所以我建议,保险起见,最好启用sharp_yuv
这个选项。
Filter strength #
过滤器选项有俩兄弟:
- Filter strength
-f
范围0-100
,默认 60,仅在有损模式有效。 - Auto filter
-af
让编码器自动选择 Filter strength 的值,默认不启用。
-f
对结果的影响微乎其微,曲线只在零点有较大的变化,后面基本都是平的,各个指标的波动范围也非常小。下面是局部放大的图,仔细观察会发现,为 0 时明显感觉到图片被分为边长为 4 个像素的方块(左图),而增大该参数后就自然了许多。可以看出,此选项影响图片的平滑程度。
综上所述,该选项不建议手动设置,用默认的或者 -af
自动选择即可。
Strong Filter #
使用 Strong 过滤器,默认启用。
该参数在图片上的表现跟 Filter strength 差不多,关闭的情况下图片更平滑一些,开启后似乎多了些噪点,图片就不放了因为差异是在太小。总之该参数对各个指标的影响实在太小了,所以没啥用,建议不管它。
Filter sharpness #
锐度 ,范围 0-7
默认为 0,从名字上看又是一个跟平滑相关的参数。
这个参数对体积和时间没有任何影响,质量也是有高有低,很难说那个值更好,所以同样建议不管它。
Passes #
-pass
整数型参数,范围1-10
,默认为 0。这个选项的文档里说与-size
或-psnr
一起使用,影响迭代次数,但测试中发现不指定它们也有效果。
这曲线跟坐过山车一样,除了编码时间以外都是上上下下。从值的范围上看,也只有编码时间从 1.5 s 到最大的 9.1 s,其它指标的波动范围都很小,可以忽略。所以这又是一个没什么卵用的选项,越大越费时间,默认的 0 就是最好的。
Spatial noise shaping (-sns) #
空间噪声整形的强度,范围 0-100
默认 50。根据文档,它能调整哪些区域应该使用相对较少的比特,以及在其他地方更好地传输这些比特。似乎是越大越好,但实际呢:
又是过山车,虽然波动幅度比前面两个大了些,但在不同的图片上表现出了不同的趋势,这使得该选项很难确定一个最佳值,所以还是使用默认值吧。
Processing #
-pre
是一个枚举类选项,有三个值0-2
分别代表 None、Segment smooth、Pseudo-random dithering,默认为 0.
平滑和抖动都是图像处理中的技术,有兴趣请自行搜索。仅从曲线上看,除了 Segment smooth 的编码速度快一些压缩比差一些外,其它指标都没什么意义,质量有的好有的坏。总之不建议去调整该参数。
Segments #
sns 算法中的分割数,范围1-4
默认 4,文档里说在 methods 大于 3 时无效,但实测还是有影响的。
这个参数也看不出明显的趋势,保持默认即可。
其它选项 #
-
-preset
参数相当于同时配置 Filter strength、Filter sharpness、Spatial noise shaping、Preprocess 四个选项,对应关系见源码,这四个选项的效果已经讨论过就不再提了。 -
-hint
参数在测试中没有产生任何效果,不知道是不是 Squoosh 的编码器实现有问题。
无损模式 #
Lossless #
对于非常重要的场景,无损的图片有时是必需的,但同时无损的图片体积也会很大;而一些不关键的场合,比如博客、IM、视频站等等,为了节约流量提高性能,牺牲一些肉眼不容易观察到的质量换取体积则是值得的,这是众所周知的常识。
对照片的测试结果如图,无损下体积比原图还大,这似乎证实了上述的规律,这么看已经没有讨论无损的必要了。但所有图片都是如此吗?有损压缩一定比无损的体积小?下面这个测试就粉碎了这种错误的观念:
在样本三这张代码截图上,结果完全反了过来,有损的压缩比为 120% 反而比原图大了,而无损的压缩比达到了惊人的 34%,毫无疑问对这张图而言,无损模式才是最佳的方案。
如果你阅读了 官网上对 WebP 的技术细节的描述 就会发现它的有损转换过程对于噪声多、边缘柔和的图片处理能力很强,而对于图形和文字就不合适了。不过 WebP 的无损无论是算法还是封装都优于传统的 PNG 格式,也当然有着更高的压缩率。
综上所述,无损模式对于某些类型图片是优于有损的,但图片属于哪类并不好检测,这里可以根据大小来判断。一个可行的方案是将一张图同时使用有损和无损压缩,然后选择小的那个。
Lossless Preset (-z) #
-z
参数指定了压缩率和速度的取舍,范围 0-9
默认 6,0 最快但是文件会更大,9 最慢也能得到最小的文件。
这个参数是一个预设,相当于同时设置 Quality 和 Method,对应关系可以从源码里找到。如果使用的是 cwebp 命令行工具,在该参数之后指定 -m
和-q
会覆盖此选项。
无损模式下质量指标没有意义,所以就省略了,只看压缩率和时间。图中的结果非常清晰,与文档描述的一致,除左右两边的两个点波动较大之外,中间都比较平滑。
在该参数为 0 的位置,压缩比翻倍到 93%,此时已经失去了体积优势;而在该参数为 9 时,编码时间急剧增加但压缩比却没有降低多少。所以实际可用的范围在 1 到 8 之间,如果愿意用时间换点质量就设为 8,反之追求速度可以设为 1,当然默认的 6 也不错。
Near Lossless #
接近无损的压缩模式,虽然也是有损的但质量损失极小,肉眼观察不出来。-near_lossless
的范围为 0-100
,默认的 100 表示关闭该功能。
-near_lossless
的曲线呈阶梯状,表明虽然它可以为0-100
中的任何整数,但每增加 20 才会有变化,实际上只有 6 个值。
先看照片的结果,随着值的增加质量越来越好,同时压缩率比也会变大,最终到 100 的位置等于无损。但即便为 0,图片的体积仍比原图大,而且质量也没有比有损模式高多少,跟有损相比没有任何优势。
再看看代码截图,当该参数增大时质量提高且体积减小,在 100 处关闭该功能时达到最佳的结果,所以对这类图片也没必要用它。
综上所述,在测试中没有发现-near_lossless
有什么值得使用的场景,建议不要使用这个参数。 当然也可能只是我没发现它的用处。
总结 #
WebP 的参数虽多,但大部分对结果的影响都很小。根据分析可以得到一个比较理想的转换流程。该流程覆盖了各种边界情况,无论哪种图都不至于搞出特别差的结果;同时也尽可能地提供较高的图片质量。不过由于做了两次转换,开销会大一些。