2006.9,2.
2006.9.13.追補
2007.1.29.訂正(原画像ファイルの読み込み)
2007.5.13.追補(SetPixelの使い方)
石立 喬
「A:\」のように「\」を使用すると、エスケープシーケンスと認識されてエラーになる場合が時々見られた(常時ではないが不思議)ので、そのような場合には、「\」を省くか、「\」の代わりに「/」や「\\」を用いて欲しい。
「マイ ドキュメント/Visual Studio 2005/Projects/<プロジェクト名>/<プロジェクト名>」に原画像ファイルを置いておけば、フルパス指定の必要はない。
Form上への表示
Imageクラスの画像に対しては、
g->DrawImage(img,X0,Y0);
でForm上に簡単に描画することができる。
Bitmapクラスの画像の場合も、
g->DrawImage(bmap,X0,Y0);
で同様に描画できる。X0とY0は、画像の左上の座標である。
画像の各ピクセルを読み取り、それらをRGB三色に分解する
上述の方法で取得したBitmapクラスの画像bmapをピクセル単位で読み取るには、ピクセル当りのColor構造体を下記のようにして取得し、
Color color=bmap->GetPixel(i,j);
得られたcolorをRGBに分解するには、
r=color.R;
g=color.G;
b=color.B;
を使用する。i、jは画像のX座標、Y座標である。
RGBからColor構造体を生成する
r、g、bのデータからColor構造体のcolorを生成するには、
Color color=Color::FromArgb(r,g,b);
を使用する。
画面上に点を打つ
Visual C++ 6.0では、pdC->SetPixel(x,y,color)が使えたが、Visual
C++ 2005 Express editionでは使えない。代わりに
g->DrawRectangle(pen,x,y,1,1);
で、一辺が長さ1の矩形を描くか(辺の長さを0にすると描画されない)、
g->DrawLine(pen,x,y,x+1,y+1);
で長さ1の線を引く(線の長さを0にする、すなわち、x,y,x,yとすると描画されない)。
これは不便なことで、画像のサイズが少し大きくなる(縦横共に1ピクセル分だけ)欠点がある。
しかし、直接描画するのではなく、
Bitmap^ bmap=gcnew Bitmap(width,height);
bmap->SetPixel(x,y,Color::Black);
g->DrawImage(bmap,X0,Y0;
とすれば、SetPixelが使える。
プログラムの作成方法(念のために)
1)「Visual C++ 2005 Express Edition」統合開発環境で、「ファイル」→「新規作成」→「プロジェクト」を選択する。
2)「新しいプロジェクト」ウインドウで、
プロジェクトの種類 ---- CLR
テンプレート --------- Windowsフォームアプリケーション
プロジェクト名 -------- (任意の名称を入力する)
ソリューションのディレクトリの作成 --- (チェックのついたままにしておく)
として、「OK」をクリックする。
3)「フォームデザイナ」ウインドウが開き、「Form1」だできているので、その中央部で右クリックし、「プロパティ」を選択する。
4)「プロパティ」ウインドウで、
Size ---------- 600,600(後で細かく調整するが、とりあえず)
BackColor ----- Window
Text --------- 色の分解(一例)
と設定する。
5)同じ「プロパティ」ウインドウで、稲妻の描かれた「イベント」アイコンをクリックし、「Paint」をダブルクリックする。
6)「コードエディタ」が開き、Form1_Paintのスケルトンができているので、そこにプログラムを記述する。
ビルドと実行(念のために)
1) 統合開発環境のメニューで、「ビルド」→「(プロジェクト名)のビルド」をクリックする。
2) ビルドが正常終了した場合には、「デバッグ」→「デバッグなしで開始」をクリックする。
プログラムA
以下は、原画像sample.jpgをFDDから読み込み、R、G、Bの各成分を表示するプログラムである。
private: System::Void Form1_Paint(System::Object^ sender, System::Windows::Forms::PaintEventArgs^
e) {
int X0=10,Y0=10;
int X1=340,Y1=10;
int X2=10,Y2=260;
int X3=340,Y3=260;
Color color_src,color_dest;
Byte r,g,b;
Pen^ pen;
Graphics^ gr=e->Graphics;
//原画像のビットマップを生成する
Bitmap^ bmap=gcnew Bitmap("A:sample.jpg");
//原画像を左上に描画する
gr->DrawImage(bmap,X0,Y0);
//原画像をRGBに分解し、表示する
for(int j=0;j<240;j++)
for(int i=0;i<320;i++){
color_src=bmap->GetPixel(i,j);
r=color_src.R;
g=color_src.G;
b=color_src.B;
//R成分
color_dest=Color::FromArgb(r,0,0);
pen=gcnew Pen(color_dest);
gr->DrawRectangle(pen,X1+i,Y1+j,1,1);
//G成分
color_dest=Color::FromArgb(0,g,0);
pen=gcnew Pen(color_dest);
gr->DrawRectangle(pen,X2+i,Y2+j,1,1);
//B成分
color_dest=Color::FromArgb(0,0,b);
pen=gcnew Pen(color_dest);
gr->DrawRectangle(pen,X3+i,Y3+j,1,1);
}
}
プログラムB
以下は、プログラムAの一部を変更し、印刷で使われるCMY系への分解を行った例である。実際には、黒を含むCMYKが使用されるが、ここでは省略した。変更部分のみを示す。
//原画像をYMCに分解し、表示する
for(int j=0;j<240;j++)
for(int i=0;i<320;i++){
color_src=bmap->GetPixel(i,j);
r=color_src.R;
g=color_src.G;
b=color_src.B;
c=255-r;
m=255-g;
y=255-b;
//C成分
color_dest=Color::FromArgb(0,c,c);
pen=gcnew Pen(color_dest);
gr->DrawRectangle(pen,X1+i,Y1+j,1,1);
//M成分
color_dest=Color::FromArgb(m,0,m);
pen=gcnew Pen(color_dest);
gr->DrawRectangle(pen,X2+i,Y2+j,1,1);
//Y成分
color_dest=Color::FromArgb(y,y,0);
pen=gcnew Pen(color_dest);
gr->DrawRectangle(pen,X3+i,Y3+j,1,1);
}
プログラムAで得られた画面
RGBへの分解は、真っ黒のディスプレイ上にそれらを加算して元に戻すので、白い部分は、R、G、Bともに最大の強さとなっている。すなわち、赤、緑、青が共に最も強い部分が白である。

