カラーコントロール (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の場合は、元画像の明度値のまゝとなります。
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.