ある表色系(色空間・カラースペース)から別の表色系に変換する式とサンプルなど。

§1 代表的な表色系の種類

RGB
加法混色の表色系、R(赤)、G(緑)、B(青)の三原色の強さによって色を表す
CMY
減法混色の表色系、C(シアン)、M(マゼンタ)、Y(黄)の三原色の濃度によって色を表す
CMYK
黒の発色をよくするためにCMYを拡張してK(Key plate)の濃度を加えた表色系
印刷物などの表色に用いられ、シアン・マゼンタ・黄・黒のインクの濃度を表す
HSV (HSB)
H(hue,色相)、S(saturation,彩度),V(value,明度)の三要素によって色を表す
色相は環状の値で、通常0度から360度で表す
彩度0%が無彩色、彩度100%が純色を表す
HSL (HLS, HSI)
HSV同様、H(hue,色相)、S(saturation,彩度),L(lightness/luminance,輝度)の三要素によって色を表す
HSVと異なり、彩度に関わらず輝度0%が黒、輝度100%が白を表し、50%の場合純色を表す
YCbCr
Y(luma,輝度成分)とCb(blue-difference chroma,青の色差成分)、Cr(red-difference chroma,赤の色差成分)の三要素によって色を表す
動画処理などの映像技術に用いられる

§1.1 表色系の変換スクリプト

表色系
近似色 (カラーネーム)
-
-
カラーコード

#

カラーネーム

RGB

R: G: B:

CMY

C: M: Y:

CMYK

C: M: Y: K:

HSV

H: S: V:

HSL

H: S: L:

使い方
カラーコードもしくは各表色系での値を入力してsetをクリックすると、対応する色と他の表色系での表現を得られます
RGB, CMY, CMYK
それぞれ16進で00~ffの範囲の数値を入力してください
HSV, HSL
S, V, Lは0.0~1.0の範囲の数値を入力してください
Hは0~359の範囲の数値を入力してください (360を超える値は自動的に0~359の範囲に正規化します)
近似色
名前(カラーネーム)が定義されている147色のうち、現在の色に最も近い色を表示します
階調の反転
現在の色をネガポジ反転した色を表示します
補色
現在の色の彩度・明度を維持したまま色相だけを反転した色を表示します
純色
現在の色の彩度・明度を最大(1.0)にした色を表示します
無彩色
現在の色の彩度を最小(0.0)にした色を表示します

§2 変換式

§2.1 RGB⇄CMY

R, G, B, C, M, Yの値域が0〜255(8ビット)の場合。

C = 255 - R
M = 255 - G
Y = 255 - B

R = 255 - C
G = 255 - M
B = 255 - Y

§2.2 RGB⇄CMYK

R, G, B, C, M, Y, Kの値域が0〜255(8ビット)の場合。

§2.2.1 RGB→CMYK

K = min(255 - R, 255 - G, 255 - B)
C = 255 - R - K
M = 255 - G - K
Y = 255 - B - K

§2.2.2 CMYK→RGB

R' = 255 - C - K
G' = 255 - M - K
B' = 255 - Y - K

R = max(0, R') // R' < 0のときは0、そうでないときはR'
G = max(0, G')
B = max(0, B')

§2.3 RGB⇄HSV

R, G, B, S, Vの値域が0〜255(8ビット)、Hの値域が0〜359の場合。

§2.3.1 RGB→HSV

max = Max(R, G, B)
min = Min(R, G, B)

    max - min
S = ---------
       max

V = max

Rが最大のとき
             G - B
  H = 60 * --------- + 0
           max - min

Gが最大のとき
             B - R
  H = 60 * --------- + 120
           max - min

Bが最大のとき
             R - G
  H = 60 * --------- + 240
           max - min

ここでH < 0のとき
  H += 360

§2.3.2 HSV→RGB

省略。 後述する実装例もしくはHSV色空間 - Wikipediaを参照。

§2.4 RGB⇄YCbCr

§2.4.1 スケーリングされていないYCbCrの場合

(Y ) = (+0.299  +0.587  +0.114) (R )
(Cb) = (-0.299  -0.587  +0.866) (G )
(Cr) = (+0.701  -0.587  -0.114) (B )

(R ) = (+1       0        +1      ) (Y )
(G ) = (+1      -0.19421  -0.50937) (Cb)
(B ) = (+1      +1         0      ) (Cr)

§2.4.2 スケーリングされたYCbCrの場合

R, G, Bの値域が0〜255(8ビット)、Yの値域が16〜235(8ビット)、Cb, Crの値域が16〜240(8ビット、128=色差なし)の場合。

(Y ) = (+0.257  +0.504  +0.098) (R )   ( 16)
(Cb) = (-0.148  -0.291  +0.439) (G ) + (128)
(Cr) = (+0.439  -0.368  -0.071) (B )   (128)

(R ) = (+1.164   0      +1.596) (Y  -  16)
(G ) = (+1.164  -0.391  -0.813) (Cb - 128)
(B ) = (+1.164  +2.018   0    ) (Cr - 128)

§3 実装例

§3.1 .NET FrameworkでのRGB→HSL変換

.NET FrameworkのColor構造体に用意されているメソッドGetHue(), GetSaturation(), GetBrightness()を用いることでRGBからHSLへの変換ができる。 なお、ドキュメントではこれらのメソッドはHSB表色系の値を返すように記述されているが、実際に返される値はHSL表色系になっている模様。

using System;
using System.Drawing;

class Sample {
  static void Main()
  {
    foreach (var col in new[] {
      Color.Red,
      Color.Yellow,
      Color.Lime,
      Color.Cyan,
      Color.Blue,
      Color.Magenta,

      Color.Black,
      Color.Gray,
      Color.White,

      Color.FromArgb(0xff, 0xa0, 0xa0),
      Color.FromArgb(0xff, 0x80, 0x80),
      Color.FromArgb(0xc0, 0x60, 0x60),
      Color.FromArgb(0x80, 0x40, 0x40),
    }) {
      Console.Write("RGB({0:D3}, {1:D3}, {2:D3}) => ", col.R, col.G, col.B);
      Console.WriteLine("HSL({0,6:N2}, {1,7:P2}, {2,7:P2})", col.GetHue(), col.GetSaturation(), col.GetBrightness());
    }
  }
}
実行結果
RGB(255, 000, 000) => HSL(360.00, 100.00%,  50.00%)
RGB(255, 255, 000) => HSL( 60.00, 100.00%,  50.00%)
RGB(000, 255, 000) => HSL(120.00, 100.00%,  50.00%)
RGB(000, 255, 255) => HSL(180.00, 100.00%,  50.00%)
RGB(000, 000, 255) => HSL(240.00, 100.00%,  50.00%)
RGB(255, 000, 255) => HSL(300.00, 100.00%,  50.00%)
RGB(000, 000, 000) => HSL(  0.00,   0.00%,   0.00%)
RGB(128, 128, 128) => HSL(  0.00,   0.00%,  50.20%)
RGB(255, 255, 255) => HSL(  0.00,   0.00%, 100.00%)
RGB(255, 160, 160) => HSL(360.00, 100.00%,  81.37%)
RGB(255, 128, 128) => HSL(360.00, 100.00%,  75.10%)
RGB(192, 096, 096) => HSL(360.00,  43.24%,  56.47%)
RGB(128, 064, 064) => HSL(360.00,  33.33%,  37.65%)

§3.2 VB.NETでのRGB, CMYK, HSV相互変換の実装例

§3.2.1 構造体宣言

それぞれのカラースペースでの色データを表す構造体を作成。

RGB
''' <summary>
''' RGB
''' </summary>
<StructLayout(LayoutKind.Explicit)> _
Public Structure Rgb

    Public Const IntensityMax As Byte = 255
    Public Const IntensityMin As Byte = 0

    Public Shared ReadOnly White As RGB
    Public Shared ReadOnly Black As RGB

    Shared Sub New()

        White = New RGB(IntensityMax, IntensityMax, IntensityMax)
        Black = New RGB(IntensityMin, IntensityMin, IntensityMin)

    End Sub

    <FieldOffset(0)> Public B As Byte
    <FieldOffset(1)> Public G As Byte
    <FieldOffset(2)> Public R As Byte

    Public ReadOnly Property RGB() As Integer
        Get
            Return CInt(R) * &H10000 + CInt(G) * &H100 + CInt(B)
        End Get
    End Property

    Public ReadOnly Property IsBlack() As Boolean
        Get
            Return (Me.R = IntensityMin AndAlso Me.G = IntensityMin AndAlso Me.B = IntensityMin)
        End Get
    End Property

    Public ReadOnly Property IsWhite() As Boolean
        Get
            Return (Me.R = IntensityMax AndAlso Me.G = IntensityMax AndAlso Me.B = IntensityMax)
        End Get
    End Property

    Public ReadOnly Property L() As Byte
        Get
            Return CByte(0.299F * R + 0.587F * G + 0.114F * B)
        End Get
    End Property

    Public Overloads Function Equals(ByVal rgb As RGB) As Boolean

        Return (rgb.R = Me.R AndAlso rgb.G = Me.G AndAlso rgb.B = Me.B)

    End Function

    Public Sub SetRGB(ByVal value As Integer)

        R = CByte(value And &HFF0000 \ &H10000)
        G = CByte(value And &HFF00 \ &H100)
        B = CByte(value And &HFF)

    End Sub

    Public Function ToInt32() As Int32

        Return R * &H10000 Or G * &H100 Or B

    End Function

    Public Function ToColor() As System.Drawing.Color

        Return System.Drawing.Color.FromArgb(R, G, B)

    End Function

    Private Sub New(ByVal r As Byte, ByVal g As Byte, ByVal b As Byte)

        Me.R = r
        Me.G = g
        Me.B = b

    End Sub

End Structure
CMYK
''' <summary>
''' CMYK
''' </summary>
<StructLayout(LayoutKind.Explicit)> _
Public Structure Cmyk

    Public Shared ReadOnly White As Cmyk
    Public Shared ReadOnly Black As Cmyk

    Public Const DensityMin As Byte = 0
    Public Const DensityMax As Byte = 255

    Shared Sub New()

        White = New Cmyk(0, 0, 0, DensityMin)
        Black = New Cmyk(0, 0, 0, DensityMax)

    End Sub

    <FieldOffset(0)> Public C As Byte
    <FieldOffset(1)> Public M As Byte
    <FieldOffset(2)> Public Y As Byte
    <FieldOffset(3)> Public K As Byte

    Public Overloads Function Equals(ByVal cmyk As Cmyk) As Boolean

        Return (cmyk.C = Me.C AndAlso cmyk.M = Me.M AndAlso cmyk.Y = Me.Y AndAlso cmyk.K = Me.K)

    End Function

    Private Sub New(ByVal c As Byte, ByVal m As Byte, ByVal y As Byte, ByVal k As Byte)

        Me.C = c
        Me.M = m
        Me.Y = y
        Me.K = k

    End Sub

End Structure
HSV
''' <summary>
''' HSV
''' </summary>
<StructLayout(LayoutKind.Explicit)> _
Public Structure Hsv

    Public Shared ReadOnly White As Hsv
    Public Shared ReadOnly Black As Hsv

    Public Const HueMin As Short = 0
    Public Const HueMax As Short = 359

    Public Const SaturationMin As Byte = 0
    Public Const SaturationMax As Byte = 255

    Public Const ValueMin As Byte = 0
    Public Const ValueMax As Byte = 255

    Shared Sub New()

        White = New Hsv(0, 0, ValueMax)
        Black = New Hsv(0, 0, ValueMin)

    End Sub

    <FieldOffset(0)> Public H As Short
    <FieldOffset(2)> Public S As Byte
    <FieldOffset(3)> Public V As Byte

    Public Overloads Function Equals(ByVal hsv As Hsv) As Boolean

        Return (hsv.H = Me.H AndAlso hsv.S = Me.S AndAlso hsv.V = Me.V)

    End Function

    Private Sub New(ByVal h As Short, ByVal s As Byte, ByVal v As Byte)

        Me.H = h
        Me.S = s
        Me.V = v

    End Sub

End Structure

§3.2.2 ColorConverter

変換メソッドとその他のユーティリティメソッドをもったクラスを作成。

''' <summary>
''' 色空間の変換
''' </summary>
Public Class ColorConverter

    ''' <summary>
    ''' 三つの要素の内、もっとも大きいものを取得する。
    ''' </summary>
    Private Shared Function GetGreatestValue(ByVal x As Byte, ByVal y As Byte, ByVal z As Byte) As Byte

        If x < y Then

            If y < z Then

                Return z

            Else

                Return y

            End If

        ElseIf x < z Then

            If z < y Then

                Return y

            Else

                Return z

            End If

        Else

            Return x

        End If

    End Function

    ''' <summary>
    ''' 三つの要素の内、もっとも小さいものを取得する。
    ''' </summary>
    Private Shared Function GetSmallestValue(ByVal x As Byte, ByVal y As Byte, ByVal z As Byte) As Byte

        If y < x Then

            If z < y Then

                Return z

            Else

                Return y

            End If

        ElseIf z < x Then

            If y < z Then

                Return y

            Else

                Return z

            End If

        Else

            Return x

        End If

    End Function

    ''' <summary>
    ''' HSVからRGBへの変換
    ''' </summary>
    Public Shared Function ToRgb(ByVal hsv As Hsv) As Rgb

        Dim rgb As New rgb()

        If hsv.S = 0 Then

            rgb.R = hsv.V
            rgb.G = hsv.V
            rgb.B = hsv.V

        Else

            Const hueMax As Single = CSng(hsv.HueMax)
            Const saturationMax As Single = CSng(hsv.SaturationMax)

            Dim ht As Integer = hsv.H * 6
            Dim d As Single = CSng(ht Mod hsv.HueMax)
            Dim t1 As Byte = CByte(hsv.V * (saturationMax - hsv.S) / saturationMax)
            Dim t2 As Byte = CByte(hsv.V * (saturationMax - hsv.S * d / hueMax) / saturationMax)
            Dim t3 As Byte = CByte(hsv.V * (saturationMax - hsv.S * (hueMax - d) / hueMax) / saturationMax)

            Select Case ht \ hsv.HueMax

                Case 0
                    rgb.R = hsv.V : rgb.G = t3 : rgb.B = t1

                Case 1
                    rgb.R = t2 : rgb.G = hsv.V : rgb.B = t1

                Case 2
                    rgb.R = t1 : rgb.G = hsv.V : rgb.B = t3

                Case 3
                    rgb.R = t1 : rgb.G = t2 : rgb.B = hsv.V

                Case 4
                    rgb.R = t3 : rgb.G = t1 : rgb.B = hsv.V

                Case Else
                    rgb.R = hsv.V : rgb.G = t1 : rgb.B = t2

            End Select

        End If

        Return rgb

    End Function

    ''' <summary>
    ''' CMYKからRGBへの変換
    ''' </summary>
    Public Shared Function ToRgb(ByVal cmyk As Cmyk) As Rgb

        Dim rgb As New rgb()

        Dim r As Integer = cmyk.DensityMax - (cmyk.C + cmyk.K)
        Dim g As Integer = cmyk.DensityMax - (cmyk.M + cmyk.K)
        Dim b As Integer = cmyk.DensityMax - (cmyk.Y + cmyk.K)

        If r < 0 Then rgb.R = 0 Else rgb.R = CByte(r)
        If g < 0 Then rgb.G = 0 Else rgb.G = CByte(g)
        If b < 0 Then rgb.B = 0 Else rgb.B = CByte(b)

        Return rgb

    End Function

    ''' <summary>
    ''' RGBからHSVへの変換
    ''' </summary>
    Public Shared Function ToHsv(ByVal rgb As Rgb) As Hsv

        Dim hsv As New Hsv()

        Dim max As Short = GetGreatestValue(rgb.R, rgb.G, rgb.B)
        Dim min As Short = GetSmallestValue(rgb.R, rgb.G, rgb.B)

        Dim d As Single = CSng(max - min)

        hsv.V = CByte(max)

        If d = 0.0 Then

            hsv.S = 0

        Else

            hsv.S = CByte(d * 255.0F / CSng(max))

        End If

        If hsv.S = 0 Then

            hsv.H = 0

        Else

            Dim rt As Short = max - CShort(rgb.R * 60.0F / d)
            Dim gt As Short = max - CShort(rgb.G * 60.0F / d)
            Dim bt As Short = max - CShort(rgb.B * 60.0F / d)

            If rgb.R = max Then

                hsv.H = bt - gt

            ElseIf rgb.G = max Then

                hsv.H = 120S + rt - bt

            Else

                hsv.H = 240S + gt - rt

            End If

            If hsv.H < 0 Then hsv.H += 360S

        End If

        Return hsv

    End Function

    ''' <summary>
    ''' CMYKからHSVへの変換
    ''' </summary>
    Public Shared Function ToHsv(ByVal cmyk As Cmyk) As Hsv

        Return ToHsv(ToRgb(cmyk))

    End Function

    ''' <summary>
    ''' RGBからCMYKへの変換
    ''' </summary>
    Public Shared Function ToCmyk(ByVal rgb As Rgb) As Cmyk

        Dim cmyk As New cmyk()

        cmyk.K = GetSmallestValue(cmyk.DensityMax - rgb.R, cmyk.DensityMax - rgb.G, cmyk.DensityMax - rgb.B)
        cmyk.C = cmyk.DensityMax - rgb.R - cmyk.K
        cmyk.M = cmyk.DensityMax - rgb.G - cmyk.K
        cmyk.Y = cmyk.DensityMax - rgb.B - cmyk.K

        Return cmyk

    End Function

    ''' <summary>
    ''' HSVからCMYKへの変換
    ''' </summary>
    Public Shared Function ToCmyk(ByVal hsv As Hsv) As Cmyk

        Return ToCmyk(ToRgb(hsv))

    End Function

End Class

§3.3 C#でのYCbCr→RGB変換の実装例

この例でyuvはYUV422フォーマット(Y0CbY1Crの順)で格納されたピクセルへのbyte*型ポインタ、bgrはBGRの順で格納されるピクセルへのbyte*型ポインタを表す。

var y0 = +1.164f * (*(yuv++) -  16);
var cb =           (*(yuv++) - 128);
var y1 = +1.164f * (*(yuv++) -  16);
var cr =           (*(yuv++) - 128);

var db = (+2.018f * cb               );
var dg = (-0.391f * cb + -0.813f * cr);
var dr = (               +1.596f * cr);

*(bgr++) = (byte)(y0 + db);
*(bgr++) = (byte)(y0 + dg);
*(bgr++) = (byte)(y0 + dr);

*(bgr++) = (byte)(y1 + db);
*(bgr++) = (byte)(y1 + dg);
*(bgr++) = (byte)(y1 + dr);