例題として、ビットマップ全体にエフェクトを掛けるというプログラムを考えてみます。
機能としては単純に、画像を1ピクセルずつ読み込んで赤・青・緑(RGB)を取り出し、選択された色だけを取り出して表示するというものです。
イメージとして下のような感じです。
→→ 特定色を取り出して表示 |
ピクセル操作ということで、最も基本的なのはTCanvasクラスのPixelsプロパティを使ってプログラミングすることでしょう。
Pixels[x,y]は2次元配列で、x,yの添字がビットマップの座標として扱え、取得も変更もできて非常に便利です。
上の様な処理でも、10数行のプログラミングで実現できます。実際のコーディングを示します。
//*********** Pixels[] 使用ルーチン *********** procedure TForm1.btnPixClick(Sender: TObject); var x, y: Integer; Color: TColor; R, G, B: Byte; begin //***** 24Bitカラーにする Image1.Picture.Bitmap.PixelFormat := pf24bit; Tmstart; for y := 0 to Image1.Height -1 do begin for x := 0 to Image1.Width -1 do begin Color := Image1.Canvas.Pixels[x, y]; //***** R,G,Bに分解 //***** バイトの並びは B->G->R R := (Color and $0000FF); G := (Color and $00FF00) div $100; B := (Color and $FF0000) div $10000; if not chkR.Checked then R := 0; if not chkG.Checked then G := 0; if not chkB.Checked then B := 0; Image1.Canvas.Pixels[x, y] := Rgb(R, G, B); end; end; Tmend; end; |
まず、
Image1.Picture.Bitmap.PixelFormat := pf24bit;
で、画像のフォーマットを24ビットにしています。これは、RGBの3色X8ビットとして扱いやすくするためです。
実際にピクセル色を取り出すのは、TColor型で定義したColorという変数へ、
Color := Image1.Canvas.Pixels[x, y];
と、座標を直接指定するだけです。ただし、ここで得られる色(TColor型)は4バイトで、下位3バイトにRGBの色成分が入ってのですが、データは下位から順番にR→G→Bと入ってることに注意しなければいけません。
例えば、真っ赤な色は$0000FFで、青い色は$FF0000と入ってきますので、取り出すのも下位(右)から1バイトずつ取り出す必要があるのです。ビットマスクは説明するまでもないですね。
R := (Color and $0000FF);
G := (Color and $00FF00) div $100;
B := (Color and $FF0000) div $10000;
次にチェックボックスでチェックされていない色を0として、選択色だけを取り出します。
if not chkR.Checked then R := 0;
画像に結果を表示するには、取り出した時と逆に
Image1.Canvas.Pixels[x, y] := Rgb(R, G, B);
と、セットします。ただし、Rgb関数で色成分を結合する必要があります。
TmstartとTmendはこの処理の時間を計るプロシージャです。
では、実際にPixels[]ボタンを押して実行してみましょう。
処理に掛かった時間がミリ秒単位でメッセージで表示されます。私の環境(Pentium2/300MHz)では、約3秒掛かりました。
画像は240x320のサイズですが、満足いくスピードとはいえませんね。では、このプログラムを速くすることを考えてみましょう。