繰り返しJpeg圧縮しても意外と画質は落ちない

Jpegファイルを品質80→品質80→品質80と繰り返し圧縮すると、どんどん画質が低下してヤバいことになるイメージがないでしょうか。

自分もそう思っていましたが、試したところ意外なことがわかりました。

# TL;DR

やっぱりJpegは85で保存しとけばよさそうです。

* 同じ解像度なら同じ品質でJpeg保存を繰り返しても実はほぼ劣化しない。
* リサイズなど加工が入ると繰り返しにより画質が漸減する。
* [Googleが推奨する品質85](https://qiita.com/miyanaga/items/a616261de490cc342d08)ならリサイズの繰り返しにもやや耐性がある。

# 解像度が同じケース

## 前提

* 実行環境はmacOS mojave
* エンコーダはHomebrewでインストールしたImageMagick 7.0.8-12

## 実験

* 品質90, 85, 80, 60, 40について5回ずつ繰り返し保存してみる。
* 最初に圧縮された画像とのSSIMを随時、計算する。

## 結果

同じ解像度なら、同じ品質で繰り返し保存しても画質がほとんど落ちない。

### 品質40での例

実験の中でいちばん低い品質40を繰り返してもほとんど変わりません。

<table>
<tbody>
<tr>
<th>40を1回</th>
<th>40を5回</th>
</tr>
<tr>
<td>

<a href="https://qiita-image-store.s3.amazonaws.com/0/35178/137f6f04-6128-d631-8410-02b4770dce70.jpeg">
<img src="https://qiita-image-store.s3.amazonaws.com/0/35178/137f6f04-6128-d631-8410-02b4770dce70.jpeg">
</a>

</td>
<td>

<a href="https://qiita-image-store.s3.amazonaws.com/0/35178/a58b11d6-9755-6f00-68c7-32d09fb7521a.jpeg">
<img src="https://qiita-image-store.s3.amazonaws.com/0/35178/a58b11d6-9755-6f00-68c7-32d09fb7521a.jpeg">
</a>

</td>
</tr>
</tbody>
</table>

### 他の品質の場合とSSIM

SSIMは何回繰り返しても`ほぼ1.0`です。

|品質|1回目|2回目|3回目|4回目|5回目|
|--:|--:|--:|--:|--:|--:|
|90|90|90|90|90|90|
|SSIM|0.99998|0.999976|0.999975|0.999974|0.999973|
|85|85|85|85|85|85|
|SSIM|0.999989|0.999988|0.999988|0.999987|0.999987|
|80|80|80|80|80|80|
|SSIM|0.999994|0.999992|0.999992|0.999991|0.999991|
|60|60|60|60|60|60|
|SSIM|0.999996|0.999996|0.999996|0.999996|0.999996|
|40|40|40|40|40|40|
|SSIM|1.0|0.999999|0.999999|0.999999|0.999999|

### 100回ならどうだ

品質40での再圧縮を100回繰り返してもSSIMは`0.999999`でした。

## 考察

当初は、圧縮によって少なからず新しい画素の並びに変化するので、そのパターンをまたできるだけ保持しようと頑張るJpeg圧縮が行われるが、やはりまた新しいパターンが生まれる(高周波成分が失われ劣化する)、そんな繰り返しで画質は漸減すると予想しました。

そうではなく同じ品質で保存すると、DCTテーブルがほぼ再現されるという推測の方が正しそうです。

# リサイズした場合はどうか

普通は同じ画像を加工せず保存しなおすとか無駄なことは行いません。

次にリサイズを繰り返したときの検証です。リサイズはさすがに画質が失われていきそうですがどうでしょうか。

## 品質40で繰り返しリサイズ

1. 品質40で解像度縦横80%のリサイズを5回繰り返す。
2. 元画像から同じ解像度に、品質40一発で保存する。

<table>
<tbody>
<tr>
<th>品質40で80%リサイズを5回</th>
<th>品質40を1回で同じ解像度に</th>
</tr>
<tr>
<td>

<a href="https://qiita-image-store.s3.amazonaws.com/0/35178/7c5bf7ab-be09-ebf2-3bd4-43b18378264b.jpeg">
<img src="https://qiita-image-store.s3.amazonaws.com/0/35178/7c5bf7ab-be09-ebf2-3bd4-43b18378264b.jpeg">
</a>

</td>
<td>

<a href="https://qiita-image-store.s3.amazonaws.com/0/35178/dcfb7782-3699-ac4b-fe89-c63ef3d6abf9.jpeg">
<img src="https://qiita-image-store.s3.amazonaws.com/0/35178/dcfb7782-3699-ac4b-fe89-c63ef3d6abf9.jpeg">
</a>

</td>
</tr>
</tbody>
</table>

まさに「Jpegの圧縮を繰り返すとこんな風になるよねー」という結果です。
とはいえ目も当てられないほどの画質ではありません。SSIMは`0.945993`です。

## 品質85で繰り返しリサイズ

85だとかなり健闘します。SSIM `0.979148` の違いしかありません。かなり注意深く見ないとわかりません。

1. 品質85で解像度縦横80%のリサイズを5回繰り返す。
2. 元画像から同じ解像度に、品質85一発で保存する。

<table>
<tbody>
<tr>
<th>品質85で80%リサイズを5回</th>
<th>品質85を1回で同じ解像度に</th>
</tr>
<tr>
<td>

<a href="https://qiita-image-store.s3.amazonaws.com/0/35178/4d75a8da-f367-a09f-1d11-2aad6be50ae7.jpeg">
<img src="https://qiita-image-store.s3.amazonaws.com/0/35178/4d75a8da-f367-a09f-1d11-2aad6be50ae7.jpeg">
</a>

</td>
<td>

<a href="https://qiita-image-store.s3.amazonaws.com/0/35178/56776e89-b94c-08d1-6b63-ef98c083c61d.jpeg">
<img src="https://qiita-image-store.s3.amazonaws.com/0/35178/56776e89-b94c-08d1-6b63-ef98c083c61d.jpeg">
</a>

</td>
</tr>
</tbody>
</table>

以上です。