ガンマ関数によるRGBカラーコントロール
R、G、B の各値をΓ(ガンマ)補正することによって、色合いを変えるプログラムを作成してみました。
全体を同じガンマ値で補正するのは、ガンマ補正のプログラムにあります。
プログラムは簡単で、スクロールバーを3個用意して、赤、緑、青 それぞれのγ値を生成、スクロールバーの移動に応じて、その時のγ値から補正用テンプレートを作成し、色の輝度値を変換して、画像を表示するだけです。
移動に応じて、画像を補正し表示しますが、サイズの大きい写真の場合は、移動中の割り込み処理が間に合わないので、移動が停止するまで、補正画面が表示されない場合があります。
その場合は、カーソルをゆっくりと移動してください。
サンプル画像
単なるガンマ値による、コントラストの補正では、暗いところを明るくするぐらいでしたが、R、G、B それぞれ単独で、補正することにより、微妙な色合いを制御できます。
サンプルプログラム
{ RGB各色のコントラストをγ補正を使用して、色の補正をするプログラムです ガンマ値の変更は、スクロールバーで行います} unit RGBGammaMain; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls, Vcl.ExtDlgs, System.Types, System.UITypes, Math; type TTempArray = array[0..255] of Byte; // テンプレート用配列 TForm1 = class(TForm) FileOpen: TButton; Image1: TImage; OpenPictureDialog1: TOpenPictureDialog; SavePictureDialog1: TSavePictureDialog; FileSaveBtn: TButton; RedScrollBar: TScrollBar; GreenScrollBar: TScrollBar; BlueScrollBar: TScrollBar; RedLabel: TLabel; GreenLabel: TLabel; BlueLabel: TLabel; GammaLabel: TLabel; RedEdit: TEdit; GreenEdit: TEdit; BlueEdit: TEdit; procedure FormCreate(Sender: TObject); procedure FileOpenClick(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FileSaveBtnClick(Sender: TObject); procedure RedScrollBarScroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Integer); procedure BlueScrollBarScroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Integer); procedure GreenScrollBarScroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Integer); private { Private 宣言 } function GammaTemplate(Gamma: Double): TTempArray; // GammaTemplateデーター作成 procedure GammaImage; // Gamma補正画像表示 public { Public 宣言 } end; var Form1: TForm1; type TPrgbarry = array[0..0] of Trgbtriple; // 24ビットカラーレコード 32ビット用はTRGBQuadArray Prgbarray = ^TPrgbarry; // ポインター // 配列のポインターが必要なだけなので、長さは1 [0..0]で問題ありません。 implementation {$R *.dfm} 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'; ImageHW = 384; // 表示枠サイズ var InBitmap : TBitmap; // ビットマップ OutBitmap : TBitmap; GHeight, GWidth : integer; // ソース画像サイズ Vrect : Trect; // 表示枠 IHeight, IWidth : Integer; // 表示サイズ RGamma : Double; // 赤ガンマ値 GGamma : Double; // 緑ガンマ値 BGamma : Double; // 青ガンマ値 RGTemp : TTempArray; // Red ガンマテンプレート用配列 赤 GGTemp : TTempArray; // Green ガンマテンプレート用配列 緑 BGTemp : TTempArray; // Blue ガンマテンプレート用配列 青 // Gamma補正画像表示 procedure TForm1.GammaImage; var Pin : Prgbarray; Pout : Prgbarray; II, JJ : Integer; begin for II := 0 to Gheight - 1 do begin Pin := InBitmap.ScanLine[II]; // 水平ラインの先頭ポインタ取得 Pout := OutBitmap.ScanLine[II]; for JJ := 0 to GWidth - 1 do begin Pout[JJ].rgbtBlue := BGTemp[Pin[JJ].rgbtBlue]; // テンプレート値へ変換 Pout[JJ].rgbtGreen := GGTemp[Pin[JJ].rgbtGreen]; Pout[JJ].rgbtRed := RGTemp[Pin[JJ].rgbtRed]; end; end; Image1.Canvas.StretchDraw(VRect, OutBitmap); // 出力枠に変倍出力 end; // テンプレートデーターの設定 function TForm1.GammaTemplate(Gamma: Double): TTempArray; // GammaTemplateデーター作成 var II : Integer; begin for II := 0 to 255 do begin // ガンマ値0の計算は出来ないのでテンプレートゼロに設定 if Gamma = 0 then Result[II] := 0 else Result[II] := Round(255 * Power(II / 255, 1 / Gamma)); // テンプレートの作成 end; end; // スクロール処理 procedure TForm1.RedScrollBarScroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Integer); begin RGamma := ScrollPos / 20; RedEdit.Text := floatTostr(RGamma); RGTemp := GammaTemplate(RGamma); GammaImage; // Gamma補正画像表示 end; procedure TForm1.GreenScrollBarScroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Integer); begin GGamma := ScrollPos / 20; GreenEdit.Text := floatTostr(GGamma); GGTemp := GammaTemplate(GGamma); GammaImage; // Gamma補正画像表示 end; procedure TForm1.BlueScrollBarScroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Integer); begin BGamma := ScrollPos / 20; BlueEdit.Text := floatTostr(BGamma); BGTemp := GammaTemplate(BGamma); GammaImage; // Gamma補正画像表示 end; // ファイルのオープン WIC がファイルの種類が多いので使用 procedure TForm1.FileOpenClick(Sender: TObject); var WIC : TWICImage; InFilename : String; begin FileSaveBtn.Enabled := False; VRect := Rect(0, 0, Image1.Width, Image1.Height); Image1.Canvas.Brush.Style := bsSolid; Image1.Canvas.Brush.Color := clBtnface; Image1.Canvas.FillRect(VRect); // Canvas 画像消去 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; // 画像幅 IWidth := ImageHW; // 出力先イメージ1の幅 IHeight := ImageHW; // 出力先イメージ1の高さ if GHeight <= GWidth then // 縦横比により出力サイズ設定 IHeight := Round(IWidth * GHeight / GWidth) else IWidth := Round(IHeight * GWidth / GHeight); Image1.Width := IWidth; Image1.Height:= IHeight; Image1.Picture.Bitmap.SetSize(IWidth, IHeight); // 表示用ビットマップサイズの設定 VRect := Rect(0, 0, IWidth, IHeight); // 出力枠設定 Image1.Canvas.StretchDraw(VRect, WIC); // 出力枠に変倍出力 InBitmap.Width := GWidth; InBitmap.Height := GHeight; InBitmap.Canvas.Draw(0, 0, WIC); // DrawでInBitmapに入力画像設定フォーマット24ビットに変換されます OutBitmap.Width := GWidth; OutBitmap.Height:= GHeight; finally WIC.Free; // TWICImage 解放 end; end else Exit; RedScrollBar.Enabled := True; GreenScrollBar.Enabled := True; BlueScrollBar.Enabled := True; FileSaveBtn.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 FileSaveBtn.Enabled := False; RedScrollBar.Enabled := False; GreenScrollBar.Enabled := False; BlueScrollBar.Enabled := False; Image1.Width := ImageHW; Image1.Height := ImageHW; InBitmap := TBitmap.Create; // 入力画像用 OutBitmap := TBitmap.Create; // 24ビット出力用 InBitmap.PixelFormat := pf24bit; // 24ビットカラーに設定 OutBitmap.PixelFormat := pf24bit; // 24ビットカラーに設定 RGTemp := GammaTemplate(1); // 赤テンプレート初期設定 GGTemp := GammaTemplate(1); // 緑テンプレート初期設定 BGTemp := GammaTemplate(1); // 青ンプレート初期設定 end; // ビットマップの解法 procedure TForm1.FormDestroy(Sender: TObject); begin InBitmap.Free; OutBitmap.Free; end; end.