WebP lossless might be lossy in 16 bit

(2020/6/2追記ここから)
タイトルに"in 16 bit"を追記しました。
頂いた指摘等を基に再検証したところRGB各色8bitの画像では問題なくlosslessですが、各色16bitの画像ではlossyです。

公式の仕様でbitdepthについての言及が見つけられなかったのですが、フォーラムでは16bit画像のサポートは念頭に無さそうなことが書かれています。曰く、「特にモバイルデバイスのディスプレイに合わせて、データ転送量を削減することを狙ってるので、16bitだとかHDRだとかCMYKはスコープ外だ」的な発言が見つかりますので、そういう仕様なのでしょう。
lossless 16-Bit grayscale support
(2020/6/2追記ここまで)

 WebMの検証を行っていたところ、ついでに気になる静止画版のWebPについても多少実験してみました。
 本投稿は、JPEG等の非可逆圧縮の代替としてではなく、可逆圧縮フォーマットの観点から記述しようと思います。

 長いので先に書いておきますが、「WebPのロスレス圧縮と言っているものは、実は非可逆圧縮」ということが判明しました。
 写真やラスタ画像のアーカイブ用途に使えそうな期待をしていたのですが、残念です。
 
 詳細は以下に。
 

WebPはロスレス圧縮に対応しているのか?

 WebPの公式サイトでは、PNG、WebP-lossless、WebP-lossyを並べて比較・紹介されています。
https://developers.google.com/speed/webp/gallery2#compressing_to_webp-lossless
 このことから解るように非可逆圧縮(lossy)で大幅にデータ量を減少させるだけではなく、可逆圧縮(lossless)に対応していることになっています。
 

ロスレスWebP生成ツール

cwebp

 純正のWebP変換ツールであるcwebpのリファレンスには、ロスレス用のオプションが明示されています。
https://developers.google.com/speed/webp/docs/cwebp#additional_options

lossless Encode the image without any loss.
ImageMagick

 純正ツールだけではなく、ImageMagickもWebPに対応しており、ロスレス用オプションが提供されています。
http://www.imagemagick.org/script/webp.php

lossless=true, false encode the image without any loss.

なお、ImageMagickをソースからビルドする際には、libwebpに依存性があるようなので、libwebpの一部として提供される純正ツールと、WebPエンコード・デコードに関しては本質的な違いは無いと思われます。
 

検証

個人的に常用しており馴染みのあるImageMagickと、純正ツールでWebPロスレス圧縮を行い、オリジナル画像との差分が無いことを検証します。
画像とはいえ数値化されたデジタルデータであるため、同じ値を引き算すれば0になる。ということで、元画像から変換後画像を減算し、完全に真っ黒な画像が得られれば差分が無い、すなわちロスレスだと解ります。

ImageMagick

使用バージョン*1: ImageMagick-6.9.3-0-Q16-x64

1. WebP-lossless変換

convert SOURCE.tif -quality 100 -define webp:lossless=true IM_OUTPUT.webp

なお、ImageMagickのqualityオプションは出力画像フォーマットによって意味合いが異なります。
単に品質の高低を指定する0~100の数値(JPEG等)であったり、二桁のコード(PNG等)であったりします。
WebPの場合の意味がリファレンスに明示されておらず、libwebpに依存する以上は後述のcwebpと同一ではないかと勝手に妄想していますが、定かではありません。

  • SOURCE.tif(Original/元画像)

f:id:kachine:20160429044735p:plain

  • IM_OUTPUT.webp(Converted/変換後画像)

f:id:kachine:20160429044836p:plain

2. 差分抽出
元画像からロスレスWebP画像を減算した差分画像を生成。

convert SOURCE.tif IM_OUTPUT.webp -compose minus -composite diff_im.png
  • diff_im.png(Differential image/差分画像)

f:id:kachine:20160429045019p:plain
得られた差分画像は一見すると黒いが、本当に全面が真っ黒か調べるため、差分画像の最大輝度を取得する。

identify -format %[max] diff_im.png

128

全面真っ黒なら0が返ってくるはずであるが、128が返却された。おかしい。
差分を知覚しやすいように差分画像を正規化してみる。

convert diff_im.png -normalize norm_diff_im.png
  • norm_diff_im.png(Normalized differential image/正規化後差分画像)

f:id:kachine:20160429045143p:plain
これは…画面全体はほとんど劣化してないものの僅かにランダムノイズが乗って、さらに高輝度領域は大きく変化してしまったということですよね。。。ロスレスじゃないじゃん。

ImageMagickのWebP実装にバグでもあるのかしら?気を取り直して純正ツールでも検証してみます。

cwebp編

使用バージョン*2: libwebp-0.5.0-windows-x64

1. WebP-lossless変換

cwebp SOURCE.tif -lossless -q 100 -o CWEBP_OUTPUT.webp

なお、qオプションは0~100の間で指定するもので、非可逆圧縮時はQuality的な意味合いですが、可逆圧縮時は小さい値ほど高速処理だが出力ファイルサイズは大きく、大きい値ほど遅いが出力ファイルサイズは小さくなるとリファレンスにあります。

Specify the compression factor for RGB channels between 0 and 100. The default is 75.
In case of lossy compression (default), a small factor produces a smaller file with lower quality. Best quality is achieved by using a value of 100.
In case of lossless compression (specified by the -lossless option), a small factor enables faster compression speed, but produces a larger file. Maximum compression is achieved by using a value of 100.

  • SOURCE.tif(Original/元画像)

f:id:kachine:20160429044735p:plain

  • CWEBP_OUTPUT.webp(Converted/変換後画像)

f:id:kachine:20160429045314p:plain

2. 差分抽出
ImageMagickの場合と同様に行う。

convert SOURCE.tif CWEBP_OUTPUT.webp -compose minus -composite diff_cwebp.png
  • diff_cwebp.png(Differential image/差分画像)

f:id:kachine:20160429045359p:plain
やはり、得られた差分画像は一見すると黒いが、念のため本当に全面が真っ黒か調べるため、差分画像の最大輝度を取得する。

identify -format %[max] diff_cwebp.png

254

今回も0ではなく254が返却された。おかしい。
同様に差分画像を正規化してみる。

convert diff_cwebp.png -normalize norm_diff_cwebp.png
  • norm_diff_im.png(Normalized differential image/正規化後差分画像)

f:id:kachine:20160429045452p:plain
今度は…画像全体が広く薄く劣化してるってことですよね。。。全然ロスレスじゃない。
 

問題整理

起きていること
  • ImageMagickによるWebP lossless変換が、lossyに見える
  • 純正ツールによるWebP lossless変換も、lossyに見える
差分抽出方法に問題があるのでは?

同様の手法で、TIFFPNG可逆圧縮検証を行ったことがあり、手法の妥当性は担保されていると考えられる。

パラメータに問題があるのでは?

qやqualityを変更しても差分は無くならない。

元画像に問題があるのでは?

冒頭の方で紹介したWebP公式に掲載されたサンプル画像でも同様に検証したところ、差分が検出された。
正規化後差分画像のみ掲載すると、以下の通り。
"Yellow Rose":
f:id:kachine:20160429051547p:plain
"baby tux for my user page":
f:id:kachine:20160429051645p:plain
"PNG transperancy demonstration":
f:id:kachine:20160429051702p:plain
"Gregor Mendel's 189th Birthday":
f:id:kachine:20160429051719p:plain
"Transparent compass card for overlays":
f:id:kachine:20160429051733p:plain
アルファチャネル付き画像のため、ブログ背景色の白が透けて見えて解りにくいですが、問題なさそうに見える"Yellow Rose","baby tux for my user page","Gregor Mendel's 189th Birthday"はエッジ部分に差異が検出されました。
また、"PNG transperancy demonstration","Transparent compass card for overlays"は図柄全体に差分が検出されました。
故に、差分内容はデータパターン依存が見え隠れしますが、いずれも差分自体は発生しており、元画像に固有の問題ではないと判断できます。

ImageMagickのWebPデコーダにバグがあるのでは?

純正ツールでWebP⇒PNG変換を行い、それを比較することでImageMagickのWebPデコーダに依存しないで検証可能となります。
ファイルパターンを整理すると、

a.元画像 ⇒ b.(ImageMagickで変換)ロスレスWebP画像 ⇒ c.(純正ツールで変換)PNG画像
         ⇒ B.(純正ツールで変換)ロスレスWebP画像 ⇒ C.(純正ツールで変換)PNG画像

現状、aとb及びaとBで差分が検出されている。
aとc及びaとCに差分が無ければImageMagickのWebPデコーダ周りのバグと特定できます。

純正ツール(dwebp)でデコード
dwebp IM_OUTPUT.webp -o DECODE_IM_OUTPUT.png
dwebp CWEBP_OUTPUT.webp -o DECODE_CWEBP_OUTPUT.png
差分抽出(aとc及びaとC)
convert SOURCE.tif DECODE_IM_OUTPUT.png -compose minus -composite diff_decode_im.png
identify -format %[max] diff_decode_im.png

128
convert SOURCE.tif DECODE_CWEBP_OUTPUT.png -compose minus -composite diff_decode_cwebp.png
identify -format %[max] diff_decode_cwebp.png

254

あれ?b及びBと全く同じ最大輝度差分が検出された。
故にImageMagickのWebPデコーダの問題ではないようです。

ここで、新たに使用したdwebpによる劣化や新たな差分が発生していないことを検証するため、bとc、BとCの差分を比較してみます。

差分抽出(bとc及びBとC)
convert IM_OUTPUT.webp DECODE_IM_OUTPUT.png -compose minus -composite diff_im_decode.png
identify -format %[max] diff_im_decode.png

0
convert CWEBP_OUTPUT.webp DECODE_CWEBP_OUTPUT.png -compose minus -composite diff_cwebp_decode.png
identify -format %[max] diff_cwebp_decode.png

0

見事に差分はありません。dwebpは正常だし、ImageMagickによる差分抽出方法の信頼性も改めて担保されました。

結論

a⇒b及びa⇒Bのフローで、差分が発生していることが確定し、WebPの自称ロスレスエンコーダはロスレスではないことが判明しました。
或いはcwebpもImageMagickもバグってるというか、libwebpのロスレスエンコーダにバグが混入していると考えられます。
故に、可逆圧縮フォーマットとしては現状では使えなさそうです。
 



はてなブログ(はてなフォトライフ)はWebPに対応していないため、掲載画像はリサイズ後、PNGに変換したものです。
以上。
 



画像引用元:

1 "Free Stock Photo in High Resolution - Yellow Rose 3 - Flowers" Image Author: Jon Sullivan This file is in the public domain. PNG source
2 "baby tux for my user page" Image Author: Fizyplankton This file is in the public domain. PNG source
3 "PNG transparency demonstration" Image Author: POV-Ray source code Photo licensed under the Creative Commons Attribution-Share Alike 3.0 Unported license. PNG source
4 "Gregor Mendel's 189th Birthday" Image Author: Google Doodle team Thanks to the Google Doodle team for this image. PNG source
5 "Transparent compass card for overlays" Image Author: Denelson83 This file is licenced under the Creative Commons Attribution-Share Alike 3.0 Unported license. PNG source

*1:常用しているため最新ではなく微妙に古い。

*2:検証実施時点の最新。