カラーコントロール (RGB HSL)

 色コントロールプログラムしとして、RGB YSH変換 RGB HSV変換については、それぞれ、カラーコントロール カラーコントロール(RGB HSV)で紹介していますが、ここでは、Windows 標準のRGB HSLについて取り上げています。

RGB HSL 変換は、Delphi XE3 以降組み込まれているので、特に変換プログラムを組む必要はありません。

RGBはTAlphaColor   色相 0~360°が 0~1  彩度 0~1 明度0~1 となります。

procedure RGBtoHSL(RGB: TAlphaColor; out H, S, L: Single);

TAlphaColorをセットして、呼び出すとH(色相) S(彩度)  L(明度)の値が計算されます。

function HSLtoRGB(H, S, L: Single): TAlphaColor;

H(色相) S(彩度)  L(明度)の値をセットして呼び出すと、TAlphaColorが返されます。

TAlphaColor をVCLで使用する場合は、TColorに変換します。
TColorは、Integer TAlphaColor は、Cardinalで、一番上のバイトは透明度の値で、 TColorでは、システムカラーで、フラグのような役割をしているので、TAlphaColorの一番上のバイトをゼロにします。

TColor := TAlphaColor and $00FFFFFF;

RGBtoHSL を使用する場合の Tcolor から TAlphaColor への変更は、必要ありません。

HSLの場合、明度Lに特徴があり、明度0.5 が彩度としては一番大きくなり、明度をゼロに近づけると、黒色になり、1に近づけると、白色になります。

次の画像サンプルは、彩度(S)、L(明度)に係数を乗じて変換しています。色相は、元の値に加算をしています。
画像サンプルの明度1は、元の明度に掛ける係数で、1の場合は、元画像の明度値のまゝとなります。

RGB HSLサンプル
YSH、HSV、HSL変換によって、微妙な色合いの差が出ますが、単独ではわかりません。
どの変換方式を使用するかは、好みによるでしょう。

サンプルプログラム

unit Main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, system.Math, Vcl.ExtDlgs, Vcl.ExtCtrls, System.UIConsts,
  Vcl.StdCtrls, System.UITypes, Vcl.Imaging.GIFImg;

type
  TForm1 = class(TForm)
    FileOpenBtn: TButton;
    ScrollBox1: TScrollBox;
    ScrollBox2: TScrollBox;
    Image1: TImage;
    Image2: TImage;
    OpenPictureDialog1: TOpenPictureDialog;
    RGBtoHSLbtn: TButton;
    RadioGroup1: TRadioGroup;
    SavePictureDialog1: TSavePictureDialog;
    FileSaveBtn: TButton;
    LabeledEdit1: TLabeledEdit;
    LabeledEdit2: TLabeledEdit;
    LabeledEdit3: TLabeledEdit;
    ColorControlBtn: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FileOpenBtnClick(Sender: TObject);
    procedure RGBtoHSLbtnClick(Sender: TObject);
    procedure FileSaveBtnClick(Sender: TObject);
    procedure ColorControlBtnClick(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

type
  TAlphaarry = array[0..0] of TAlphaColor;    // TAlphaColor配列
  PAlphaarray = ^TAlphaarry;                  // 配列のポインター

const
// ファイル拡張子設定
  OpenFileFilter =
    '画像ファイル|*.png;*.jpg;*.gif;*.bmp;*.tif;*.ico;*.wdp'+
    '|*.png|*.png' +
    '|*.jpg|*.jpg' +
    '|*.gif|*.gif' +
    '|*.bmp|*.bmp' +
    '|*.tif|*.tif' +
    '|*.ico|*.ico' +
    '|*.wdp|*.wdp';

  SaveFileFilter =
    '画像ファイル|*.png;*.jpg;*.gif;*.bmp;*.tif;*.wdp' +
    '|*.png|*.png' +
    '|*.jpg|*.jpg' +
    '|*.gif|*.gif' +
    '|*.bmp|*.bmp' +
    '|*.tif|*.tif' +
    '|*.wdp|*.wdp';

var
  InBitmap        : TBitmap;                    // ビットマップ
  OutBitmap       : TBitmap;
  GHeight, GWidth : integer;                    // ソース画像サイズ

//=================================================================
// RGB から HSL 変換 表示
// H 0~1(0~360)  S -X~X  L 0~1    L の値 0.5が純色 0 は黒 1 は白
//=================================================================
procedure TForm1.RGBtoHSLbtnClick(Sender: TObject);
var
  i, j        : integer;
  D           : Byte;
  hf, Sf, Lf  : single;
  pb          : PRGBQuadArray;                                // Vcl.Imaging.GIFImg
  pbi         : PAlphaarray;
  CAlpha      : TAlphaColor;
begin
  for i := 0 to Gheight - 1 do begin
    pbi := Inbitmap.ScanLine[i];
    pb  := OutBitmap.ScanLine[i];
    D   := 0;
    for j := 0 to GWidth - 1 do begin
      CAlpha := pbi[j];                                       // TAlphaColorの取得
      RGBtoHSL(CAlpha, Hf, Sf, lf);                           // HSL 変換
      case RadioGroup1.ItemIndex of                           // ラジオボタンの位置で表示変更
        0 : D := Round(Hf * 255);                             // 色相
        1 : D := Round(Sf * 255);                             // 彩度
        2 : D := Round(Lf * 255);                             // 明度
      end;
      pb[j].rgbBlue       := D;                               // 三色同じ値をセットしてグレー化
      pb[j].rgbGreen      := D;
      pb[j].rgbRed        := D;
      pb[j].rgbReserved   := 0;                               // フラグなし
    end;
  end;
  image2.Picture.Bitmap := OutBitmap;                         // 画像表示
end;

//======================================================
// ColorConrol
// H S L をそれぞれの係数で変更 R G B に変換して画像表示
//======================================================
procedure TForm1.ColorControlBtnClick(Sender: TObject);
var
  Hue, sat, Lvalue  : Single;
  k                 : integer;
  Hi, sati          : Single;
  Lvaluei           : Single;
  X, Y              : Integer;
  Pb                : PAlphaarray;
  pbi               : PAlphaarray;
begin
  val(LabeledEdit1.Text, Hue, K);
  if K <> 0 then begin
    Application.MessageBox('色相角度の入力値に誤りがあります。','色相',0);
    exit;
  end;
  if abs(hue) > 360 then begin
    Application.MessageBox('色相角度値が大きすぎます。','色相',0);
    exit;
  end;
  val(LabeledEdit2.Text, sat, K);
  if K <> 0 then begin
    Application.MessageBox('彩度Gain係数の入力値に誤りがあります。','彩度',0);
    exit;
  end;
  val(LabeledEdit3.Text, Lvalue, K);
  if K <> 0 then begin
    Application.MessageBox('明度Gain係数の入力値に誤りがあります。','明度',0);
    exit;
  end;
  if Lvalue < 0 then begin
    Application.MessageBox('明度Gain係数はゼロ以下ではいけません。','明度',0);
    exit;
  end;
  for Y := 0 to GHeight - 1 do begin
    pbi := Inbitmap.ScanLine[Y];
    pb  := OutBitmap.ScanLine[Y];
    for X := 0 to GWidth - 1 do begin
      RGBtoHSL(pbi[X], Hi, Sati, LValuei);                // HSL 変換
      Hi := Hi + Hue / 360;                               // 色相の処理
      if Hi < 0   then Hi := Hi + 1;
      if Hi > 1 then Hi := Hi - 1;
      sati := sati * sat;                                 // 彩度の処理
      if sati > 1 then sati := 1;
      Lvaluei := Lvaluei * Lvalue;                        // 明度の処理
      if Lvaluei > 1 then Lvaluei := 1;
      pb[X] := HSLtoRGB(Hi, sati, Lvaluei);               // H S L を R G B に変換
{ ChangeHSLを使用する場合は、変化分だけ与えますが、
  明度に対しては、変化率が大きく注意が必要です。
 HSLtoRGBを使用したほうが良いようです。}
//      pb[X] := ChangeHSL(pb[X], Hue / 360, sat, Lvalue);
    end;
  end;
  image2.Picture.Bitmap := OutBitmap;                         // 画像表示
  FileSaveBtn.Enabled := True;
end;

//========================================
// ファイルの指定オープン
// オープン画像表示
//========================================
procedure TForm1.FileOpenBtnClick(Sender: TObject);
var
  WIC         : TWICImage;
  InFilename  : String;
begin
  OpenPictureDialog1.Filter := OpenFileFilter;                // ファイルオープンフィルターの設定
  if OpenPictureDialog1.Execute then                          // ファイルが指定されたら
    begin
      WIC := TWICImage.Create;                                // TWICImageの生成
      try
        InFilename := OpenPictureDialog1.FileName;            // ファイル名の取得
        WIC.LoadFromFile(InFilename);                         // 画像の読み込み
        GHeight := WIC.Height;                                // 画像高さ取得
        GWidth  := WIC.Width;                                 // 画像幅
        InBitmap.Width    := GWidth;                          // 画像幅
        InBitmap.Height   := GHeight;                         // 画像高さ
        InBitmap.Canvas.Draw(0, 0, WIC);                      // DrawでInBitmapに入力画像設定フォーマット32ビットに変換されます
        OutBitmap.Width   := GWidth;                          // 出力画像幅
        OutBitmap.Height  := GHeight;                         // 出力画像高さ
        image1.Picture.Bitmap := InBitmap;                    // 画像表示
      finally
        WIC.Free;                                             // TWICImage 解放
      end;
    end
    else Exit;
  RGBtoHSLbtn.Enabled := True;                                // ボタンイネーブル
  ColorControlBtn.Enabled := True;
end;

//=============================
// ファイルへ保存
//=============================
procedure TForm1.FileSaveBtnClick(Sender: TObject);
var
  WIC     : TWicImage;
  WICF    : TWicImageFormat;

  Fname   : String;
  ExeStr  : String;
  FnameTop: String;
  Findex  : integer;

  function WFormatSet: Boolean;                                             // 拡張子によるファイルフォーマット設定
  begin
    Result := false;
    ExeStr := LowerCase(ExeStr);
    if ExeStr = '.jpg'  then  begin WICF := Wifjpeg; Result := True; end;
    if ExeStr = '.jpeg' then  begin WICF := Wifjpeg; Result := True; end;
    if ExeStr = '.tif'  then  begin WICF := Wiftiff; Result := True; end;
    if ExeStr = '.tiff' then  begin WICF := Wiftiff; Result := True; end;
    if ExeStr = '.png'  then  begin WICF := Wifpng;  Result := True; end;
    if ExeStr = '.gif'  then  begin WICF := Wifgif;  Result := True; end;
    if ExeStr = '.bmp'  then  begin WICF := Wifbmp;  Result := True; end;
    if ExeStr = '.wdp'  then  begin WICF := WifWMPhoto; Result := True; end;
    if ExeStr = '.hdp'  then  begin WICF := WifWMPhoto; Result := True; end;
  end;

begin
  SavePictureDialog1.Filter := SaveFileFilter;
//  SavePictureDialog1.DefaultExt := GraphicExtension(TWicImage);
  if not SavePictureDialog1.Execute then exit;
  ExeStr := ExtractFileExt(SavePictureDialog1.FileName);
  if ExeStr = '' then begin                                                 // 拡張子がなかったら
    Findex := SavePictureDialog1.FilterIndex;                               // FilterIndexによる拡張子の設定
    case Findex of
      1, 3 : Fname := ChangeFileExt(SavePictureDialog1.FileName,'.jpg');    // 拡張子の設定
         2 : Fname := ChangeFileExt(SavePictureDialog1.FileName,'.png');
         4 : Fname := ChangeFileExt(SavePictureDialog1.FileName,'.gif');
         5 : Fname := ChangeFileExt(SavePictureDialog1.FileName,'.bmp');
         6 : Fname := ChangeFileExt(SavePictureDialog1.FileName,'.tif');
         7 : Fname := ChangeFileExt(SavePictureDialog1.FileName,'.wdp');
    end;
  end
  else
    Fname := SavePictureDialog1.FileName;
  ExeStr := ExtractFileExt(Fname);                                          // 拡張子だけ取り出し
  if not WFormatSet then begin                                              // 拡張子によるファイルフォーマット設定と確認
    application.MessageBox('ファイルの拡張子が間違っています。','注意', 0);
    exit;
  end;
  FnameTop := ExtractFileName(Fname);                                       // ファイル名だけ取り出し
  if Length(FnameTop) = Length(ExeStr) then begin                           // ファイル名の長さ確認
    application.MessageBox('ファイル名がありません。','注意', 0);
    exit;
  end;

  if FileExists(Fname) then                                                 // ファイル名によるファイル検索
    if MessageDlg('既に同じ名前のファイルがあります上書きしますか ' + ExtractFileName(Fname) + '?',
                                                      mtConfirmation, [mbYes, mbNo], 0, mbNo) = IDNo then exit;

  WIC := TWicImage.Create;                                                  // TWicImage生成
  try
    WIC.Assign(OutBitmap);                                                  // TWicImageにビットマップデーター割り付け
    WIC.ImageFormat := WICF;                                                // 保存フォーマットセット
    WIC.SaveTofile(Fname);                                                  // ファイルの書き出し
  finally                                                                   // XE3,XE4の場合はアンシャープマスキングを参照してください
    WIC.Free;                                                               // TWicImage解放
  end;
end;

//============
// 初期設定
//============
procedure TForm1.FormCreate(Sender: TObject);
begin
  Top := (Screen.Height - Height) div 2;                      // 表示位置設定
  Left := (Screen.Width - Width) div 2;
  InBitmap      := TBitmap.Create;                            // 入力画像用
  OutBitmap     := TBitmap.Create;                            // 出力画像用
  InBitmap.PixelFormat    := pf32bit;                         // 32ビットカラーに設定
  OutBitmap.PixelFormat   := pf32bit;                         // 32ビットカラーに設定
  RGBtoHSLbtn.Enabled := False;                               // ボタンディスエブル
  FileSaveBtn.Enabled := False;
  ColorControlBtn.Enabled := False;
end;

//=============================
// 終了時ビットマップの解放
//=============================
procedure TForm1.FormDestroy(Sender: TObject);
begin
  InBitmap.Free;
  OutBitmap.Free;
end;

end.

    download ColorContRol_RGBtoHSL.zip

画像処理一覧へ戻る

      最初に戻る