シンプルな非可逆圧縮を作ってみました。簡単な処理しかしていません。
組み込み向けに設計したのでデコードのメモリ消費は抑えてあり、圧縮後の画像は16bitカラー相当になります。 *1
また、以下のような画像は苦手です。
- モノクロ画像
- もともと色差がないので圧縮効果はあまり期待できません。
- 小さいピクセルアート (数十ピクセル以下)
- 大きい画像 (FullHDなど)
- この形式は 8x8 のブロック単位で圧縮しますが、大きい画像は近隣のピクセルと変化が少ないため同じようなブロックが大量に発生します。しかし、この形式はブロックを超えて圧縮できないため相対的に圧縮効率が悪くなります。
まとめると、数十〜数百ピクセルくらいのサイズの写真では PNG と JPG の間くらいの圧縮率になります。 また、イラスト調画像でも JPG のようなブロックノイズはほぼ発生しません。
しくみ
まずは処理をしやすくするために画像を 8x8 のブロックに分割します。 以降の処理は 8x8 ブロック単位で処理するためメモリをあまり消費しません。 また、今のところサイズが 8 の倍数でない画像は処理できません。
次に、各ピクセルの色を RGB → YUV に変換し、同時に 24bit (8x3) → 18bit (6x3) に精度を落とします。 その後、人間の目は輝度の変化には敏感だけど色差の変化には鈍感な性質を利用して YUV 4:2:0 に近い間引き処理で色差 (UとV) を1/4にします。 色差情報を間引くため、最悪でも生のビットマップの約半分のサイズの圧縮が保証されます。一連の色変換処理が非可逆になります。
最後にスライド辞書を使った単純なLZ法で圧縮します。
追記:差分エンコーディングはLZ圧縮を採用した現在ではむしろ圧縮率が悪化するケースが多いことがわかったので削除しました。
いかがでしたか?
YUV 圧縮は実際に画像や映像処理でよく使われている定評のある圧縮方法で、単純な処理で結構効果があることがわかりました。
今回の圧縮方式ではあえて仕様をシンプルにするため採用しなかった仕様がいくつかあります。 例えば、ブロック単位の処理をやめて Y, U, V をそれぞれチャンネルごとに圧縮すると多くのメモリが必要になる代わりに良好な圧縮効果が期待できると思います。 機会があったらもっと強い圧縮を考えてみると良いかもしれません。
*1:厳密には 16bit カラーとちょっと違いますが、 24bit カラーよりも色情報を落としているので 16bit カラーでグラデーションを表示したときとよく似た段差が発生します。