ガンマ関数による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.

    download RGBGammaControl.zip

画像処理一覧へ戻る

      最初に戻る