RGB色空間からHSI色空間に変換する

注意:
この文書は以前「.NETでいきまっしょい!」で公開していたものですが、公開以降メンテナンスされていません。 今や古い情報となった内容が記載されている場合があるのでご注意ください。

 System.Drawing名前空間のColor構造体はRGB色空間で色を扱う。 HSI色空間を利用する場合は数式によってRGBに変換する必要がある。 次のクラスはRGBとHSIを相互に変換するメソッドを含むクラスである。 ちなみに、明度IntensityはValue、HSIはHSVとも呼ばれる。
VB.NET
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
Option Strict On

Imports System
Imports System.Drawing

Public Class ColorSpace

    '--------------------------------------------------------------------------------
    ' 名前: HSIToRGB()
    ' 概要: 色空間をHSIからRGBへ変換する
    '       色相(Hue)、彩度(Saturation)、明度(Intensity)
    '--------------------------------------------------------------------------------
    Public Shared Sub HSIToRGB(ByVal h As Integer, ByVal s As Integer, ByVal i As Integer, ByRef r As Integer, ByRef g As Integer, ByRef b As Integer)

        If 0 > h AndAlso h > 359 Then Throw New ArgumentOutOfRangeException("h", "色相Hは0〜359の範囲でなければなりません。")
        If 0 > s AndAlso s > 255 Then Throw New ArgumentOutOfRangeException("s", "彩度Sは0〜255の範囲でなければなりません。")
        If 0 > i AndAlso i > 255 Then Throw New ArgumentOutOfRangeException("i", "明度Iは0〜255の範囲でなければなりません。")

        If s = 0 Then

            r = i
            g = i
            b = i

        Else

            Dim ht As Integer = h * 6
            Dim d As Double = CDbl(ht Mod 360)
            Dim t1 As Integer = CInt(i * (255.0 - s) / 255.0)
            Dim t2 As Integer = CInt(i * (255.0 - s * d / 360.0) / 255.0)
            Dim t3 As Integer = CInt(i * (255.0 - s * (360.0 - d) / 360.0) / 255.0)

            Select Case ht \ 360
                Case 0
                    r = i : g = t3 : b = t1
                Case 1
                    r = t2 : g = i : b = t1
                Case 2
                    r = t1 : g = i : b = t3
                Case 3
                    r = t1 : g = t2 : b = i
                Case 4
                    r = t3 : g = t1 : b = i
                Case Else
                    r = i : g = t1 : b = t2
            End Select

        End If

    End Sub

    Public Shared Function HSIToRGB(ByVal h As Integer, ByVal s As Integer, ByVal i As Integer) As Color

        Dim r, g, b As Integer

        HSIToRGB(h, s, i, r, g, b)

        Return Color.FromArgb(r, g, b)

    End Function

    '--------------------------------------------------------------------------------
    ' 名前: RGBToHSI()
    ' 概要: 色空間をRGBからHSIへ変換する
    '       色相(Hue)、彩度(Saturation)、明度(Intensity)
    '--------------------------------------------------------------------------------
    Public Shared Sub RGBToHSI(ByVal r As Integer, ByVal g As Integer, ByVal b As Integer, ByVal h As Integer, ByVal s As Integer, ByVal i As Integer)

        If 0 > r AndAlso r > 255 Then Throw New ArgumentOutOfRangeException("r", "赤Rは0〜255の範囲でなければなりません。")
        If 0 > g AndAlso g > 255 Then Throw New ArgumentOutOfRangeException("g", "緑Gは0〜255の範囲でなければなりません。")
        If 0 > b AndAlso b > 255 Then Throw New ArgumentOutOfRangeException("b", "青Bは0〜255の範囲でなければなりません。")

        Dim max As Integer = GetGreatestValue(r, g, b)
        Dim min As Integer = GetSmallestValue(r, g, b)

        Dim d As Double = CDbl(max - min)

        i = max

        If d = 0.0 Then

            s = 0

        Else

            s = CInt(d * 255.0 / CDbl(max))

        End If

        If s = 0 Then

            h = 0

        Else

            Dim rt As Integer = max - CInt(r * 60.0 / d)
            Dim gt As Integer = max - CInt(g * 60.0 / d)
            Dim bt As Integer = max - CInt(b * 60.0 / d)

            If r = max Then

                h = bt - gt

            ElseIf g = max Then

                h = 120 + rt - bt

            Else

                h = 240 + gt - rt

            End If

            If h < 0 Then h += 360

        End If

    End Sub

    Public Shared Sub RGBToHSI(ByVal col As Color, ByRef h As Integer, ByRef s As Integer, ByRef i As Integer)

        RGBToHSI(col.R, col.G, col.B, h, s, i)

    End Sub

    '--------------------------------------------------------------------------------
    ' 名前: GetGreatestValue()
    ' 概要: 三つの要素の内、もっとも大きいものを取得する
    '--------------------------------------------------------------------------------
    Private Shared Function GetGreatestValue(ByVal x As Integer, ByVal y As Integer, ByVal z As Integer) As Integer

        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

    '--------------------------------------------------------------------------------
    ' 名前: GetSmallestValue()
    ' 概要: 三つの要素の内、もっとも小さいものを取得する
    '--------------------------------------------------------------------------------
    Private Shared Function GetSmallestValue(ByVal x As Integer, ByVal y As Integer, ByVal z As Integer) As Integer

        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

End Class
C#
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
using System;
using System.Drawing;

namespace ColorSpace
{
    public class ColorSpace
    {
        //--------------------------------------------------------------------------------
        // 名前: HSIToRGB
        // 概要: 色空間をHSIからRGBへ変換する
        //       色相(Hue)、彩度(Saturation)、明度(Intensity)
        //--------------------------------------------------------------------------------
        public static void HSIToRGB( int h, int s, int i, out int r, out int g, out int b )
        {
            if ( 0 > h && h > 359 ) throw new ArgumentOutOfRangeException( "h", "色相Hは0〜359の範囲でなければなりません。" );
            if ( 0 > s && s > 255 ) throw new ArgumentOutOfRangeException( "s", "彩度Sは0〜255の範囲でなければなりません。" );
            if ( 0 > i && i > 255 ) throw new ArgumentOutOfRangeException( "i", "明度Iは0〜255の範囲でなければなりません。" );
            
            if ( s == 0 )
            {
                r = g = b = i;
            }
            else
            {
                int ht = h * 6;
                double d = (double)( ht % 360 );
                int t1 = (int)( i * ( 255.0d - s ) / 255.0d );
                int t2 = (int)( i * ( 255.0d - s * d / 360.0d ) / 255.0d );
                int t3 = (int)( i * ( 255.0d - s * ( 360.0d - d ) / 360.0d ) / 255.0d );

                switch ( ht / 360 )
                {
                    case 0:
                        r =  i; g = t3; b = t1; break;
                    case 1:
                        r = t2; g =  i; b = t1; break;
                    case 2:
                        r = t1; g =  i; b = t3; break;
                    case 3:
                        r = t1; g = t2; b =  i; break;
                    case 4:
                        r = t3; g = t1; b =  i; break;
                    default:
                        r =  i; g = t1; b = t2; break;
                }
            }
        }

        public static Color HSIToRGB( int h, int s, int i )
        {
            int r, g, b;

            HSIToRGB( h, s, i, out r, out g, out b );

            return Color.FromArgb( r, g, b );
        }

        //--------------------------------------------------------------------------------
        // 名前: RGBToHSI
        // 概要: 色空間をRGBからHSIへ変換する
        //       色相(Hue)、彩度(Saturation)、明度(Intensity)
        //--------------------------------------------------------------------------------
        public static void RGBToHSI( int r, int g, int b, out int h, out int s, out int i )
        {
            if ( 0 > r && r > 255 ) throw new ArgumentOutOfRangeException( "r", "赤Rは0〜255の範囲でなければなりません。" );
            if ( 0 > g && g > 255 ) throw new ArgumentOutOfRangeException( "g", "緑Gは0〜255の範囲でなければなりません。" );
            if ( 0 > b && b > 255 ) throw new ArgumentOutOfRangeException( "b", "青Bは0〜255の範囲でなければなりません。" );

            int max = GetGreatestValue( r, g, b );
            int min = GetSmallestValue( r, g, b );

            double d = (double)( max - min );

            i = max;

            if ( d == 0 )
            {
                s = 0;
            }
            else
            {
                s = (int)( d * 255.0d / (double)max );
            }
            
            if ( s == 0 )
            {
                h = 0;
            }
            else
            {
                int rt = max - (int)( r * 60.0d / d );
                int gt = max - (int)( g * 60.0d / d );
                int bt = max - (int)( b * 60.0d / d );

                if ( r == max )
                {
                    h = bt - gt;
                }
                else if ( g == max )
                {
                    h = 120 + rt - bt;
                }
                else
                {
                    h = 240 + gt - rt;
                }

                if ( h < 0 ) h += 360;
            }
        }

        public static void RGBToHSI( Color col, out int h, out int s, out int i )
        {
            RGBToHSI( col.R, col.G, col.B, out h, out s, out i );
        }

        //--------------------------------------------------------------------------------
        // 名前: GetGreatestValue
        // 概要: 三つの要素の内、もっとも大きいものを取得する
        //--------------------------------------------------------------------------------
        private static int GetGreatestValue( int x, int y, int z )
        {
            if ( x < y )
            {
                return ( y < z ) ? z : y;
            }
            else if ( x < z )
            {
                return ( z < y ) ? y : z;
            }
            else
            {
                return x;
            }
        }

        //--------------------------------------------------------------------------------
        // 名前: GetSmallestValue
        // 概要: 三つの要素の内、もっとも小さいものを取得する
        //--------------------------------------------------------------------------------
        private static int GetSmallestValue( int x, int y, int z )
        {
            if ( y < x )
            {
                return ( z < y ) ? z : y;
            }
            else if ( z < x )
            {
                return ( y < z ) ? y : z;
            }
            else
            {
                return x;
            }
        }
    }
}
使用例(VB.NET)
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
Public Class Form1
    Inherits System.Windows.Forms.Form

#Region " Windows フォーム デザイナで生成されたコード "

    Public Sub New()
        MyBase.New()

        ' この呼び出しは Windows フォーム デザイナで必要です。
        InitializeComponent()

        ' InitializeComponent() 呼び出しの後に初期化を追加します。

    End Sub

    ' Form は dispose をオーバーライドしてコンポーネント一覧を消去します。
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    ' Windows フォーム デザイナで必要です。
    Private components As System.ComponentModel.IContainer

    ' メモ : 以下のプロシージャは、Windows フォーム デザイナで必要です。
    ' Windows フォーム デザイナを使って変更してください。  
    ' コード エディタは使用しないでください。
    Friend WithEvents PictureBox1 As System.Windows.Forms.PictureBox
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.PictureBox1 = New System.Windows.Forms.PictureBox()
        Me.SuspendLayout()
        '
        'PictureBox1
        '
        Me.PictureBox1.Location = New System.Drawing.Point(8, 8)
        Me.PictureBox1.Name = "PictureBox1"
        Me.PictureBox1.Size = New System.Drawing.Size(360, 255)
        Me.PictureBox1.TabIndex = 0
        Me.PictureBox1.TabStop = False
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 12)
        Me.ClientSize = New System.Drawing.Size(376, 270)
        Me.Controls.AddRange(New System.Windows.Forms.Control() {Me.PictureBox1})
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.ResumeLayout(False)

    End Sub

#End Region

    Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint

        Dim bmp As New Bitmap(360, 256)
        Dim x As Integer
        Dim y As Integer

        For x = 0 To 360 - 1

            For y = 0 To 256 - 1

                ' xを色相、yを彩度として描画
                bmp.SetPixel(x, y, ColorSpace.HSIToRGB(x, y, 255))

            Next y

        Next x

        e.Graphics.DrawImage(bmp, 0, 0)

        bmp.Dispose()

    End Sub

End Class
実行結果
実行結果