擬似カラー
疑似カラーは、山の高さ表示や、温度分布の表示など、本来は色の無いものに、色を付けて表示かる方法です。
360°のカラーリングを用いると、最高の値と、最低の値が同じ色になってしまうので、青から赤までの色を使用するのが一般的です。
温度の場合は、
最低の値が純粋な青で、最大値が純粋な赤とします。
画像の場合、一端モノクロームのグレイスケール画像にしてから、上図右の様な配分で色付けをします。
青が一番小さい値で、赤を大きくするのは、人の色に対する感覚を利用したものです。
もし、緑化を表す場合は、純赤を一番小さくして、純緑を一番大きな値にするのが良いと思われます。
必要に応じて、色の組み合わせを変えたほうが良いでしょう。
グレイスケールと色の関係を示すカラーバーです。
下の図は、上のカラーバーの条件で、グレイスケール画像に色付けをしたものです。
この方法は、一般的な写真には使用それませんが、測定器のデーターを二次元で表示する場合に、よく使用される方法です。
サンプルプログラム
unit PseudoColor; 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; type TForm1 = class(TForm) FileOpenBtn: TButton; Image1: TImage; GrayBtn: TButton; Image2: TImage; Image3: TImage; OpenPictureDialog1: TOpenPictureDialog; Pseudo_ColorBtn: TButton; SorceBtn: TButton; procedure FormCreate(Sender: TObject); procedure FileOpenBtnClick(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure GrayBtnClick(Sender: TObject); procedure Pseudo_ColorBtnClick(Sender: TObject); procedure SorceBtnClick(Sender: TObject); private { Private 宣言 } procedure MakeTemp; // カラーテンプレート作成 procedure MonoColorBar; // モノクロカラーバー procedure ColorBar; // カラーバー procedure ConvertGray; // グレースケール変換 public { Public 宣言 } end; 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'; kr = 0.299; // R 輝度変換係数 kg = 0.587; // G 輝度変換係数 kb = 0.114; // B 輝度変換係数 var ColorTemp : array[0..255] of TColor; // カラーテンプレート GrayScale : array of array of Byte; InBitmap : TBitmap; // ビットマップ OutBitmap : TBitmap; GHeight, GWidth : integer; // ソース画像サイズ VRect : Trect; // 表示サイズ設定用 type TPrgbarry = array[0..0] of Trgbtriple; // 24ビットカラーレコード 32ビット用はTRGBQuadArray Prgbarray = ^TPrgbarry; // ポインター // 配列のポインターが必要なだけなので、長さは1 [0..0]で問題ありません。 //====================== // グレースケール変換 //====================== procedure TForm1.ConvertGray; var PB : Prgbarray; X, Y : Integer; begin for Y := 0 to GHeight - 1 do begin PB := InBitmap.ScanLine[Y]; for X := 0 to GWidth -1 do GrayScale[Y, X] := Round(PB[X].rgbtBlue * kb + PB[X].rgbtGreen * kg + PB[X].rgbtRed * kr); // 輝度変換 end; end; //========================== // モノクロカラーバー 作成 //========================== procedure TForm1.MonoColorBar; var II: Integer; C : Integer; begin for II := 0 to 255 do begin C := II * 256 * 256 + II * 256 + II; Image1.Canvas.Pen.Color := C; Image1.Canvas.MoveTo(II, 0); Image1.Canvas.LineTo(II, 30); end; end; //=============================== // グレイスケール表示 //=============================== procedure TForm1.GrayBtnClick(Sender: TObject); var PB : Prgbarray; X, Y : Integer; begin for Y := 0 to GHeight - 1 do begin PB := OutBitmap.ScanLine[Y]; for X := 0 to GWidth -1 do begin PB[X].rgbtBlue := GrayScale[Y, X]; PB[X].rgbtGreen := GrayScale[Y, X]; PB[X].rgbtRed := GrayScale[Y, X]; end; end; Image3.Canvas.StretchDraw(VRect, OutBitmap); // 出力枠に変倍出力 end; //================================ // 擬似カラー表示 //================================ procedure TForm1.Pseudo_ColorBtnClick(Sender: TObject); var PB : Prgbarray; X, Y : Integer; TC : TColor; begin for Y := 0 to GHeight - 1 do begin PB := OutBitmap.ScanLine[Y]; for X := 0 to GWidth -1 do begin TC := ColorTemp[GrayScale[Y, X]]; PB[X].rgbtBlue := GetBValue(TC); PB[X].rgbtGreen := GetGValue(TC); PB[X].rgbtRed := GetRValue(TC); end; end; Image3.Canvas.StretchDraw(VRect, OutBitmap); // 出力枠に変倍出力 end; //============================ // 元画像表示 //============================ procedure TForm1.SorceBtnClick(Sender: TObject); begin Image3.Canvas.StretchDraw(VRect, InBitmap); // 出力枠に変倍出力 end; //========================= // カラーバー 作成 //========================= procedure TForm1.ColorBar; var II : Integer; begin for II := 0 to 255 do begin Image2.Canvas.Pen.Color := ColorTemp[II]; Image2.Canvas.MoveTo(II, 0); Image2.Canvas.LineTo(II, 30); end; end; //============================ // カラーテンプレート作成 //============================ procedure TForm1.MakeTemp; var II : Integer; R, B, G : Integer; begin for II := 0 to 255 do begin B := 0; // RGB初期化 G := 0; R := 0; if II <= 63 then begin // II 0~63 B := 255; G := II * 4; end; if (II >= 64) and (II <= 127) then begin // II 64~127 B := (255 - (II - 64) * 4); G := 255; end; if (II >= 128) and (II <= 191) then begin // II 128~191 G := 255; R := (II - 128) * 4; end; if (II >= 192) then begin // II 192~255 G := (255 - (II - 192) * 4); R := 255; end; B := B shl 16; // 左シフト16bit G := G shl 8; // 左シフト 8bit ColorTemp[II] := B + G + R; // 三色加算 end; end; //==================================== // 画像ファイルのオープン //==================================== procedure TForm1.FileOpenBtnClick(Sender: TObject); var WIC : TWICImage; InFilename : String; IHeight : Integer; IWidth : Integer; 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; // 画像幅 IWidth := Image3.Width; // 出力先イメージ1の幅 IHeight := Image3.Height; // 出力先イメージ1の高さ if GHeight <= GWidth then begin // 縦横比により出力サイズ設定 IHeight := Round(IWidth * GHeight / GWidth); end else begin IWidth := Round(IHeight * GWidth / GHeight); end; VRect := Rect(0, 0, IWidth, IHeight); // 出力枠設定 InBitmap.Assign(WIC); finally WIC.Free; // TWICImage 解放 end; InBitmap.PixelFormat := pf24bit; Image3.Canvas.StretchDraw(VRect, InBitmap); // 出力枠に変倍出力 setlength(GrayScale, GHeight, GWidth); OutBitmap.PixelFormat := pf24bit; OutBitmap.Height := GHeight; OutBitmap.Width := GWidth; end else Exit; ConvertGray; // グレースケール変換 GrayBtn.Enabled := True; Pseudo_ColorBtn.Enabled := True; SorceBtn.Enabled := True; end; //================= // 初期設定 //================= procedure TForm1.FormCreate(Sender: TObject); var Bitmap : Tbitmap; begin top := (Screen.Height - Height) div 2; left := (Screen.Width - Width) div 2; Image1.Width := 256; Image1.Height := 30; Image2.Width := Image1.Width; Image2.Height := Image1.Height; Image3.Width := 256; Image3.Height := 256; Bitmap := Tbitmap.Create; // 初期化用ビットマップ生成 Bitmap.Width := Image1.Width; Bitmap.Height := Image1.Height; Image1.Picture.Bitmap := Bitmap; Image2.Picture.Bitmap := Bitmap; Bitmap.Free; // 初期化用ビットマップの破棄 Image1.Picture.Bitmap.PixelFormat := pf24bit; Image2.Picture.Bitmap.PixelFormat := pf24bit; MakeTemp; // カラーテンプレート作成 MonoColorBar; // モノクロカラーバー ColorBar; // カラーバー InBitmap := TBitmap.Create; // ビットマップ生成 OutBitmap := TBitmap.Create; GrayBtn.Enabled := False; // ボタンの設定 Pseudo_ColorBtn.Enabled := False; SorceBtn.Enabled := False; end; //================================== // 終了処理 作業用ビットマップの開放 //================================== procedure TForm1.FormDestroy(Sender: TObject); begin InBitmap.Free; OutBitmap.Free; end; end.
カラーテンプレートの作成の簡素化
Delphi Xe3 以降には、HSLtoRGB
の変換メソッドが用意されているので、それを利用すれば簡単に擬似カラーパターンを作成することが出来ます。
変換テンプレートを使用せず、直接変換しても良いのですが、配列のサイズは4バイトデーターを256個用意するだけなのと、高速に擬似カラー化する為にテンプレートを使用するのが一番です。
前記サンプルプログラムの、MakeTemp ルーチンを下記の様に修正すれば、擬似カラーパターンの作成が簡単になります。
Uses節に
System.UITypes, System.UIConsts の追加が必要です。
下記のHsは、値 255 を 色相の240°に変換する為の係数です。
240の値を変更すれば、値 255に対する色相角度を変更することが出来ます。
HSLtoRGB(色相, 彩度, 明度) で、色相の0~360°は 0~1
彩度は 0~1 明度は0~1 で 0.5 が純色となります。
TAlphaColor,HSLToRGBは、FireMonkey
用に追加された物のようですが、VCLでも使用できます。
//============================================================== // カラーテンプレート作成 // Hs は HSLtoRGB 変換時 値255 を 240度赤純色にするための補正値 // TAlphaColorはUsesにSystem.UITypesが // HSLToRGB()にはUsesにSystem.UIConstsが必要です //============================================================== procedure TForm1.MakeTemp; const Hs = 240 / 360 / 255; var II : Integer; C : TAlphaColor; begin for II := 0 to 255 do begin C := HSLToRGB(II * Hs, 1, 0.5); ColorTemp[II] := C and $00FFFFFF; end; end;