🎨

色空間と変換についてのメモ

に公開

この記事は 株式会社ガラパゴス(有志) Advent Calendar 2025 の20日目の記事です。

前書き

こんにちは。@samechaaです。
しばらくぶりに画像処理をやろうとしたら色空間の変換方法を全く覚えていなかったので、覚え書きとして書き残しておきます。

色空間

色空間とは色を数値の組み合わせで表現するための座標系のようなものです。
立方体(RGB色空間)、円錐(HSV色空間)などで可視化されているのをよく見かけるのではないでしょうか。
エンジニアがよく使うのはRGB空間(画像のデジタルデータ)やYUV色空間またはYCbCr色空間(カメラからの入力や映像データ)、HSV色空間かと思います。

RGB色空間

Red, Green, Blueの3色を組み合わせて色を表現する方法です。
これら3色は光の三原色とも呼ばれ、色を重ねるごとに明るくなり、3つを等量で混ぜ合わせると白色になることから、加法混色(additive mixture)と呼ばれます。

CMYK色空間

印刷物で色を表現するのに用いられる色空間です。
シアン(Cyan), マゼンタ(Magenta), イエロー(Yellow)の3色に加えて、K(Key plate)[1]を加えた4色で表現されます。
これら3色は色料の三原色と呼ばれ、混ぜ合わせるほど暗く黒い色に近づくことから減法混色(subtractive mixture)と呼ばれます。

YUV色空間, YCbCr色空間

YUV色空間、YCbCr色空間は輝度信号Yと2つの色差信号U(Cb), V(Cr)で表現される映像信号用の色空間です。
色差(color difference)とはRGBの各色から輝度成分のYを差し引いた信号のことです。

  • U(Cb):輝度信号と青色成分の差
  • V(Cr):輝度信号と赤色成分の差。

YUV色空間とYCbCr色空間の主な用途は以下の通りです。

色空間 主な用途 信号タイプ
YUV NTSCなどのアナログビデオ信号 アナログ
YCbCr DVDやHD映像などのデジタルビデオ信号 デジタル

なおYUV色空間とYCbCr色空間はよく似ていますが、値域や規格が異なります。デジタル映像を扱う場合はITU-R BT.601やBT.709などの規格に準拠したYCbCrが用いられます。変換時には、準拠する規格によって係数が変わることに注意が必要です。

HSV色空間

色相(Hue)、彩度(saturation)、明度(ValueまたはIntensity)によって色を表現します。

要素 内容
色相(H) 色の種類。円錐の角度で表され、0°~360°の範囲をとります。
彩度(S) 色の鮮やかさ。円錐の中心からの距離で表され、0.0~1.0の範囲をとります。
明度(V) 色の明るさ。円錐の高さで表され、0.0~1.0の範囲をとります。

HSV色空間は、明るさの変動を受けにくく、特定の色を抽出したり、色合いを変えたりするなどの画像処理を直観的に行いやすいという利点があります。

色空間の変換

以下に主な色空間間の変換式をまとめます。
BT.601はアナログTV解像度用です。HD映像を扱う場合は、BT.709が適用されます。

RGB→YUV (ITU-R BT.601準拠)

RGBの値域は0.0~1.0に正規化されているものとし、変換後の値域の幅は1.0とします。

\begin{array}{lrrr} Y = &0.299R &+0.587G &+0.114B \\ U = &-0.147R &-0.289G &+0.436B \\ V = &0.615R &-0.515G &-0.100B \end{array}

YUV→RGB (ITU-R BT.601準拠)

RGBの値域は0.0~1.0に正規化しているものとし、変換後の値域の幅は1.0とします。

\begin{array}{lrrr} R = &1.000Y & &+1.140V \\ G = &1.000Y &-0.395U &-0.581V \\ B = &1.000Y &+2.032U & \end{array}

RGB→YUVの変換時の逆行列ですね。

\begin{bmatrix} R G B \end{bmatrix} = \begin{bmatrix} 0.299 & 0.587 & 0.114 \\ -0.147 & -0.289 & 0.436 \\ 0.615 & -0.515 & 0.100 \end{bmatrix}^{-1} \begin{bmatrix} Y U V \end{bmatrix}

RGB→YCbCr (ITU-R BT.601準拠, 8bit デジタル Limited Range)

RGBの値域は0~255になっているものとします。

\begin{array}{lrrrr} Y = &0.257R &+0.504G &+0.098B &+16 \\ Cb = &-0.148R &-0.291G &+0.439B &+128 \\ Cr = &0.439R &-0.368G &-0.071B &+128 \end{array}

YCbCr→RGB (ITU-R BT.601準拠, 8bit デジタル Limited Range)

RGBの値域は0~255になっているものとします。

\begin{array}{lrrr} R = &1.164(Y-16) & &+1.596 (Cr-128) \\ G = &1.164(Y-16) &-0.391 (Cb-128) &-0.813(Cr-128) \\ B = &1.164(Y-16) &+2.018 (Cb-128) \\ \end{array}

RGB→HSV

RGBの値域は0.0~1.0に正規化されているものとし、MAX=max(R,G,B), MIN=min(R,G,B)とします。

\begin{array}{ll} H = &\begin{cases} 60・\frac {G-B}{MAX-MIN} + 0 &\text{if } MAX=R\land G\geq B \\ 60・\frac {G-B}{MAX-MIN} + 360 &\text{if } MAX=R\land G<B \\ 60・\frac {B-R}{MAX-MIN} + 120 &\text{if } MAX=G \\ 60・\frac {R-G}{MAX-MIN} + 240 &\text{if } MAX=B \\ undefined &\text{if } MAX=MIN \end{cases} \\ \\ S = &\begin{cases} &\frac {MAX-MIN}{MAX} &\text{if } MAX≠0 \\ &0 &\text{if } MAX=0 \end{cases} \\ \\ V = &MAX \end{array}

値域

  • 色相Hは0.0°~360.0°で変化します。(範囲外の値は360で割った余剰でこの範囲に対応できます。)
  • 彩度Sおよび明度Vは0.0~1.0の範囲で変化します。

HSV→RGB

色相Hが0.0°~360.0°、彩度S,明度Vがそれぞれ0.0~1.0の間で変化するものとします。

特殊なケース

  • H=360°のときはH=0°として扱います。
  • S=0.0の場合、最終的な色は無彩色(無色もしくは灰色)となります。このような場合、R=G=B=Vとなります。(この場合Hは無意味となります)。

一般的なケース(S≠0.0)の場合:

\begin{array}{rl} H_i = &\Large \lfloor \frac{H}{60} \rfloor \space \small (mod 6) \\ \\ f = &\Large \frac{H}{60} - \lfloor \frac{H}{60} \rfloor \\ \\ p = &V (1-S) \\ q = &V (1-fS) \\ t = &V (1-(1-f)S) \end{array}

ここで、関数\lfloor X \rfloorは、床関数(X以下の最大の整数)を表します。

\left\{ \begin{array}{llll} H_i = 0のとき & R=V, & G=t, & B=p \\ H_i = 1のとき & R=q, & G=V, & B=p \\ H_i = 2のとき & R=p, & G=V, & B=t \\ H_i = 3のとき & R=p, & G=q, & B=V \\ H_i = 4のとき & R=t, & G=p, & B=V \\ H_i = 5のとき & R=V, & G=p, & B=q \end{array} \right.

YUV,YCbCRの係数はどこから来たのか?

YUVの場合

公式では輝度信号E'_Yは以下の割合で合成されると定義されています。

E'_Y = 0.299E'_R + 0.587E'_G + 0.114E'_B \\

式差(E'_R-E'_Y)および(E'_B-E'_Y)は以下の通りです。

\begin{array}{lrr} (E'_R-E'_Y) = & E'_R-0.299E'_R - 0.587E'_G - 0.114E'_B = & 0.701E'_R - 0.587E'_G - 0.114E'_B\\ (E'_B-E'_Y) = & E'_B-0.299E'_R - 0.587E'_G - 0.114E'_B = & -0.299E'_R - 0.587E'_G + 0.886E'_B \end{array}



ただし、色が全くないとき(白やグレー)、色差信号を0にするというルールがあります。
これらを表に表したものが公式の[2.5.1 - TABLE 1 Normalized signal values]です。

Condition E'_R E'_g E'_B E'_Y E'_R-E'_Y E'_B-E'_Y
White
Black
1.0
0
1.0
0
1.0
0
1.0
0
0
0
0
0
Red
Green
Blue
1.0
0
0
0
1.0
0
0
0
1.0
0.299
0.587
0.114
–0.701
–0.587
–0.114
–0.299
–0.587
0.886

上記を見て分かるように単純にB-YR-Yを使うと、値の範囲がバラバラになってしまいます。
例えば青の成分が最大(R=0,G=0,B=1)の時、

  • Y = 0.114
  • B - Y = 1.0 - 0.114 = 0.886

であるため、青が最小の場合B-Y=0-0.114=-0.886となり、B-Yの範囲は\pm 0.886になります。R-Yも同様で範囲は\pm 0.701となります。
このままだとデータの扱いが不便なため、すべての色が最大,最小になったとき、値が\pm 0.5(または特定のビット幅)に収まるようにスケーリングします。スケーリング用の係数K_uおよびK_vは以下の式で求められます。

Uの場合:

0.886 × k_u = 0.5 \\ k_u = \frac{0.5}{0.886} \approx 0.5643...

Vの場合:

0.701 × k_v = 0.5 \\ k_v = \frac{0.5}{0.701} \approx 0.7132...



これらのスケーリング関数をYの式(0.299R+0.587G+0.114B)に代入すると、

\begin{array}{lrrr} U = &-0.147R &-0.289G &+0.436B \\ V = &0.615R &-0.515G &-0.100B \end{array}

になります。これでRGB→YUV (ITU-R BT.601準拠)に記載した変換式の係数がどうやって決まっているかがわかりました。

YCbCrの場合

YCbCrでも輝度および色差の考え方は基本的に同じです。ではなぜYUVと係数が異なるかというと、YCbCrはLimited Rangeという制限された範囲を使用するためです。
Yは16~235, CbおよびCrは16~240の範囲であるため、フルレンジ(0~255)であるRGB値は制限範囲内に収めるためのスケーリング処理を行います。
ちなみに0~15の値をfootroom, 236~255の値をheadroomと呼びます。

輝度の係数

輝度Yの有効範囲は16~235の219段階です。RGBは255段階なので、スケーリングするための係数は219 / 256 \approx 0.8554...となります。
この係数を前述の輝度Yの基本式の係数にかけると、YCbCrにおける輝度YY = 0.257R + 0.504G + 0.098Bが算出できます。

色差の係数

色差Cb,Crの有効範囲は16~240の224段階です。

  1. 基本式で輝度Yを算出する
  2. 1で算出した輝度とR,Bの差を計算します。((B - Y),(R - Y))
  3. 2の最大値を、有効範囲(16〜240の224段階)に収まるようにスケーリング係数を掛け、色差の係数を算出します。

オフセット

16や128といった値はデジタル化(今回は8bit)のためにオフセットとして使用しています。
輝度Yは整数値しかとらないため、制限範囲の下限分+16すればOKです。
色差(B - Y),(R - Y)は正負両方の値をとります。デジタル処理上負数の扱いが面倒なため、中心値を足すことで16~240の正の整数の範囲内に押し込めます。中心値は224(段階) / 2 + 16(footroom)で128となります。

まとめ

備忘録として変換式を書き記しましたが、多くのプログラミング言語やフレームワークで変換用の関数が用意されています。
次回は、Swiftにおけるこれらの変換方法やユースケースについて紹介したいと思います。

参考

脚注
  1. 印刷において黒の板(キープレート)が重要であることに由来します。 ↩︎

株式会社ガラパゴス(有志)

Discussion