Rec.709からRec.2020への変換行列はどこから来るのか
技術連結課の松浦です。
今回はHDR描画に関連する色域について紹介したいと思います。
HDR出力では、SDR用に作成したアセットをHDRで使用する際などに、色域の変換が必要になる場合があります。たとえば Rec.709 の色を Rec.2020 で正しく表示するには、3×3 の変換行列を掛けることになります。
この行列がどこから来るのかを自分でちゃんと追えていなかったので、今回は原色の座標から順に整理してみました。この記事では、まず変換行列の結果と使い方を示し、そのあとで計算の流れを追っていきます。
目次
色域について
色域は、その色空間で表現できる色の範囲です。
RGB で色を表す場合でも、RGB の値だけで色が決まるわけではなく、どの原色を使うか、どの白色点を使うかといった定義が必要になります。
CIE xy 色度図上では、3つの原色の座標を結んだ三角形が色域に対応します。三角形が大きいほど、表現できる色の範囲が広くなります。白色点は RGB 空間でいう (1, 1, 1) に対応する色で、三角形の内側に位置します。
代表的な色空間として、SDR でよく使われる Rec.709 と、HDRで広く用いられるRec.2020があります。それぞれの原色と白色点の xy 座標と色度図は以下の通りです。
| 原色R (x, y) | 原色G (x, y) | 原色B (x, y) | 白色点(x, y) | |
| Rec.709 | (0.640, 0.330) | (0.300, 0.600) | (0.150, 0.060) | D65 = (0.3127, 0.3290) |
| Rec.2020 | (0.708, 0.292) | (0.170, 0.797) | (0.131, 0.046) | D65 = (0.3127, 0.3290) |

Rec.2020 の原色は色度図上でより外側に位置するため、Rec.709 より広い色域を持ちます。
本記事では、HDR 出力で広く使われる Rec.2020 を念頭に、Rec.709 から Rec.2020 への色域変換を扱います。
変換結果と実装上の扱い
Rec.709 から Rec.2020 への変換は、 3×3 の行列として表せます。
ITU-R BT.2087 では、線形な Rec.709 RGB から線形な Rec.2020 RGB への変換として、次の行列が示されています。
$$
\begin{bmatrix}
0.6274 & 0.3293 & 0.0433 \\
0.0691 & 0.9195 & 0.0114 \\
0.0164 & 0.0880 & 0.8956
\end{bmatrix}
$$
この行列を使うと、Rec.709 の RGB を Rec.2020 の RGB へ変換できます。
実装上は、この行列をそのままシェーダなどで使えます。
ただし、ここで変換するのは線形空間の色データです。変換の前後で適切な転送関数の処理が必要になります。たとえば、sRGB で符号化されたテクスチャを扱う場合は、まず sRGB の逆転送関数で線形化してからこの行列を掛けます。変換後のデータをどの転送関数で再符号化するかは用途によって異なります。テクスチャとして保存するなら sRGB 等の画像フォーマットに合わせた転送関数を、ディスプレイに HDR10 で出力するなら PQを使います。
実際に変換
以下は、左から「元画像」「RGB 値をそのまま Rec.2020 として解釈した場合の sRGB プレビュー」「Rec.709 → Rec.2020 に変換した後の sRGB プレビュー」の比較です。
変換せずに Rec.2020 として扱うと色がずれて見えますが、正しく色域変換した場合は、そのずれが解消されて元画像の意図に近い見た目になります。
※プレビュー画像は SDR 環境向けにクリップしているため、Rec.2020 の広い色域をそのまま表示したものではありません。


ここではまず結果だけを使いましたが、次の章でこの行列がどのように導けるのかを追います。
なお、以下では途中計算の値は読みやすさのため小数第6位程度で丸めて表示しています。
Rec.709 から Rec.2020 への変換行列を導出する
ここでは、前の章で使った変換行列を、Rec.709 と Rec.2020 の原色座標から導きます。
考え方としては、Rec.709 の RGB をいったん XYZ 空間に変換し、そこから Rec.2020 の RGB に変換します。
つまり、
$$
\mathrm{Rec.709\ RGB} \rightarrow XYZ \rightarrow \mathrm{Rec.2020\ RGB}
$$
という流れです。
最終的に欲しい行列は、
$$
\mathbf{M}_{709 \to 2020}
=
\mathbf{M}_{XYZ \to 2020}
\mathbf{M}_{709 \to XYZ}
$$
です。
xy から XYZ を作る
色度座標 (x, y)は、XYZ から次のように定義されます。
$$
x = \frac{X}{X+Y+Z}, \qquad
y = \frac{Y}{X+Y+Z}
$$
ここから逆に XYZ を求めると、
$$
X = \frac{xY}{y}, \qquad
Z = \frac{(1-x-y)Y}{y}
$$
になります。
今回は原色ベクトルの向きだけが欲しいので、いったん Y = 1と置きます。
すると、
$$
X = \frac{x}{y}, \qquad
Y = 1, \qquad
Z = \frac{1-x-y}{y}
$$
になります。
Rec.709 の RGB→XYZ 行列を作る
まず Rec.709 の原色を XYZ ベクトルに変換します。
$$
r =
\begin{bmatrix}
0.640 / 0.330 \\
1 \\
(1 – 0.640 – 0.330)/0.330
\end{bmatrix}
=
\begin{bmatrix}
1.939394 \\
1 \\
0.090909
\end{bmatrix}
$$
$$
g =
\begin{bmatrix}
0.300 / 0.600 \\
1 \\
(1 – 0.300 – 0.600)/0.600
\end{bmatrix}
=
\begin{bmatrix}
0.5 \\
1 \\
0.166667
\end{bmatrix}
$$
$$
b =
\begin{bmatrix}
0.150 / 0.060 \\
1 \\
(1 – 0.150 – 0.060)/0.060
\end{bmatrix}
=
\begin{bmatrix}
2.5 \\
1 \\
13.166667
\end{bmatrix}
$$
これらを列に並べると、
$$
P_{709} =
\begin{bmatrix}
1.939394 & 0.5 & 2.5 \\
1 & 1 & 1 \\
0.090909 & 0.166667 & 13.166667
\end{bmatrix}
$$
です。
次に、白色点 D65 を XYZ にします。
$$
w =
\begin{bmatrix}
0.3127 / 0.3290 \\
1 \\
(1 – 0.3127 – 0.3290)/0.3290
\end{bmatrix}
=
\begin{bmatrix}
0.950456 \\
1 \\
1.089058
\end{bmatrix}
$$
ここで、各原色のスケールを \(S_r, S_g, S_b\) として、
$$
P_{709}
\begin{bmatrix}
S_r \\
S_g \\
S_b
\end{bmatrix}
=
w
$$
を解きます。
これはつまり、
$$
S_r r + S_g g + S_b b = w
$$
であり、赤・緑・青をどれだけの強さで足せば白色点になるかを解いています。
成分ごとに書くと、
$$
1.93939394 S_r + 0.5 S_g + 2.5 S_b = 0.95045593
$$
$$
S_r + S_g + S_b = 1
$$
$$
0.09090909 S_r + 0.166667 S_g + 13.166667 S_b = 1.089058
$$
です。
途中式
2本目から
$$
S_g = 1 – S_r – S_b
$$
を代入すると、
$$
1.439394 S_r + 2.0 S_b = 0.450456
$$
$$
-0.075758 S_r + 13.0 S_b = 0.922391
$$
となります。
これを解くと、
$$
S_r \approx 0.212639,\qquad
S_g \approx 0.715169,\qquad
S_b \approx 0.072192
$$
です。
したがって、Rec.709 の RGB→XYZ 行列は
$$
\mathbf{M}_{709 \to XYZ}
=
P_{709}
\begin{bmatrix}
S_r & 0 & 0 \\
0 & S_g & 0 \\
0 & 0 & S_b
\end{bmatrix}
$$
であり、実際に掛けると
$$
\mathbf{M}_{709 \to XYZ}
=
\begin{bmatrix}
0.412391 & 0.357584 & 0.180481 \\
0.212639 & 0.715169 & 0.072192\\
0.019331 & 0.119195 &0.950532
\end{bmatrix}
$$
となります。
Rec.2020 の RGB→XYZ 行列を作る
同じことを Rec.2020 でも行います。
$$
r =
\begin{bmatrix}
0.708 / 0.292 \\
1 \\
(1 – 0.708 – 0.292)/0.292
\end{bmatrix}
=
\begin{bmatrix}
2.424658\\
1 \\
0
\end{bmatrix}
$$
$$
g =
\begin{bmatrix}
0.170 / 0.797 \\
1 \\
(1 – 0.170 – 0.797)/0.797
\end{bmatrix}
=
\begin{bmatrix}
0.213300 \\
1 \\
0.041405
\end{bmatrix}
$$
$$
b =
\begin{bmatrix}
0.131 / 0.046 \\
1 \\
(1 – 0.131 – 0.046)/0.046
\end{bmatrix}
=
\begin{bmatrix}
2.847826 \\
1 \\
17.891304
\end{bmatrix}
$$
これを並べると、
$$
P_{2020} =
\begin{bmatrix}
2.424658 & 0.213300 & 2.847826 \\
1 & 1 & 1 \\
0 & 0.041405 & 17.891304
\end{bmatrix}
$$
白色点は同じ D65 なので、同じく
$$
w =
\begin{bmatrix}
0.950456 \\
1 \\
1.089058
\end{bmatrix}
$$
です。
同様に
$$
P_{2020}
\begin{bmatrix}
S_r \\
S_g \\
S_b
\end{bmatrix}
=
w
$$
を解くと、
$$
S_r \approx 0.262700,\qquad
S_g \approx 0.677998,\qquad
S_b \approx 0.059302
$$
となります。
したがって、Rec.2020 の RGB→XYZ 行列は
$$
\mathbf{M}_{2020 \to XYZ}
=
\begin{bmatrix}
0.636958 & 0.144617 & 0.168881 \\
0.262700 & 0.677998 & 0.059302 \\
0 & 0.028073 & 1.060985
\end{bmatrix}
$$
です。
したがって XYZ→Rec.2020 行列は、その逆行列です。
$$ \begin{aligned} \mathbf{M}_{XYZ \to 2020} &= \mathbf{M}_{2020 \to XYZ}^{-1} \\ &= \begin{bmatrix} 1.716651 & -0.355671 & -0.253366 \\ -0.666684 & 1.616481 & 0.015769 \\ 0.017640 & -0.042771 & 0.942103 \end{bmatrix} \end{aligned} $$
Rec.709 → Rec.2020 行列を作る
ここまで来れば、あとは合成するだけです。
$$
\mathbf{M}_{709 \to 2020}
=
\mathbf{M}_{XYZ \to 2020}
\mathbf{M}_{709 \to XYZ}
$$
実際に掛けると、
$$
\mathbf{M}_{709 \to 2020}
=
\begin{bmatrix}
0.627404 & 0.329283 & 0.043313 \\
0.069097 & 0.919540 & 0.011362 \\
0.016391 & 0.088013 & 0.895595
\end{bmatrix}
$$
となります。
小数第4位で丸めると、
$$
\begin{bmatrix}
0.6274 & 0.3293 & 0.0433 \\
0.0691 & 0.9195 & 0.0114 \\
0.0164 & 0.0880 & 0.8956
\end{bmatrix}
$$
です。
まとめ
Rec.709 と Rec.2020 の間の変換は、見た目として同じ色を 別の色域の RGB 値で表し直す処理です。
本記事で扱ったのはそのための 線形 RGB 同士の色域変換であり、PQ やトーンマッピングのような HDR 処理そのものは含みません。HDR パイプラインではこれらの処理も組み合わさるため、最終的な表示結果は SDR と見た目が異なる場合がある点には注意が必要です。
導出としては、まず Rec.709 の原色座標と白色点から RGB→XYZ 行列を求め、同様に Rec.2020 の RGB→XYZ 行列を求めます。そのうえで
$$
\mathrm{Rec.709\ RGB} \rightarrow XYZ \rightarrow \mathrm{Rec.2020\ RGB}
$$
という形で行列を合成することで、Rec.709 → Rec.2020 の変換行列を得ることができます。
導出の過程を見ると色空間の定義から計算できることが分かりますが、実装としては最終的に 3×3 行列の乗算だけで処理できるため、シェーダなどでも扱いやすい形になっています。
参考文献
- ITU-R BT.709-6, Parameter values for the HDTV standards for production and international programme exchange.
- ITU-R BT.2020-2, Parameter values for ultra-high definition television systems for production and international programme exchange.
- ITU-R BT.2087-0, Colour conversion from Recommendation ITU-R BT.709 to Recommendation ITU-R BT.2020.
【免責事項】
本サイトでの情報を利用することによる損害等に対し、
株式会社ロジカルビートは一切の責任を負いません。