輝度、彩度、色相のコントロール

 此処では、画像の輝度、彩度、色相を変更するプログラムを検討します。

実行画面
  一般的に色は、明度、彩度、色相で表されますが、画像として処理をする場合は、輝度、彩度、色相で処理をする必要があります。
 明度の場合定義によって異なるのですが、R、G、Bの色の最大値と、最小値の平均値だったり、最大値だけだったりします。
色を視覚的に捕らえるのではなく、単に理論的に区分けする為のもので、明度は画像の色の実際の明るさではありません。
明度と、視覚的に感じる明るさとはかけ離れたものになっています。
例えば、Windowsの場合、RGB各値の最大値は、255ですが、明度は全て同じ値となります、しかし、視覚的には、G(グリーン)が明るく、R、Bの順でB(ブルー)が一番暗く感じます。
しかし、この3色を、混合すると白にみえます。
 元々、太陽光線を反射した光りで、画像を見ているのですが、太陽光線のスペクトル中の一番強い部分を利用していて、R、G、Bの光りの強さに大きな差はありませんが、視覚的に緑を明るく感じる為、輝度値として大きな係数をあたえます。

 等々の理由により、此処では明るさの値として、輝度を使用します。
輝度の値は、明度と異なり、RGB三色による値となります。


 下図は、明度と輝度の差を表していますが、明度の場合、そのままグレーに変換すると、同じグレーの値になり、視覚にあわせた輝度変換をすると、見た目の明るさに応じたグレー画像になります。
マゼンタは赤と青の同じ明るさの混合色なので、赤、青の単色よりもよりも明るい色の筈ですが、同じ明度として数値化されているため、その値でグレーにすると、全て同じ明るさのグレーになってしまいます。
 画像として色を扱う場合は、光りの強さに応じた明るさを扱う必要があるということです。
カラーパレット
 輝度は、グレーに変換する場合の係数として、赤 0.298912 緑 0.586611 青 0.114478 となっています。
これは、カラーのテレビ放送が始まった時に、同じ電波でカラーと、モノクロの画像を送る必要があり、カラーの画像を視覚的に同じ明るさで視聴する為に定められた、変換係数のようですが、実際には、赤 0.3 緑 0.6 青 0.1 でも、問題はありません。
テレビ画像は、輝度(y)と色信号(Cb,Cr)からなっている事になり、此処での計算も、輝度(y)と色信号(Cb,Cr)を利用して計算します。

RGBtoYcbcr
 左の計算式は、上側がRGBから輝度値と彩度に変換する式で、ST が彩度の値となります。
下側が、輝度値と、彩度からRGBに変換をする式です。

輝度値をグレー画像として利用しなければ、変換の係数は赤=1/3、緑=1/3、青=1/3 でも問題ありません。
 
色相は、カラー値のCR、CBから計算される角度で左のHuが色相となります。
色相の単位は角度の単位となります。
arctanの計算は四象限の答えが出る計算です。

 
赤 0.299 緑 0.587 青 0.114で 輝度値を計算して色相を求めると、通常は 赤 113度 緑 225度 青 353度となり、120度等分にはなりません。
又、一般的な色相環は、赤の位置が0度ですが、ここの計算では0度になりません。
緑の位置は、変換係数の値に関係なく 225度 なります。
120度等分にするには、次の値に設定すれば120度等分となりますが、グレー(輝度)変換時の濃度に差が出ます。

赤 kr := 255 / (255 - 255 * tan(105 / 180 * pi));  // kr = kb = 0.211325
青 kb := kr;
緑 kg := 1 - kr - kb;                   // kg = 0.57735

120度等分にした場合は、赤と、青の係数が同じになるので、グレーにした場合、同じ明るさだと、同じ輝度値(グレー値)になるので、グレー画像では判別できなくなります。
しかし、グレー画像に変換した場合、どの様な変換係数を設定しても、同じ輝度値になる組み合わせの条件は、必ず存在するのであまり気にする必要はないと思います。
まして、カラー画像を、グレーに変換して処理をするような事は、特殊な場合を除いて殆ど無いでしょう。
変換サンプル
上のサンプル画像で、右から二番目の輝度が赤 0.299 緑 0.587 青 0.114の値で輝度変換したもので、右側の輝度1が、120度等分になるして輝度変換したものです。
赤の部分の明るさが、輝度1の方が暗くなっているのが分かります。

サンプル2
 上側の画像が、色相角度120°毎になるように変換係数を設定した場合の角度を変更した場合で、下側が標準の変換係数を使用した場合です。
120°変更した時に、差が顕著に現れていますが、240°ではあまり差が分かりません。

色相環
 色相環を表示すると、赤の位置と、青の位置がずれていることが分かります。
一般的な方法では、赤を0度しますが、此処で作成したプログラムは、0度に補正せず計算された値で表示しています。
0度する場合は、プログラムをダウンロードして、赤の角度分シフト、色の方向は、描画時の座標計算を逆にして下さい。

サンプルプログラム (ColorControl)

unit Main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtDlgs, Vcl.ExtCtrls, Vcl.StdCtrls, System.Math,
  Vcl.Buttons;

Type
  TDIarray   = array of array of Double;

type
  TForm1 = class(TForm)
    FileOpenbtn: TButton;
    Image1: TImage;
    OpenPictureDialog1: TOpenPictureDialog;
    RGBtoHSVtoRGBBtn: TButton;
    Image2: TImage;
    sat_imageBtn: TButton;
    hue_imageBtn: TButton;
    YmEdit: TLabeledEdit;
    SmEdit: TLabeledEdit;
    HdEdit: TLabeledEdit;
    CheckBox1: TCheckBox;
    yTograyBtn: TButton;
    tran_yshBtn: TBitBtn;
    procedure FileOpenbtnClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure RGBtoHSVtoRGBBtnClick(Sender: TObject);
    procedure sat_imageBtnClick(Sender: TObject);
    procedure hue_imageBtnClick(Sender: TObject);
    procedure tran_yshBtnClick(Sender: TObject);
    procedure yTograyBtnClick(Sender: TObject);
  private
    { Private 宣言 }
    procedure rgb_to_yc;                      // R,G,Bから輝度,色差信号に変換
    procedure yc_to_rgb(y, c1, c2: TDIarray); // 輝度,色差信号からR,G,B信号に変換
    procedure c_to_sh;                        // 色差信号から彩度,色相を計算
    procedure sh_to_c;                        // 彩度,色相から色差信号を計算
    function  sat_image: Integer;             // 彩度データを濃淡画像化
    procedure hue_image;                      // 色相データを画像化
    procedure tran_ysh(ym, sm, hd :Double);   // 輝度,彩度,色相を変える
    procedure setarray;                       // 配列サイズ設定
  public
    { Public 宣言 }
  end;

type
  TPrgbarry = array[0..0] of Trgbtriple;
  Prgbarry  = ^TPrgbarry;

var
  Form1: TForm1;

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;                            // 表示枠サイズ

//  kr = 0.299;                                 // R 輝度変換係数
//  kg = 0.587;                                 // G 輝度変換係数
//  kb = 0.114;                                 // B 輝度変換係数


var
  GHeight, GWidth : integer;
  Vrect           : Trect;
  InBitmap        : TBitmap;
  OutBitmap       : TBitmap;
  Inprgbarry      : array of Prgbarry;
  y               : TDIarray;                 // y  輝度
  c1              : TDIarray;                 // R - Y
  c2              : TDIarray;                 // B - y
  sat             : TDIarray;                 // 彩度
  hue             : TDIarray;                 // 色相

  Out_y           : TDIarray;                 // y  輝度
  Out_sat         : TDIarray;                 // 彩度
  Out_Hue         : TDIarray;                 // 色相
  Out_c1          : TDIarray;                 // R - Y
  Out_c2          : TDIarray;                 // B - y

  kr              : double;                   // = 0.299;  R 輝度変換係数
  kg              : double;                   // = 0.587;  G 輝度変換係数
  kb              : double;                   // = 0.114;  B 輝度変換係数

//------- tran_ysh  輝度,彩度,色相を変えます -----------------------
//    y:            入力データ配列 Y
//    sat:          入力データ配列 SAT
//    hue:          入力データ配列 HUE
//    out_y:        出力データ配列 Y
//    out_sat:      出力データ配列 SAT
//    out_hue:      出力データ配列 HUE
//    ym:           輝度の乗数
//    sm:           彩度の乗数
//    hd:           色相の増分
//-------------------------------------------------------------------
procedure TForm1.tran_ysh(ym, sm, hd :Double);
var
  i, j  : integer;
begin
  for i := 0 to GHeight - 1 do
    for j := 0 to GWidth - 1 do begin
      out_y[i][j]   := y[i][j] * ym;         // 輝度の計算
      out_sat[i][j] := sat[i][j] * sm;       // 彩度の計算
      out_hue[i][j] := hue[i][j] + hd;       // 色相の計算
      if out_hue[i][j] > 360 then out_hue[i][j] := out_hue[i][j] - 360;
      if out_hue[i][j] <  0  then out_hue[i][j] := out_hue[i][j] + 360;
    end;
  sh_to_c;                                            // 彩度,色相から色差信号を計算
  yc_to_rgb(out_Y, out_C1, out_C2);                   // 輝度,色差信号からR,G,B信号に変換
  Image2.Canvas.StretchDraw(VRect, OutBitmap);        // 出力枠に変倍出力
end;

//------------- 輝度、彩度、色相を変えます -----------------
//    ym:           輝度の乗数
//    sm:           彩度の乗数
//    hd:           色相の増分
//--------------------------------------------------------
procedure TForm1.tran_yshBtnClick(Sender: TObject);
var
  ym    : Double;
  sm    : Double;
  hd    : Double;
  ch    : Integer;
begin
  if CheckBox1.Checked then begin
    // チェック時 輝度変換係数を色相角度が120度毎になるように設定 R 105度 g 225度 b 345度
    // Rを105度にする
    kr := 255 / (255 - 255 * tan(105 / 180 * pi));  // kr = kb = 0.211325
    kb := kr;
    kg := 1 - kr - kb;                              // kg = 0.57735
  end
  else begin
    // 通常は  R 113度  g 225度  b 353 度
    kr  := 0.299;                     // R 輝度変換係数
    kg  := 0.587;                     // G 輝度変換係数
    kb  := 0.114;                     // B 輝度変換係数
  end;
  setarray;                           // 配列サイズ設定
  rgb_to_yc;                          // R,G,Bから輝度,色差信号に変換
  c_to_sh;                            // 色差信号から彩度,色相を計算
  val(ymEdit.Text, ym, ch);       // 輝度の乗数
  if ch <> 0 then ym := 1;
  ym := abs(ym);
  val(smEdit.Text, sm, ch);       // 彩度の乗数
  if ch <> 0 then sm := 1;
  sm := abs(sm);
  val(hdEdit.Text, hd, ch);       // 色相の増分
  if ch <> 0 then hd := 0;
  if hd > 360  then hd :=  360;   // 360度以内に設定
  if hd < -360 then hd := -360;
  tran_ysh(ym, sm, hd);           // 輝度,彩度,色相を変える
end;

//--- hue_image  色相データを画像化します ------------------------------------
//    sat:          彩度のデータ配列
//    hue:          色相のデータ配列
//    stdhue:       基準となる色相値
//    OutBitmap:    出力画像
//----------------------------------------------------------------------------
procedure TForm1.hue_image;
var
  i, j    : Integer;
  ihue    : Integer;
  delt    : Double;
  OutPrgbarray  : Prgbarry;
  stdhue  : double;
begin
  val(hdedit.Text, stdhue, i);
  if i <> 0 then stdhue := 0;
  if stdhue > 360  then stdhue :=  360;                       // 360度以内に設定
  if stdhue < -360 then stdhue := -360;
  for i := 0 to GHeight - 1 do begin
    OutPrgbarray := OutBitmap.ScanLine[i];
    for j := 0 to GWidth -1 do begin
      if sat[i][j] > 0 then begin                             // 彩度がゼロ以上だったら
        delt := abs(hue[i][j] - stdhue);                      // 色相角度の絶対値
        if delt < 0 then delt := delt + 360;
        if delt > 180  then delt := 360.0 - delt;             // 180度以内に設定 
        ihue := Trunc(255.0 - delt * 255.0 / 180);            // 255から0に変換
        OutPrgbarray[j].rgbtBlue  := ihue;
        OutPrgbarray[j].rgbtGreen := ihue;
        OutPrgbarray[j].rgbtRed   := ihue;
      end
      else begin
        OutPrgbarray[j].rgbtBlue  := 0;
        OutPrgbarray[j].rgbtGreen := 0;
        OutPrgbarray[j].rgbtRed   := 0;
      end;
    end;
  end;
  Image2.Canvas.StretchDraw(VRect, OutBitmap);                // 出力枠に変倍出力
end;

procedure TForm1.hue_imageBtnClick(Sender: TObject);
begin
  hue_image;        // 色相データを画像化
end;

//--- sat_image  彩度データを濃淡画像化します ------------------------------
//    sat:          彩度のデータ配列
//    OutBitmap:    出力画像
//--------------------------------------------------------------------------
function TForm1.sat_image: Integer;
var
  i, j      : Integer;
  isat      : Integer;
  min, max  : double;
  OutPrgbarray  : Prgbarry;
begin
  min := 255;
  max := 0;
  // 彩度の最大値と最小値検索
  for i := 0 to  GHeight - 1 do
    for j := 0 to GWidth - 1 do begin
      if sat[i][j] > max then max := sat[i][j];
      if sat[i][j] < min then min := sat[i][j];
    end;
  // 彩度がなかったら終了
  if min = max then begin
    result := -1;
    exit;
  end;
  for i := 0 to GHeight - 1 do begin
    OutPrgbarray := OutBitmap.ScanLine[i];
    for j := 0 to GWidth - 1 do begin
      isat := Trunc(255 * (sat[i][j] - min) / (max - min));   // 彩度の値を0~255に変換
      OutPrgbarray[j].rgbtRed   := isat;
      OutPrgbarray[j].rgbtGreen := isat;
      OutPrgbarray[j].rgbtBlue  := isat;
    end;
  end;
  Image2.Canvas.StretchDraw(VRect, OutBitmap);                // 出力枠に変倍出力
  result := 0;
end;

procedure TForm1.sat_imageBtnClick(Sender: TObject);
var
  Ret : Integer;
begin
  Ret := sat_image;                                           // 彩度データを濃淡画像化
  if Ret = -1 then application.MessageBox('彩度がありません。','情報',0);
end;

//--- sh_to_c  彩度,色相から色差信号を計算します -----------------------------
//    out_c1:     出力データ配列R-Y
//    out_c2:     出力データ配列B-Y
//    out_sat:    彩度のデータ配列
//    out_hue:    色相のデータ配列
//----------------------------------------------------------------------------
procedure TForm1.sh_to_c;
var
  i, j  : Integer;
  rad   : Double;
begin
  for i := 0 to GHeight - 1 do
    for j := 0 to GWidth do begin
      rad := PI * out_hue[i][j] / 180;
      out_c1[i][j] := out_sat[i][j] * sin(rad);
      out_c2[i][j] := out_sat[i][j] * cos(rad);
    end;
end;

//---- c_to_sh  色差信号から彩度,色相を計算します ----------------------------
//    c1:        入力データ配列R-Y
//    c2:        入力データ配列B-Y
//    sat:      彩度のデータ配列
//    hue:      色相のデータ配列
//    単色角度    R 113度 g 225度 b 353度  通常は均等の角度にはなっていない
//    均等配分時  R 105度  g 225度  b 345度  CheckBox check時
//----------------------------------------------------------------------------
procedure TForm1.c_to_sh;
const
  THRESHOLD =  0;               // 彩度の有無を判断する閾値
  NONE      =  0;               // 彩度がない場合に代入する値
var
  i, j          : Integer;
  fhue, length  : Double;
begin
  for i := 0 to  GHeight -1 do
    for j := 0 to GWidth - 1 do begin
      length    := c1[i][j] * c1[i][j] + c2[i][j] * c2[i][j];
      sat[i][j] := sqrt(length);                              // 彩度
      if sat[i][j] > THRESHOLD then begin
        fhue := arctan2(c1[i][j] , c2[i][j]) * 180 / pi;      // 色相
        if fhue < 0 then  fhue := fhue + 360;
        hue[i][j] := fhue;
      end
      else hue[i][j] := NONE;  // 彩度が閾値以下の時
    end;
end;

//--- yc_to_rgb  輝度,色差信号からR,G,B信号に変換します ---------------------
//    y:            入力データ配列 Y
//    c1:           入力データ配列R-Y
//    c2:           入力データ配列B-Y
//    OutBitmap:     出力画像
//  fr         =  y[i][j] + c1[i][j]
//  fb         =  y[i][j] + c2[i][j]
//  y[i][j]    =  0.299 * fr + 0.587 * fg + 0.114 * fb
//  0.587 * fg =  y[i][j] - 0.299 * fr - 0.114 * fb
//  fg         = (y[i][j] - 0.299 * fr - 0.114 * fb) / 0.587
//  fg         =  y[i][j] - 0.299 / 0.587 * c1[i][j] - 0.114 / 0.587 * c2[i][j]
//------------------------------------------------------------------------------
procedure TForm1.yc_to_rgb(y, c1, c2: TDIarray);
var
  i, j          : Integer;
  ir, ig, ib    : Integer;
  OutPrgbarray  : Prgbarry;
  a, b          : Double;
begin
  a := kr / kg;                                            // a = 0.299 / 0.587
  b := kb / kg;                                            // b = 0.114 / 0.587
  for i := 0 to GHeight - 1 do begin
    OutPrgbarray := OutBitmap.ScanLine[i];
    for j := 0 to GWidth - 1 do begin
      ir := Trunc(y[i][j] + c1[i][j]);                     // R = Y + (R - y)
      if ir > 255 then ir := 255;
      if ir < 0   then ir := 0;
      ig := Trunc(y[i][j] - a * c1[i][j] - b * c2[i][j]);  // G = Y - a(R - Y) - b(B - Y);
      if ig > 255 then ig := 255;
      if ig < 0   then ig := 0;
      ib := Trunc(y[i][j] + c2[i][j]);                     // B = Y + (B - Y)
      if ib > 255 then ib := 255;
      if ib < 0   then ib := 0;
      OutPrgbarray[j].rgbtRed   := ir;
      OutPrgbarray[j].rgbtGreen := ig;
      OutPrgbarray[j].rgbtBlue  := ib;
    end;
  end;
end;

// グレイ画像(輝度)表示
procedure TForm1.yTograyBtnClick(Sender: TObject);
var
  i, j          : Integer;
  iglay         : Integer;
  OutPrgbarray  : Prgbarry;
begin
  for i := 0 to GHeight - 1 do begin
    OutPrgbarray := OutBitmap.ScanLine[i];
    for j := 0 to GWidth - 1 do begin
      iglay := round(y[i,j]);
      OutPrgbarray[j].rgbtRed   := iglay;
      OutPrgbarray[j].rgbtGreen := iglay;
      OutPrgbarray[j].rgbtBlue  := iglay;
    end;
  end;
  Image2.Canvas.StretchDraw(VRect, OutBitmap);                // 出力枠に変倍出力
end;

//--- rgb_to_yc  R,G,Bから輝度,色差信号に変換します ------------------------
//    Inprgbarry:    入力画像配列
//    y:             出力データ配列 Y
//    c1:            出力データ配列R-Y
//    c2:            出力データ配列B-Y
//    y[i][j]  :=  0.299 * fr + 0.587 * fg + 0.114 * fb;      // Y
//    c1[i][j] :=  0.701 * fr - 0.587 * fg - 0.114 * fb;      // R - Y  (fr - y)
//    c2[i][j] := -0.299 * fr - 0.587 * fg + 0.886 * fb;      // B - Y  (fb - y)
//-----------------------------------------------------------------------------
procedure TForm1.rgb_to_yc;
var
  i, j        : Integer;
  fr, fg, fb  : Double;
begin
  for i := 0 to GHeight - 1 do
    for j := 0 to GWidth - 1 do begin
      fr := Inprgbarry[i][j].rgbtRed;
      fg := Inprgbarry[i][j].rgbtGreen;
      fb := Inprgbarry[i][j].rgbtBlue;
//      fr := 0;
//      fg := 0;
//      fb := 255;
      y[i][j]  :=  kr * fr + kg * fg + kb * fb;               // Y
      c1[i][j] :=  fr - y[i][j];                              // R - Y  (fr - y)
      c2[i][j] :=  fb - y[i][j];                              // B - Y  (fb - y)
   end;
end;

//---------- 配列の長さセット---------------------
//    y:            データ配列 Y
//    c1:           データ配列R-Y
//    c2:           データ配列B-Y
//    sat:          彩度のデータ配列
//    hue:          色相のデータ配列
//    out_c1:       出力データ配列R-Y
//    out_c2:       出力データ配列B-Y
//    out_sat:      出力彩度のデータ配列
//    out_hue:      出力色相のデータ配列
//    Inprgbarry:   入力画像配列
//------------------------------------------------
procedure TForm1.setarray;
var
  i        : integer;
begin
  setlength(Inprgbarry, GHeight);
  setlength(y,   GHeight, GWidth);
  setlength(C1,  GHeight, GWidth);
  setlength(C2,  GHeight, GWidth);
  setlength(sat, GHeight, GWidth);
  setlength(hue, GHeight, GWidth);
  setlength(out_sat, GHeight, GWidth);
  setlength(out_hue, GHeight, GWidth);
  setlength(out_y,   GHeight, GWidth);
  setlength(out_C1,  GHeight, GWidth);
  setlength(out_C2,  GHeight, GWidth);
  for i := 0 to GHeight - 1 do
    Inprgbarry[i] := InBitmap.ScanLine[i];
  OutBitmap.Width  := GWidth;
  OutBitmap.Height := GHeight;
end;

//------- 各変換後元へ戻して画像表示確認--------------------
procedure TForm1.RGBtoHSVtoRGBBtnClick(Sender: TObject);
begin
  if CheckBox1.Checked then begin
    // チェック時 輝度変換係数を色相角度が120度毎になるように設定 R 105度 g 225度 b 345度
    // Rを105度にする
    kr := 255 / (255 - 255 * tan(105 / 180 * pi));  // kr = kb = 0.211325
    kb := kr;
    kg := 1 - kr - kb;                              // kg = 0.57735
  end
  else begin
    // 通常は  R 113度  g 225度  b 353 度
    kr  := 0.299;                     // R 輝度変換係数
    kg  := 0.587;                     // G 輝度変換係数
    kb  := 0.114;                     // B 輝度変換係数
  end;
  setarray;                           // 配列サイズ設定
  rgb_to_yc;                          // R,G,Bから輝度,色差信号に変換
  c_to_sh;                            // 色差信号から彩度,色相を計算
  yc_to_rgb(Y, C1, C2);               // 輝度,色差信号からR,G,B信号に変換
  Image2.Canvas.StretchDraw(VRect, OutBitmap);                // 出力枠に変倍出力
  sat_imageBtn.Enabled  := True;
  hue_imageBtn.Enabled  := True;
  yTograyBtn.Enabled    := True;
end;

//------- 画像ファイルオープン 表示---------------------------
procedure TForm1.FileOpenbtnClick(Sender: TObject);
var
  WIC         : TWICImage;
  InFilename  : String;
  IHeight     : Integer;
  IWidth      : Integer;
begin
  VRect := Rect(0, 0, Image1.Width, Image1.Height);
  Image1.Canvas.Brush.Style := bsSolid;
  Image1.Canvas.Brush.Color := clBtnface;
  Image1.Canvas.FillRect(VRect);                              // Canvas 画像消去
  Image2.Canvas.Brush.Style := bsSolid;
  Image2.Canvas.Brush.Color := clBtnface;
  Image2.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ビットに変換
      finally
        WIC.Free;                                             // TWICImage 解放
      end;
    end
    else exit;
  RGBtoHSVtoRGBBtn.Enabled    := True;
  sat_imageBtn.Enabled  := False;
  hue_imageBtn.Enabled  := False;
  tran_yshBtn.Enabled   := True;
end;

//----------- 初期設定 ------------------------
procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Width  := ImageHW;
  Image1.Height := ImageHW;
  Image2.Width  := ImageHW;
  Image2.Height := ImageHW;
  InBitmap  := TBitmap.Create;
  OutBitmap := TBitmap.Create;
  InBitmap.PixelFormat  := pf24bit;
  OutBitmap.PixelFormat := pf24bit;
  RGBtoHSVtoRGBBtn.Enabled    := False;
  sat_imageBtn.Enabled  := False;
  hue_imageBtn.Enabled  := False;
  tran_yshBtn.Enabled   := False;
  yTograyBtn.Enabled    := False;
  tran_yshBtn.Caption := 'Color調整' + #13#10 + 'HSV to RGB';
end;

//------------ 終了処理 ------------------------
procedure TForm1.FormDestroy(Sender: TObject);
begin
  InBitmap.Free;
  OutBitmap.Free;
end;

end.

    download ColorControl.zip

画像処理一覧へ戻る

      最初に戻る