動画エンコーダ屋さんと会話して少しわかった画質の話（PSNR / RD曲線 / BD-rate）

動画コーデック/動画エンコード周りの話です。これは一例ですが、巷には「H.265はH.264と同等画質でデータ量が半分になる」みたいな言説が見られます。

> 　H.264/MPEG-4 AVC以上に圧縮効率を高めて半分以下のビットレートを実現する。モバイルデバイスや、4K解像度などの超解像度ビデオにおける利用を想定している。
> https://pc.watch.impress.co.jp/docs/news/585297.html

たぶんより新しい技術だからすごいんだろうと思う一方で、画質・ビットレートに関する根拠というか考え方がさっぱりわかりません :thinking: 

- 画質と言われても何をどうやって測定しているのか
- どんな条件でもぴったり半分になるのか？ さすがにそんなことはなさそう？

よくわからなさすぎて困ったので、会社の自席の近くにいる動画エンコーダの専門家に基本的な事項について教わってみたので、その内容をまとめます。ちゃんとした専門家から見ると拙い箇所があるかも知れませんのでご注意ください。

## TL;DR

- 動画コーデックやそのパラメータの優劣は、あるデータセットに対するBD-rateを計算することで求める
- BD-rateはRD曲線から計算する
- RD曲線は、PSNRなどの評価指標から計算する

見慣れない単語がたくさん並んでしまいました。順番にまとめていきます。

## PSNR

### 指標の位置づけ
動画像の画質について評価する際には

- 人間がある規格化された手順で観察して、画質の良さをスコアリングする
- 何らかのアルゴリズムで「画質の良さスコア」を算出する

主にこの二通りの切り口で議論されることが多いです。前者を主観評価・後者を客観評価と呼びます。

### PSNRとは

客観評価手法のうち、（色々と問題はあるのですが）よく使われている古典的なメトリクスがPSNRです。このメトリクスはfull-reference型、つまりエンコードによって非可逆圧縮される前と後を比較し、発生した差分からスコア計算するものです。これに関しては、↓などの解説記事が沢山あるので詳細を省略します。

- [ピーク信号対雑音比 - Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%94%E3%83%BC%E3%82%AF%E4%BF%A1%E5%8F%B7%E5%AF%BE%E9%9B%91%E9%9F%B3%E6%AF%94)
- https://qiita.com/yoya/items/510043d836c9f2f0fe2f

この記事では、次のような理解で十分です。

- PSNRは、比較対象の2つの動画像を入力するとスコアが得られる一種の関数とみなせる
- スコアは単位デシベル(dB)で得られる。典型的には30dBとか40dBとか、それぐらいの数字になる
- 大きいほどきれい。つまり、元入力の再現度が高い
- 動画に対して適用する場合、動画の全フレームの差分平均から計算する[^fast-impl]

[^fast-impl]: ツールによっては高速だが精度が低い実装を提供していることもあります。具体例として、有名なMSU Quality Measurement Toolだと、全フレームのPSNRをフレーム単位PSNRの平均として近似する実装を提供しているようです。 参照: http://www.compression.ru/video/quality_measure/info.html#psnr

### PSNR取り扱いの注意点

PSNRは、計算式自体はとても単純なのですが、実用するには注意点というか微妙な点が多数出てくるので、そのあたりへの配慮が必要です（それをわかった上で使うことになります）。

#### 人間の主観との相関は、ほどほど程度（必ずしも良好とは言えない）

Netflixは、自社のデータセットに関して主観評価と客観評価メトリクスの相関を調査した結果を公表しています。

<img src="https://cdn-images-1.medium.com/max/2000/0*vACj-yx-J3oXP_-c." alt="widely-used video quality metrics vs DMOS" width="50%">
出典: https://medium.com/netflix-techblog/toward-a-practical-perceptual-video-quality-metric-653f208b9652

DMOSは主観評価（人間が採点した）メトリクスです。PSNRはDMOSと緩やかに相関していますが、それほど強い相関ではなく、またコンテンツ（色が違う点は別のコンテンツです）によって差が大きいこともわかります。

#### カラーチャンネルをどう扱うかは……微妙

世の中の大抵の動画像は、モノクロではなく色がついています。カラー動画像を扱う際には、各ピクセルを3つのカラーチャンネルに分解する色空間で表すことがほとんどです。色空間はRGBやYCbCrなどに大別され、さらに具体的な規格が無数に存在します。

この時何が困るかというと、2つのピクセルの差を単純に定義できなくなるという点です。1ピクセルに3つの値があるため、単なる差の絶対値を取ると3つの値が出てきます。

- カラーチャンネルごとにPSNRを計算する
- （YCbCr系の色空間であれば）YチャンネルのPSNRのみを計算する
    - 特にY-PSNRと呼ばれることがあります
- 重み付き平均を取る
    - 例えばY:Cb:Cr = 6:1:1にするなど

などなど、一口に「PSNRを計算する」と言ってもバリエーションが多いので注意が必要です[^chroma-subsampling]。

[^chroma-subsampling]: ちなみに、YCbCrを採用する映像系の規格では、人間がCbCrに比較的鈍感であることを利用して解像度を下げて記録するという情報削減の手法（chroma subsamplingと呼ばれます）が用いられることも多いです。この場合、そもそもカラーチャンネルごとに記録している値の数が異なるため、状況はさらに混沌としてきます。

#### PSNRを過信しすぎない

よく訓練された人間の感覚はとても優れています。そもそも動画像は人間が見るためのものなので、最終的には主観評価で画質の評価をするのが妥当だと、動画コーデック屋さんは考えているようです。

## RD曲線

あるコーデック・エンコーダ・エンコード・パラメータについて議論する時、「エンコーダが使えるビットレートを変化させた時に画質はどう変化するか」という観点から特性を見ます。具体的には、エンコーダの品質パラメータを変化させながら、PSNRのような画質の指標を測定することで、ビットレート/PSNRの組をグラフ上にプロットしていきます。
もちろん、このままでは離散的な測定点しか得られないので、通常は何らかの方法（スプライン補間など）で補間することで曲線にします。

データ量を増やすとノイズは減るため、横軸にビットレート縦軸にPSNRをとる時、グラフとしては単調増加の曲線を描くことになります。
この曲線はレート（Rate: ビットレートのことです）と歪み（Distortion: 要するに画質の良し悪しことです）の関係を表したものなので、RD曲線（RD-curve）と呼ばれます。複数のRD曲線を並べることで、エンコーダやエンコードオプションなどの優劣を論じることができるようになります。

一例として、MSUが出しているレポートから引用[^msu-rd-curve]します。

<img width="408" alt="example-rd-curve.png" src="https://qiita-image-store.s3.amazonaws.com/0/64680/266ba143-1db7-4b7f-7388-0557ec63453c.png">

[^msu-rd-curve]: 出典: [Fourth Annual MSU MPEG-4 AVC/H.264 Video Codec Comparison](http://compression.ru/video/codec_comparison/mpeg-4_avc_h264_2007_en.html) のFree Versionからです。

（そのコンテンツに関して）どのエンコーダがどのビットレート領域でどれぐらい優れているのか、RD曲線から読み取れることがわかります。

また、RD曲線のDはPSNRがよく利用されるものの、必然性はありません。例えば[SSIM](https://en.wikipedia.org/wiki/Structural_similarity)でも同様の意図のグラフを描くことはできます。ただし、この記事では、以降のRD曲線はPSNRを用いるものとします。

## BD-rate

RD曲線を比べることで、2つの（複数の）コーデックやパラメータの特性の違いを観察できるわけですが、定量的にどれぐらいの差があるのか計算する方法を、Gisle Bjøntegaardという人が2001年にITU-Tで提案しました。

この指標は提案者の名前を取って、BD-PSNR(Bjøntegaard delta PSNR)と呼ばれます。また、RD曲線はPSNRが同一の時のビットレートの違いという見方もできます。その時に得られる差はBD-rate(Bjøntegaard delta bitrate)と呼ばれます。

BD-rateは割合の差分なので、例えば-0.2だと、同一画質で2割ビットレートが削減されていることになります。100倍してパーセンテージ表記されることもあります（今の例だと-20%）。

### 算出の流れ

BD-rateは次の手順で計算します。

- 比較対象となる2つのRD曲線について……
- R（レート）軸が常用対数になったRD曲線を考える
- RD曲線を三次多項式で近似する
- このようにして求めた2つの近似多項式の差の平均を、割合で求める
    - つまり関心のある区間で差を積分することになります

Netflixのイラストが直感的でわかりやすいです。この図は常用対数による変換を行っていない点には注意してください[^why-no-log10]。
<img src="https://cdn-images-1.medium.com/max/1600/1*L41DNP3htghVJofp81zeTw.png" width="70%">
出典: https://medium.com/netflix-techblog/toward-a-practical-perceptual-video-quality-metric-653f208b9652

[^why-no-log10]: BD-rateの問題は対数変換が重要なのではなく、積分するために曲線当てはめ問題を解きたい、というのが本質的です。オリジナルの提案では、常用対数変換をした場合の方が特異点を回避でき、実験的に都合が良かったという経緯があるようです。

### もう少し数学的な説明

もう少しだけ厳密に書きます。
RD曲線は、ビットレート$R$と歪み$D$の関係なので、関数$R(D)$と書くことにします。
いま求めたいBD-rateは、2つのRD曲線$R_1(D), R_2(D)$が平均的にどれだけの割合で違うかです。

```math
\text{BD-rate} = \frac{R_2(D) - R_1(D)}{R_1(D)}
```

これを具体的に計算するために、$R$を対数変換した$r = \log_{10}(R)$と、PSNRである$D$の関係を三次多項式で補間します。補間曲線を

```math
r = a + bD + cD^2 + dD^3
```

と書くことにします。$r$は$D$の関数です。2つの多項式$r_1, r_2$から$\text{BD-rate}$を求める、次のような近似式が知られています[^bd-rate-approx]。

[^bd-rate-approx]: 例えば、 "[Video Quality Evaluation Methodology and Verification Testing of HEVC Compression Performance](https://ieeexplore.ieee.org/document/7254155)"を参照してください。正直、一見してさっぱりわからない近似式です……。

```math
\begin{eqnarray}
\text{BD-rate} &=& \frac{R_2(D)}{R_1(D)} - 1 \\
               &=& \frac{10^{r_2}}{10^{r_1}} - 1 \\
               &=& 10^{r_2 - r_1} - 1 \\
         &\approx& 10^{\frac{1}{D_H - D_L} \int^{D_H}_{D_L} (r_2 - r_1)\ dD} - 1 \\
\end{eqnarray}
```

ここで、$D_L, D_H$は、2つのRD曲線両端(min, max)の測定点のうち、内側の測定点のDです。ちょっと図がないとわかりづらいのですが。

- $D_L$: 2つのRD曲線の測定点のうち、それぞれでDが最小になるものを選ぶと、2つのDが得られる。そのうち大きい方
- $D_H$: 2つのRD曲線の測定点のうち、それぞれでDが最大になるものを選ぶと、2つのDが得られる。そのうち小さい方

このように数式で書くと比較的ややこしいのですが、要するに、2つの補間多項式を引き算して定積分した値を10の指数に乗せて1を引くと、BD-rateが求められます。

## BD-rateの具体的な計算例

具体的に2つのエンコーダの比較例を作ってみます。動画だと取り扱いが大変なので、今回は画像を使いますが、本質的な手順に違いはありません。

入力の画像としてはおなじみのLennaをグレースケール化したものを使います。本来は多数のコンテンツからなるデータセットを用いるのが適切だろうとは思います。
<img src="https://qiita-image-store.s3.amazonaws.com/0/64680/5145ca51-3e89-8e91-118a-fe939a7aa568.png" width="30%">

比較対象としては、手元のImageMagickに組み込まれたJPEGとWebPでやってみます。複雑なプリセット設定などは行わず、`-quality`を5通りに変化させながら、成果物のファイルサイズとPSNRを取得しています。

```bash
$ convert Lenna.png -type grayscale origial.png
$ for i in 10 25 50 75 90; do convert original.png -quality $i q$i.jpg; done
$ ls *.jpg | xargs -I{} sh -c 'compare -metric psnr original.png {} diff.png; echo'
30.1417
33.3566
35.4085
37.366
40.2008
ls -l *.jpg | awk '{ print $6 }'
6746
12986
21034
33289
60991
```
```bash
$ for i in 10 25 50 75 90; do convert original.png -quality $i q$i.webp; done
$ ls *.webp | xargs -I{} sh -c 'compare -metric psnr original.png {} diff.png; echo'   
31.7325
33.2348
35.18
36.7453
42.0154
$ ls -l *.webp | awk '{ print $6 }'
5912
8494
13476
20112
54288
```

結果をグラフにします。静止画なのでRateはファイルサイズですが、これからBD-rateを計算することになるので、Rateの軸を`log10(Rate)`とします。積分する時のことを考えて、今回は縦軸にビットレートの対数、横軸にPSNRとします。
<img width="403" alt="rd-curve-jpg-webp.png" src="https://qiita-image-store.s3.amazonaws.com/0/64680/090c79d9-41bf-9256-8ec9-ac8431ed025f.png">
2つの補間曲線はそれぞれ

- JPEG: $r_1 = -0.000320243 D^3 + 0.034155 D^2 - 1.11095 D + 15.054$ （→[Wolfram Alphaによる計算例](https://www.wolframalpha.com/input/?i=cubic+fit+%7B%7B30.1417,+3.829046%7D,+%7B33.3566,+4.113475%7D,+%7B35.4085,+4.322922%7D,+%7B37.366,+4.522301%7D,+%7B40.2008,+4.785266%7D%7D)）
- WebP: $r_2 = -0.000306757 D^3 + 0.0316499 D^2 - 0.981467 D + 12.8474$ （→[Wolfram Alphaによる計算例](https://www.wolframalpha.com/input/?i=cubic+fit+%7B%7B31.7325,+3.77%7D,+%7B33.2348,+3.93%7D,+%7B35.18,+4.13%7D,+%7B36.7453,+4.30%7D,+%7B42.0154,+4.73%7D%7D)）

です。

この時点で既に、グラフの全域でWebPの方が曲線が低いことから、同一画質ならファイルサイズがより小さくできており、符号化として優れているという雰囲気が掴めます。得られた数式を積分します。今回の測定点の共通範囲が31.7325dBから40.2008dBなので、この範囲で定積分することでBD-rateを算出します。

```math
\frac{1}{40.2008 - 31.7325} \int^{40.2008}_{31.7325} (-0.000306757 D^3 + 0.0316499 D^2 - 0.981467 D + 12.8474 - (-0.000320243 D^3 + 0.034155 D^2 - 1.11095 D + 15.054))\ dD \\
= -0.168946
```
（→ [Wolfram Alphaによる計算例](https://www.wolframalpha.com/input/?i=(1%2F(40.2008-31.7325))*(integral+from+31.7325+to+40.2008,+-0.000306757+x%5E3+%2B+0.0316499+x%5E2+-+0.981467+x+%2B+12.8474-(-0.000320243+x%5E3+%2B+0.034155+x%5E2+-+1.11095+x+%2B+15.054)))）したがって

```math
\text{BD-rate} \approx 10^{-0.168946} - 1 \approx -0.32
```

結論としては、同一画質（PSNR）ならJPEG比で3割ほどWebPがデータ量を削減できることがわかります。

## BD-rateの限界

ここまでの議論で既に明らかになっていると思うのですが、BD-rateは決して万能の指標ではありません。

- 区間全体の平均的なビットレート削減割合について述べているだけなので、ある特定領域では特性が異なることがある
- 計算にPSNRを使うため、PSNRそのものの限界を内包している
- 近似式の理論的妥当性が不明。2001年当時のデータセットに対して実験的に妥当性があったのだとしても、現代で同様の議論が成立するのか？
- （BD-rate固有の問題ではないが）データセットの選択が難しい

こういった限界があるため、例えば[Netflixの最近の記事](https://medium.com/netflix-techblog/performance-comparison-of-video-coding-standards-an-adaptive-streaming-perspective-d45d0183ca95)では、BD-bitrateの基本的な考え方を受け入れつつも、測定方法を調整しているように見受けられます。例えばPSNRではなくVMAFを使ったり、adaptive bitrateを評価プロセスに組み込むようにしているようです。

## 参考資料/関連リンク

- [Digital Video Concepts, Methods, and Metrics](https://www.apress.com/br/book/9781430267126)
- https://medium.com/netflix-techblog/performance-comparison-of-video-coding-standards-an-adaptive-streaming-perspective-d45d0183ca95
- https://code.fb.com/video-engineering/av1-beats-x264-and-libvpx-vp9-in-practical-use-case/
- https://streaminglearningcenter.com/encoding/compute-bd-rate-functions.html