備忘録2




代表的な表色系の種類

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,赤の色差成分)の三要素によって色を表す
動画処理などの映像技術に用いられる

変換式

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

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

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

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')

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

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

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

RGB⇄YCbCr
スケーリングされていない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)

スケーリングされた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)

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

Imports System
Imports System.Drawing

Class Sample
 Public Shared Sub Main()
   For Each col As Color In New Color() { _
     Color.Red, _
     Color.Yellow, _
     Color.Lime, _
     Color.Cyan, _
     Color.Blue, _
     Color.Magenta, _
     Color.Black, _
     Color.Gray, _
     Color.White, _
     Color.FromArgb(&hFF, &hA0, &hA0), _
     Color.FromArgb(&hFF, &h80, &h80), _
     Color.FromArgb(&hC0, &h60, &h60), _
     Color.FromArgb(&h80, &h40, &h40) _
   }
     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())
   Next
 End Sub
End Class

実行結果
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%)


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

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

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


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

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);




最終更新:2013年03月23日 16:23
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。