JPEG圧縮を繰り返しても際限なく劣化するわけではない2017年02月10日 01:47
ビデオテープのダビングやコピー機でのコピーは世代を重ねるごとに劣化が蓄積する。
同様にJPEG画像も、保存→開く→保存…と繰り返すと、

オリジナル
保存1回目
保存9回目
保存17回目
保存49回目
保存97回目
保存201回目
保存497回目
保存1001回目
保存2001回目
保存5001回目
保存10001回目といった具合に劣化が蓄積して画質が際限なく落ちていき、最後には一面のノイズになってしまう…
…と誤った認識を持っている人が多い。
実際に試してみよう。使用するソフトは定番のImageMagick。
結果は次のとおり。

オリジナル
保存1回目
保存17回目
以上だ。
3000回くらい回していたのだが、確認してみると18回目で既に前回と同一の画像が出力されていた。だいぶ時間を無駄にした。
このように、繰り返し保存による劣化は早々に止まることが分かる。
なお今回は1種類に収束したが、以前試した時は3種類のローテーションになったこともあった。
また、見て分かる(分からない)とおり、1回目と17回目で差はほとんど無い。
念のため差分をとってみよう。

全く見えないので64倍に強調したものも置いておく。

そもそも非可逆圧縮の原理は、元データを少々変えて「圧縮しやすいデータ」を作り、それを可逆圧縮するものと解釈できる。
よって一度非可逆圧縮したデータを展開したデータは、既に「圧縮しやすいデータ」になっているため、同じ設定で圧縮すれば完全に可逆圧縮になってもおかしくない。
むしろ17回まで劣化が続くことの方が不思議といえる。
ではなぜかだが、JPEGの圧縮の根幹である離散コサイン変換(DCT)は本来は可逆なのだが、実際には有限の精度で計算するために丸め誤差が発生する。おそらくこれがJPEG再圧縮が不可逆な原因だと思う。
またどうもJPEGの仕様はあまり厳密でないようで、エンコードでは演算の精度をソフトの自由で選べたり、デコードもソフトによって結果が違ったりする。これも一因かもしれない。
(2/11追記)RGB→YUVの変換も丸め誤差が発生するので一因かもしれない。
さて次にパラメータを少し変えてみる。

オリジナル
1回目
10回目
20回目
50回目
103回目
今度は劣化が103回目まで続く。劣化の度合いも目に見えて分かる。色が褪せていて、特に赤が大幅にくすんでしまっている。
差分をとってみる。

少し見にくいので4倍に強調しておこう。

闇夜に光る眼のようで可愛い。
何を変えたかというと、カラーサブサンプリングだ。
カラーサブサンプリングは、クロマサブサンプリングや色成分間引きと呼ばれたり、単にサンプリングやサンプリング比という名の設定項目で設定したりする。名前が定まっておらず面倒な概念だ。
先の17回で劣化が止まったものは、カラーサブサンプリングがOff、別の言い方をするとサンプリングが1x1や4:4:4と呼ばれるものだ。この設定では輝度成分と色成分を元の解像度のまま処理する。この時、画像は8×8のブロックごとに処理され、隣のブロックとの間で影響を及ぼすことはない。
一方103回の方は、カラーサブサンプリングがOn、サンプリングが2x2や4:2:0と呼ばれる設定であり、輝度成分は元解像度で、色成分は縦横1/2に縮小してから処理をする。
この縮小で単純に2×2ピクセルを平均するのであれば16×16のブロック内に影響が留まるだろうが、どうもそうではなく線形補間か何かをされているようで、ドットの色が16×16pxの境界を越えてにじむ現象が見られる。これにより隣のブロックの色が圧縮に影響し、次回は隣の隣のブロックにまで波及し、と際限なく影響を与え合う。厳密なことは分からないがこれが劣化が長く続く理由ではないかと思う。
なので劣化が蓄積するというのは、カラーサブサンプリングOnの設定においてはある程度正しい。
ただしそれにしても際限なく劣化するということはないし、JPEGが全てそのように劣化するわけでもないことは上で示したとおりだ。
さてもうひとつ、冒頭の例のように完全なノイズにまで際限なく劣化させるにはどうすればよいだろう。劣化しそうな方法をいろいろ試してみた。
まず圧縮率を毎回変えたら量子化の閾値が変わることで劣化が続くのではないかと考えたのだが、駄目であった。1万回繰り返してもほぼ劣化が見えなかった。(同じ画像が続くことは無かったので何パターンかのローテーションになっていたようだ)
次に90度回転を試したがこれも同様であった。今回使ったJPEGの量子化行列は縦と横で対称でないのでそれによるゆらぎを期待したのだが…。
そこで毎回画像の位置をずらしてみることにした。7回右下へ1pxずらしたあと、1回左上に7pxずらして戻すの繰り返し。これは見事に成功、これでできたのが冒頭の画像だ。
なぜこれが上手くいくかは、正確なことは分からないが、特定のドットに注目するとそのドットは8×8のブロック内で位置が毎回変わるようになっており、これで誤差が波及し続けるのが一因だろう。
サンプリング2x2の時は止まってしまったのでそれ以外に何かあるのだろうが、よく分からない。何か誤差が発振するような機構があるのだろうか…。
なお90度回転も、画像サイズが8×8の倍数でない場合はずらすのと同じことになる。
以上、まとめると
・単純に同じ設定で圧縮を繰り返すだけでは際限なく劣化することはない。
・ただしサンプリングを落とした場合は少々劣化が続く。
・設定を変えても際限なく劣化はしてくれない。
・位置の移動を伴うと際限なく劣化した。
JPEGの劣化は奥が深い。
同様にJPEG画像も、保存→開く→保存…と繰り返すと、

オリジナル

保存1回目

保存9回目

保存17回目

保存49回目

保存97回目

保存201回目

保存497回目

保存1001回目

保存2001回目

保存5001回目

保存10001回目
…と誤った認識を持っている人が多い。
実際に試してみよう。使用するソフトは定番のImageMagick。
magick convert -sampling-factor 1x1 -quality 95 orig.png gen1.jpg
magick convert -sampling-factor 1x1 -quality 95 gen1.jpg gen2.jpg
magick convert -sampling-factor 1x1 -quality 95 gen2.jpg gen3.jpg
…
このようなバッチファイルをExcelとテキストエディタで作成し、実行する。magick convert -sampling-factor 1x1 -quality 95 gen1.jpg gen2.jpg
magick convert -sampling-factor 1x1 -quality 95 gen2.jpg gen3.jpg
…
結果は次のとおり。

オリジナル

保存1回目

保存17回目
以上だ。
3000回くらい回していたのだが、確認してみると18回目で既に前回と同一の画像が出力されていた。だいぶ時間を無駄にした。
このように、繰り返し保存による劣化は早々に止まることが分かる。
なお今回は1種類に収束したが、以前試した時は3種類のローテーションになったこともあった。
また、見て分かる(分からない)とおり、1回目と17回目で差はほとんど無い。
念のため差分をとってみよう。

全く見えないので64倍に強調したものも置いておく。

そもそも非可逆圧縮の原理は、元データを少々変えて「圧縮しやすいデータ」を作り、それを可逆圧縮するものと解釈できる。
よって一度非可逆圧縮したデータを展開したデータは、既に「圧縮しやすいデータ」になっているため、同じ設定で圧縮すれば完全に可逆圧縮になってもおかしくない。
むしろ17回まで劣化が続くことの方が不思議といえる。
ではなぜかだが、JPEGの圧縮の根幹である離散コサイン変換(DCT)は本来は可逆なのだが、実際には有限の精度で計算するために丸め誤差が発生する。おそらくこれがJPEG再圧縮が不可逆な原因だと思う。
またどうもJPEGの仕様はあまり厳密でないようで、エンコードでは演算の精度をソフトの自由で選べたり、デコードもソフトによって結果が違ったりする。これも一因かもしれない。
(2/11追記)RGB→YUVの変換も丸め誤差が発生するので一因かもしれない。
さて次にパラメータを少し変えてみる。

オリジナル

1回目

10回目

20回目

50回目

103回目
今度は劣化が103回目まで続く。劣化の度合いも目に見えて分かる。色が褪せていて、特に赤が大幅にくすんでしまっている。
差分をとってみる。

少し見にくいので4倍に強調しておこう。

闇夜に光る眼のようで可愛い。
何を変えたかというと、カラーサブサンプリングだ。
カラーサブサンプリングは、クロマサブサンプリングや色成分間引きと呼ばれたり、単にサンプリングやサンプリング比という名の設定項目で設定したりする。名前が定まっておらず面倒な概念だ。
先の17回で劣化が止まったものは、カラーサブサンプリングがOff、別の言い方をするとサンプリングが1x1や4:4:4と呼ばれるものだ。この設定では輝度成分と色成分を元の解像度のまま処理する。この時、画像は8×8のブロックごとに処理され、隣のブロックとの間で影響を及ぼすことはない。
一方103回の方は、カラーサブサンプリングがOn、サンプリングが2x2や4:2:0と呼ばれる設定であり、輝度成分は元解像度で、色成分は縦横1/2に縮小してから処理をする。
この縮小で単純に2×2ピクセルを平均するのであれば16×16のブロック内に影響が留まるだろうが、どうもそうではなく線形補間か何かをされているようで、ドットの色が16×16pxの境界を越えてにじむ現象が見られる。これにより隣のブロックの色が圧縮に影響し、次回は隣の隣のブロックにまで波及し、と際限なく影響を与え合う。厳密なことは分からないがこれが劣化が長く続く理由ではないかと思う。
なので劣化が蓄積するというのは、カラーサブサンプリングOnの設定においてはある程度正しい。
ただしそれにしても際限なく劣化するということはないし、JPEGが全てそのように劣化するわけでもないことは上で示したとおりだ。
さてもうひとつ、冒頭の例のように完全なノイズにまで際限なく劣化させるにはどうすればよいだろう。劣化しそうな方法をいろいろ試してみた。
まず圧縮率を毎回変えたら量子化の閾値が変わることで劣化が続くのではないかと考えたのだが、駄目であった。1万回繰り返してもほぼ劣化が見えなかった。(同じ画像が続くことは無かったので何パターンかのローテーションになっていたようだ)
次に90度回転を試したがこれも同様であった。今回使ったJPEGの量子化行列は縦と横で対称でないのでそれによるゆらぎを期待したのだが…。
そこで毎回画像の位置をずらしてみることにした。7回右下へ1pxずらしたあと、1回左上に7pxずらして戻すの繰り返し。これは見事に成功、これでできたのが冒頭の画像だ。
なぜこれが上手くいくかは、正確なことは分からないが、特定のドットに注目するとそのドットは8×8のブロック内で位置が毎回変わるようになっており、これで誤差が波及し続けるのが一因だろう。
サンプリング2x2の時は止まってしまったのでそれ以外に何かあるのだろうが、よく分からない。何か誤差が発振するような機構があるのだろうか…。
なお90度回転も、画像サイズが8×8の倍数でない場合はずらすのと同じことになる。
以上、まとめると
・単純に同じ設定で圧縮を繰り返すだけでは際限なく劣化することはない。
・ただしサンプリングを落とした場合は少々劣化が続く。
・設定を変えても際限なく劣化はしてくれない。
・位置の移動を伴うと際限なく劣化した。
JPEGの劣化は奥が深い。
CDのピットの数
6段のカレンダーが好きだ
PIC16のDhrystone MIPSを測ろうとしてみた
Twitterの画像の扱いがやっとまともになって嬉しい
ファミコンで9×9ドット文字表示(ほか)
謎の色名「honeydewtab」とlegacy color valueパース手順
6段のカレンダーが好きだ
PIC16のDhrystone MIPSを測ろうとしてみた
Twitterの画像の扱いがやっとまともになって嬉しい
ファミコンで9×9ドット文字表示(ほか)
謎の色名「honeydewtab」とlegacy color valueパース手順
Post time : 2017年02月10日 01:47│Comments(2)
│プログラム・アルゴリズム
この記事へのコメント
JPEG画像の劣化で一番大きい要因は量子化によるものです。不可逆なのは量子化→逆量子化で、除算して乗算するので例えば123/10=12、12*10=120のように123→120に劣化します(DCTの結果であって画素データではないので注意)。ただしこれも低周波成分(人間の目に劣化がわかりやすい部分)よりも高周波成分(人間の目でわかりにくい部分)の劣化が大きくなるようになっています。
上記量子化(除算)に使用するテーブルはエンコード時に指定した画質によって決まります(実際のテーブルはソフトによってまちまちなので同じ画質を指定してもソフトが違えば画質は異なります)。画質95でエンコードしているようですが、95だとかなり高画質なのでそもそも劣化は少ないです。画質を落としてエンコードする場合はもっとどんどん画質が落ちていくと思います(際限なくではなくある程度収束はしますが)。
あと、JPEGでは限界まで劣化すると8x8ブロックの単色ブロックが並んだものになります(これはDCTのAC成分が全0の状態)。最初の例のような劣化にはなりません。あくまでも多くの人が持っているであろうイメージを示しただけというのはわかりますが。
上記量子化(除算)に使用するテーブルはエンコード時に指定した画質によって決まります(実際のテーブルはソフトによってまちまちなので同じ画質を指定してもソフトが違えば画質は異なります)。画質95でエンコードしているようですが、95だとかなり高画質なのでそもそも劣化は少ないです。画質を落としてエンコードする場合はもっとどんどん画質が落ちていくと思います(際限なくではなくある程度収束はしますが)。
あと、JPEGでは限界まで劣化すると8x8ブロックの単色ブロックが並んだものになります(これはDCTのAC成分が全0の状態)。最初の例のような劣化にはなりません。あくまでも多くの人が持っているであろうイメージを示しただけというのはわかりますが。
Posted by 俺様 at 2024年02月03日 16:08
それはJPEGの1回の圧縮の話ですね。
ここで問題にしているのは既に圧縮されたJPEGの再圧縮の話です。
ここで問題にしているのは既に圧縮されたJPEGの再圧縮の話です。
Posted by いかづちSqueak
at 2024年03月28日 01:31
