Web图片优化系列(二):WebP 转换参数分析

发布时间:

最后更新:

关键词: PSNR 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。

质量为 0 和 75 的结果 质量为 0 和 75 的结果

照片 照片

基本上跟这个参数的描述一致,而且对编码时间没有影响,但有两个点需要注意:

第一个是在 75 的位置压缩率的增长趋势有明显的改变,大于该值时体积会迅速增大,而小于该值则压缩率收益降低,可以认为如果要在质量和体积重选择一个平衡的点,quality = 75 是最佳的, 这也是 cwebp 的默认值。为什么在 75 处会有变动呢,从源码里可以看到,它是人为设置的,为了模仿 JPEG?

第二个是 0,在此处图片的质量大幅降低,已经没法看了,所以使用中请勿将quality降到 0.

Compression method (-m)

-m <0-6>这个参数影响质量和速度的取舍,根据文档该值越大转换速度越慢,但是产生的图片质量和体积都更好,默认值为 4,但实际如何呢?

照片 照片 插画 插画

比起前面的qualitymethod参数对质量和体积的影响要小许多(Y 轴幅度较小),随着值的增大文件的大小逐渐降低,但并不明显。图片的质量时高时低,并且波动幅度不大,不过还是能看到一些趋势:

  1. 在最大值 6 的位置压缩时间显著增加,但质量和体积的收益很少。

  2. 在小于 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 的作用就十分显著,比如截屏,开启后文件体积也增加了 10%,Butteraugli 大幅降低了 6.7,这个质量提升见下图,左边色彩失真肉眼可见,右边是开启了的:

SharpYUV对比 SharpYUV对比

那么这个选项要不要开?如果是照片插画这样的就没必要;如果是纯图形和文字这样的,其实也没必要,后面会提到无损模式效果更好。但是,图片是能合成的,如果这两类混合在一起呢?

SharpYUV对比 SharpYUV对比

我的博客列表页的截图就是典型的混合图片,其中大部分是文字和图形,但同时 banner 部分却是插画。该图中左上角的 logo 如果不启用sharp_yuv则会变暗,色彩失真很严重。所以我建议,保险起见,最好启用sharp_yuv这个选项。

Filter strength

过滤器选项有俩兄弟:

  • Filter strength -f 范围0-100,默认 60,仅在有损模式有效。
  • Auto filter -af 让编码器自动选择 Filter strength 的值,默认不启用。

照片 照片 去掉零点后的 去掉零点后的

-f对结果的影响微乎其微,曲线只在零点有较大的变化,后面基本都是平的,各个指标的波动范围也非常小。下面是局部放大的图,仔细观察会发现,为 0 时明显感觉到图片被分为边长为 4 个像素的方块(左图),而增大该参数后就自然了许多。可以看出,此选项影响图片的平滑程度。

0 和 100 对比 0 和 100 对比

综上所述,该选项不建议手动设置,用默认的或者 -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 才会有变化,实际上只有 5 个值。

先看照片的结果,随着值的增加质量越来越好,同时压缩率比也会变大,最终到 100 的位置等于无损。但即便为 0,图片的体积仍比原图大,而且质量也没有比有损模式高多少,跟有损相比没有任何优势。

再看看代码截图的结果,当该参数增大时质量提高且体积减小,在 100 处关闭该功能时达到最佳的结果,所以对这类图片也没必要用它。

综上所述,在测试中没有发现-near_lossless有什么值得使用的场景,建议不要使用这个参数。 当然也可能只是我没发现它的用处。

总结

推荐流程 推荐流程

WebP 的参数虽多,但大部分对结果的影响都很小。根据对各个参数的讨论,可以得到一个比较理想的转换流程。该流程覆盖了各种边界情况,无论哪种图都不至于搞出特别差的结果;同时也尽可能地提供较高的图片质量。不过由于做了两次转换,开销会大一些。

评论加载中