F-2 HSV

RGB (赤緑青) という色体系は、確かに人間の視神経に基づいた色体系ですが、実はあまり使いやすくありません。例えば、「(R=211, G=141, B=0) という色と同じ明るさの青紫」を作ろうとしても、大変な作業になります。

このような場合は、色相 (H), 彩度 (S), 明度 (V) の3つで色を表す HSV 色体系 (HSI とも呼ばれる) を用いると便利です。

色相 (hue) 0〜360 の値をとり、0 で赤、120 で緑、240 で青、360 でまた赤とする。
彩度 (saturation) 0〜1 の値をとり、0 で灰色 (白から黒までの彩りない色)、1 で鮮やかな色とする。
明度 (value 又は intensity) 0〜1 の値をとり、0 で黒、1 で白とする。

【練習問題】

RGB の値を入れて「RGB から HSV を計算」ボタンを押すと
HSV それぞれの値が求まり、
逆に HSV の値を入れて「HSV から RGB を計算」ボタンを押すと
RGB それぞれの値が求まる、というプログラムを作ります。

まずは、次のようにフォームにコンポーネントを追加して下さい。

コンポーネント Name プロパティ
「RGB から HSV を計算」ボタン ButtonRGBtoHSV
「色相」エディット EditH
「彩度」エディット EditS
「明度」エディット EditV
「HSV から RGB を計算」ボタン ButtonHSVtoRGB

それぞれのボタンのイベントハンドラの中身は、かなり複雑になるのでここでは説明しません。

 処理内容の詳細 (アルゴリズム) は少し専門的になるので、ブラックボックスとしておいても構いません。ただし、後の節でここで作成したプログラム(ユニット)を用いるので、少なくとも、「RGB と HSV との間の変換がこのプログラムでなされているのだ。」ということは理解しておいてください。

「RGB から HSV を計算」ボタンのイベントハンドラは次のようにして下さい。

// 「RGB から HSV を計算」ボタン
procedure TFormCustomColor.ButtonRGBtoHSVClick(Sender: TObject);
var
  h: Real; // 色相 hue
  s: Real; // 彩度 saturation
  v: Real; // 明度 value
  min: Integer;
  max: Integer;
  delta: Integer;
begin
  if (SpinEditR.Value > SpinEditG.Value)
    then
      begin
        if (SpinEditR.Value > SpinEditB.Value)
          then
            begin
              max := SpinEditR.Value;
            end
          else
            begin
              max := SpinEditB.Value;
            end
        ;
        if (SpinEditG.Value < SpinEditB.Value)
          then
            begin
              min := SpinEditG.Value;
            end
          else
            begin
              min := SpinEditB.Value;
            end
        ;
      end
    else
      begin
        if (SpinEditG.Value > SpinEditB.Value)
          then
            begin
              max := SpinEditG.Value;
            end
          else
            begin
              max := SpinEditB.Value;
            end
        ;
        if (SpinEditR.Value < SpinEditB.Value)
          then
            begin
              min := SpinEditR.Value;
            end
          else
            begin
              min := SpinEditB.Value;
            end
        ;
      end
  ;
  v := max;
  if (max <> 0)
    then
      begin
        s := (max - min + 0.0) / max;
      end
    else
      begin
        s := 0;
      end
  ;
  if (s = 0)
    then
      begin
        h := 0;
      end
    else
      begin
        h := 0;
        delta := max - min;
        if (SpinEditR.Value = max)
          then
            begin
              h := (SpinEditG.Value - SpinEditB.Value + 0.0) / delta;
            end
          else
            begin
              if (SpinEditG.Value = max)
                then
                  begin
                    h := 2 + (SpinEditB.Value - SpinEditR.Value + 0.0) / delta;
                  end
                else
                  begin
                    if (SpinEditB.Value = max)
                      then
                        begin
                          h := 4 + (SpinEditR.Value - SpinEditG.Value) / delta;
                        end
                    ;
                  end
              ;
            end
        ;
        h := h * 60;
        if (h < 0)
          then
            begin
              h := h + 360;
            end
        ;
      end
  ;
  EditH.Text := FloatToStr(h);
  EditS.Text := FloatToStr(s);
  EditV.Text := FloatToStr(v / 255);
end;

「HSV から RGB を計算」ボタンのイベントハンドラは次のようにして下さい。

// 「HSV から RGB を計算」ボタン
procedure TFormCustomColor.ButtonHSVtoRGBClick(Sender: TObject);
var
  h: Real; // 色相 hue
  s: Real; // 彩度 saturation
  v: Real; // 明度 value
  f: Real;
  p: Real;
  q: Real;
  t: Real;
begin
  h := StrToFloat(EditH.Text);
  s := StrToFloat(EditS.Text);
  v := StrToFloat(EditV.Text);
  if (s = 0)
    then
      begin
        SpinEditR.Value := Trunc(v * 255);
        SpinEditG.Value := Trunc(v * 255);
        SpinEditB.Value := Trunc(v * 255);
      end
    else
      begin
        if (h = 360)
          then
            begin
              h := 0;
            end
        ;
        h := h / 60;
        f := h - Int(h);
        p := v * (1 - s);
        q := v * (1 - (s * f));
        t := v * (1 - (s * (1 - f)));
        Case (Trunc(h)) of
          0:
            begin
              SpinEditR.Value := Trunc(v * 255);
              SpinEditG.Value := Trunc(t * 255);
              SpinEditB.Value := Trunc(p * 255);
            end;
          1:
            begin
              SpinEditR.Value := Trunc(q * 255);
              SpinEditG.Value := Trunc(v * 255);
              SpinEditB.Value := Trunc(p * 255);
            end;
          2:
            begin
              SpinEditR.Value := Trunc(p * 255);
              SpinEditG.Value := Trunc(v * 255);
              SpinEditB.Value := Trunc(t * 255);
            end;
          3:
            begin
              SpinEditR.Value := Trunc(p * 255);
              SpinEditG.Value := Trunc(q * 255);
              SpinEditB.Value := Trunc(v * 255);
            end;
          4:
            begin
              SpinEditR.Value := Trunc(t * 255);
              SpinEditG.Value := Trunc(p * 255);
              SpinEditB.Value := Trunc(v * 255);
            end;
          5:
            begin
              SpinEditR.Value := Trunc(v * 255);
              SpinEditG.Value := Trunc(p * 255);
              SpinEditB.Value := Trunc(q * 255);
            end;
        end;
      end
  ;
end;

 前節と同じく、このプログラム (ユニット) は customcolor.pas という名前で保存しておいてください。

正しく動くかどうか、確かめましょう。

  1. R=211, G=141, B=0 と入力し、「RGB から HSV を計算」ボタンを押します。
  2. H=40.0947867298578, S=1, V=0.827450980392157 と表示されたら、正しく計算されています。
  3. 逆に、この HSV と同じ明るさの青紫を求めます。青紫の色相は 275 くらいなので、色相の欄に 275 と入力し、「HSV から RGB を計算」ボタンを押します。
  4. R=123, G=0, B=211 と表示されたら、正しく計算されています。

このプログラムの出典

RGB と HSV を相互変換する上記のイベントハンドラは、GIMP (1.2.0) というプログラムの一部を Delphi 向けに改変したものです。GIMPGPL というライセンスに従って配布されており、そのため GIMP を改変したプログラムも GPL に従わなくてはなりません。

【基礎課題 F-2】

「RGB から HSV を計算」ボタンを押しても「HSV から RGB を計算」ボタンを押しても、左上のパネルに色が表示される、というようにプログラムに手を加えて下さい。

ここまでのプログラムをダウンロード(D)

【応用課題 F-2】

【応用課題 F-1】と同様に、スクロールバーによって HSV も調整出来るようにプログラムを改良して下さい。