waifu2xを画像可逆圧縮に使ってみた(…が、うまくいかなかった)

 waifu2xは不可逆圧縮されたり縮小されたりした画像を元に戻すためのツールです。deep learningの一種であるCNN(Convolutional Neural Network)が使われており、良い感じに復元されると評判です。原著論文はarXivにあるので自由に読むことができます。
[1501.00092] Image Super-Resolution Using Deep Convolutional Networks
 元画像を縮小してjpgで圧縮した画像をwaifu2xで復元したら一般には誤差が残るわけですが、その誤差とjpg画像を合わせれば可逆圧縮画像とみなせるのではないかと思い、実際に試してみました。

方法

 大まかな手順としては、
(1)テスト画像をMSペイントで開き、縦横50%に縮小してjpgで保存する。
(2)そのjpg画像をwaifu2xで元の大きさに復元する。
(3)テスト画像と復元後の画像との誤差を求め、ビットマップ画像として書き出す。
(4)そのビットマップ画像を7zでLZMA圧縮する。
 となります。前回の記事ではjpgで公開されている画像をテストに使いましたが、今回はpngで公開されている画像としてこれを使ってみました。ただし、縦を切り詰めて1150ピクセルにしました。縦横のピクセル数がともに偶数だと、復元後の画像と元画像との大きさが同じになって実装しやすくなるためです。

www.pixiv.net
 また、waifu2xには派生ソフトがいろいろあるのですが、今回は簡単に操作できるこれを使いました。inatsuka.com
テスト画像と復元後の画像の誤差を求めるコードは以下のようになります。ここ以外は前回の記事のコードとほとんど一緒です。

	//imgが元画像で、img2がimgをjpg圧縮してからwaifu2xで復元した画像とする。
	//imgとimg2の差分を求めてimgを更新する。
	for (int y = 0; y < img->height; y++)for (int x = 0; x < img->width * 3; x++)
	{
		const int pos = y * img->widthStep + x;
		const unsigned char d = (unsigned char)(img2->imageData[pos] - img->imageData[pos]);
		img->imageData[pos] = (char)(d < 128 ? 255 - 2 * d : 2 * d - 256);
	}

結果

 以下のようになりました。waifu2xにはノイズ除去設定が3通りあるのですが、念の為全て試してみました。2列目は誤差画像をLZMA圧縮したファイルの容量であり、jpg画像の容量は含んでいません。jpg画像は175 KBでした。

ノイズ除去 容量(MB)
なし 2.12
1.92
1.93

 元画像をPNGで圧縮すると1.62 MB、JPEG 2000で圧縮すると1.46 MBになりますから、PNGと比較してもかなり悪い結果です。

考察

 waifu2xは確かに滑らかに拡大してくれていますし、jpg特有のノイズは除かれているのですが、jpg圧縮で失われたディテールを完全には復元できていません。実際に復元後の画像と元画像を比較してみると細部のディテールが結構失われていることがわかります。(興味のある人は試してみると良いです) そのため、誤差画像が予想していたより黒っぽくなり、圧縮率が上がりませんでした。あと、分かってはいたのですが、waifu2xはコーデックに使うにはあまりにも計算量が大きすぎます。最初はいくつかの元画像で試そうかと思っていたのですが、計算が重すぎて1枚でギブアップしました。