NASがパンク寸前でピンチ!画像圧縮でスペース節約術 – AVIF

画像圧縮でNASの空き容量の節約術 - AVIF HowTo
画像圧縮でNASの空き容量の節約術 - AVIF

写真ファイルも結構容量を喰っている

 この前、動画ファイルの圧縮による容量節約術をご紹介しましたが、今回は写真データの圧縮によるNASのダイエットついて語ります。

 みなさんはスマホやデジカメで撮影する写真をどのようなフォーマットで保存していますか?最近の撮像素子を搭載したカメラでは4000ピクセル超えは当たり前という、途方もないサイズのデータが生成されたりして、あっと言う間にSDカードがパンパンになった経験をお持ちではないかと思います。

 私の使用する Xperia XZ3 の標準カメラアプリで撮影した場合、3,096 x 5504 ピクセル解像度のJPEGファイルで4MBから10MB(中央値は6MB程度)といった具合です。年単位で写真を撮り貯めていくとNASを圧迫するのに十分なサイズになることが予想されます。すでにもうそうなっている人も多いのではないでしょうか?

容量圧縮の目標

 今回は、画質を損なわずに最低でも50%程度の圧縮率を目指します。

 用途によって最適なアプローチが異なりますので、そのあたりについても触れていきたいと思います。

容量圧縮のメリット

 容量が減ることのメリットは、ストレージの圧迫が小さくて済むことです。NASを労わることになりますし、ファイルの移動時間の短縮にも繋がります。

 それだけではありません。写真を閲覧する時にはデータの読み出しが発生するわけで、その処理時間を短縮することにもつながり、ユーザビリティが向上します。このことは、クラウドストレージを使用する場合においては結構なストレス緩和となりますので馬鹿になりません。

写真ファイルの容量圧縮の方法

 大きく2つの方法があります。

  1. サイズを小さく
  2. 圧縮率を大きく

 1の方法は賢いやり方ではありません。写真は撮影時は可能な限り大きくしておき、保存もそのサイズを維持するほうがよいです。4Kディスプレイでの視聴が今後一般的になってきた時に解像度を落とした写真を閲覧すると、オリジナルに比較してかなり画質が見劣りしてしまうからです。

 2の方法で容量圧縮する方法で最適な方法を模索してみます。

スマホの解像度縮小アプリはおすすめできない理由

 スマホアプリでサイズを縮小して容量を圧縮してくれる類のものをよく見かけます。容量の追加が容易でないスマホにおいては一見有難い機能ではありますが、撮影した画像はなるべくオリジナルに近い形で保存しておきたいものです。一度サイズをシュリンクさせてしまったら2度と元には戻せません。

 スマホの小さい画面で見る分には支障がなくとも、大型テレビなどで見たときにはかなりの違和感を覚えるはずです。撮影データは解像度を縮小をせず、閲覧用のデータを別に生成するのが手間は掛かりますがベストな方法です。

圧縮率を上げるにはどうしたらいいか?

 ここではオリジナルのデータのフォーマットを JPEG と想定します。デジカメでもAndroidでも一般的なものですね。JPEGフォーマット自体、圧縮が効く画像フォーマットですので、zip などによる圧縮による容量削減効果はほとんど見込めません。

 一口に圧縮率を上げるといっても、2つのアプローチがあります。

JPEGの圧縮率を上げる

 これは古典的な方法ですが、依然として有効な手段です。

 20世紀から存在するJPEGフォーマットは、すでにあらゆるところで利用されており枯れた技術です。枯れた技術というのは安心して利用できることを意味します。

画像のフォーマットを変更する

 演算速度の向上によって、最新の画像フォーマットは優れた圧縮率を実現できています。

 今回は、その中でも最有力株である AVIF フォーマットを中心に検証していきます。

実際に圧縮して画質を比較してみる

 画像ファイルをハンドリングする環境はいろいろありますが、今回はWindows環境からも簡単に扱うことのできる Python + Pillow ( Python の画像処理ライブラリ )の環境でテストしてみることにします。

JPEG の圧縮率を上げる

 オリジナルの JPEG ファイルの圧縮率を上げてみます。

 Pillow に与えるクオリティというパラメータは30(初期値は75)に設定しています。画質をある程度犠牲にしますが、最小限の劣化で劇的な容量圧縮効果を得られる値です。

 以下が使用したコードです。処理時間も計測しています。

# compress JPEG to JPEG with Pillow

from PIL import Image
from io import BytesIO
import os
import time
import glob

start = time.time()

QUALITY = 30

files = glob.glob("./*.JPG")
for file in files:

	original_file_size = os.path.getsize(file)

	file_name = os.path.splitext(os.path.basename("./" + file))[0]
	with open(file, 'rb') as inputfile:
		im = Image.open(inputfile)
		im_io = BytesIO()
		im.save(im_io, 'jpeg', quality = QUALITY, exif=im.info['exif'])
	with open('./compress/' + file_name + '.JPG', mode='wb') as outputfile:
		outputfile.write(im_io.getvalue())

	output_file_size = os.path.getsize('./compress/' + file_name + '.JPG')

	compress_rate = output_file_size / original_file_size
	print( compress_rate )

end = time.time()
print(end - start)

JPEG から AVIF へのコンバート

 次にオリジナルの JPEG ファイルから AVIF フォーマットへコンバートしてみます。クオリティなどのパラメータは JPEG の時と同様です。

# compress JPEG to AVIF with Pillow

from PIL import Image
from io import BytesIO
import os
import time
import glob
import pillow_avif

start = time.time()

QUALITY = 30

files = glob.glob("./*.JPG")
for file in files:
#	print(file)

	original_file_size = os.path.getsize(file)

	file_name = os.path.splitext(os.path.basename("./" + file))[0]
	with open(file, 'rb') as inputfile:
		im = Image.open(inputfile)
		im_io = BytesIO()
		im.save(im_io, 'avif', quality = QUALITY)
	with open('./compress/' + file_name + '.avif', mode='wb') as outputfile:
		outputfile.write(im_io.getvalue())

	output_file_size = os.path.getsize('./compress/' + file_name + '.avif')

	compress_rate = output_file_size / original_file_size
	print( compress_rate )

end = time.time()
print(end - start)

オリジナルと生成されたデータの比較

 それぞれのファイルをダウンロードして比較してみてください。 

オリジナル JPEG フォーマットの画像

桔梗(キキョウ)の花 - オリジナル
桔梗(キキョウ)の花 – オリジナル

高圧縮率 JPEG フォーマットの 画像

桔梗(キキョウ)の花 - JPEGフォーマット
桔梗(キキョウ)の花 – JPEGフォーマット

AVIF フォーマットの 画像

桔梗(キキョウ)の花 - AVIFフォーマット
桔梗(キキョウ)の花 – AVIFフォーマット

 あなたに画質の違いがわかりますか?

 このページ上の表示サイズでは、その差を見分けるのは相当困難なレベルです。極端な拡大画像を比較して重箱の隅をつつくことはやめにします。みなさんの目で見たものが現実です。

 もし、このクオリティダウンがあなたの審美眼にかなわないということであれば、クオリティの値を上げて最適解を見つけてみてください。

容量の比較

 クオリティを30で統一した結果ですが、フォーマットごとの圧縮アルゴリズムは異なりますから、容量には大きな違いが現れました。驚きの結果です。

オリジナル

6,950KB ( 100% )

高圧縮率JPEG

736KB ( 10.5% )

AVIF

87KB ( 1.2% )

 なんと、AVIF フォーマットへのコンバートによる圧縮率は1.2%という驚異の数字になりました!

 あまりにビックリしたので、手持ちの写真100程度を対象に圧縮率の平均値を取ってみたところ、高圧縮JPEGでは16.3%AVIF では5.8%になりました。画像圧縮では、細かな表現が多ければ多いほど圧縮率が下がる特性があるため、かなりのバラつきが生じます。このように背景面積が広くボケているような画像では顕著な結果が出た模様です。それにしても、演算処理のスピード向上で世界は変わりますね。

処理時間の比較

 このように素晴らしい性能を発揮する AVIF フォーマットにも泣き所があります。処理速度です。100枚の画像処理時間の比較を見てみましょう。

高圧縮率JPEG

25.67秒

AVIF

175.76秒

 AVIF では JPEG に比較して、およそ6.8倍の処理時間を要しています。10,000枚を処理するとなると、4時間以上のロスという計算になりますね。

 しかし、いくら画像が大量にあっても、寝る前に仕掛けておけば、翌朝には仕上がっていることでしょうから、このデメリットはそれほど深刻なものではないと判断することもできます。

AVIFは環境対応に多少の難あり

 AVIF は 最新のフォーマットであるため、Windows 11でも、まだネイティブにはサポートされていません。ただ、マイクロソフトのストアから AV1 Video Extension をインストールすれば無料で解決します。ひと手間面倒であることは確かですね。これをインストールしてしまえば、フォトなどのアプリでの閲覧もできるようになります。

AV1 ビデオ拡張機能 - Microsoft Apps
Windows 上のお気に入りのビデオ アプリで AV1 ビデオを再生します。この拡張機能は、Windows にインストールされているビデオ アプリが、Alliance for Open Media で開発された AV1 ビデオ コーディン...

 AVIF フォーマットは、AV1 フォーマットと同じく業界で今後手厚くサポートされることが表明されていますから、一発屋でないレベルに至っていることは確かで、未来においてファイルのハンドリングに窮してしまうような憂き目に会うことはなさそうです。

 今後においては、CPUやGPUでのエンコード/デコードのアクセラレーション対応も進み、処理速度の問題も早晩解消していくことでしょう。

 クオリティの低下と容量低減のトレードオフに鑑み、手持ちのライブラリを圧縮するための選択肢として、AVIF が有望株であることはお分かりいただけたと思います。ただし、ライフスタイルによっては、写真のフォーマットはJPEGのまま保持したほうがいろいろと不便がないこともまた事実ですから、あなたにあったアプローチを選択して、NASのシェイプアップにトライしてみてください。