Visual Studio (VC++) 入門 (その4)


− 画像の表示方法 −


信州大学工学部 井澤裕司

(H18.1.30)


課  題 4

Microsoft Visual Studio2005 の Visual C++ を用いて、以下の機能をもつプログラムを作成しなさい.

MFCアプリケーションのメニュー「 描画 」,サブメニューの「 ゾーンプレート 」 を起動すると,中心からの距離に比例して,空間周波数が高くなる同心円状の縞模様,すなわちゾーンプレート 」が画面上に表示される.

図形の表示という点では,「課題2」と同じですが,ゾーンプレートのような「2次元画像」を高速に表示するためには,2次元配列をビットマップに変換して表示する方法が有効です.この課題では,その具体的な方法を修得します.


このコンテンツの中で,Visual C++ の使用法を詳細に説明することは困難です. Visual C++については、以下のような書籍が出版されていますので,参考にして下さい.
   ・Visual C++ 2005 ビギナー編
        林 晴彦 Softbank Creative
 
WEB上には 以下のようなサイトがあります.
 
   ・[Visual C++の使い方]
          http://www.nitoyon.com/vc/
   ・[Visual C++の勉強部屋]
          http://homepage3.nifty.com/ishidate/vcpp.htmvc/
   ・[Area of VC++ Tips]
          http://rararahp.cool.ne.jp/vc/vctips/tipindex.htm
 
手順の概略を以下に示します.
なお手順の (5) 以外 は 資料 「VC++入門(その2)」 と同じです.
(1) プロジェクト( Zone_plate )の新規作成
・新規プロジェクト 「 Zone_plate 」 をシングルダイヤログ形式( SDI )で作成する.

・手順は
入門(その1) のステップ1〜3と同じ.
(2) メニューの 新規作成
・メニューの 「 表示 」,「 リソースビュー 」 をクリックし,「 Menu 」 の IDR_MAINFRAME を編集する.

・新しいメニューとして,例えば
描画 」 を作成し,その下の サブメニュー を,例えば 「 ゾーンプレート 」 のように作成する.

・作成したサブメニュー「
ゾーンプレート 」 をダブルクリック(左)するか,メニューの右上にあるアイコンの 「 プロパティ ウィンドウ 」 を左クリックして,メニューエディタを起動し,リストの項目 ID を例えば 「 ID_ZONE_PLATE 」 のように設定する. 

・リソースのサブメニュー「
リサージュ 」 にマウスのカーソルを合わせ,マウスを ”右” クリックして,「 イベント ハンドラの追加 」 を起動する.

・メッセージの種類を 「
COMMAND 」 ,クラスの一覧の中から 「 CZone_plateView 」 を選択し,「 追加して編集 」 のボタンをクリックする.

イベントハンドラ ウィザード により View クラスの中に 新たなクラス 「 OnZone_plate() 」 が自動生成され,自動的にエディタのモードに移行する.
(3)  Viewクラス 「 CZone_plateView 」 の編集 (1)
・Viewクラス 「 CZone_plateView 」 の最初に,サイン,コサインなどの数値演算ライブラリを呼び出すためのヘッダーファイル 「 math.h 」 をインクルードし,定数を定義する「 define文 」 を追加する.

‥(略)‥
#include   "Zone_plateView.h"

#include   "math.h"       // 追加したヘッダーファイル

#define X_SIZE 256       // 追加した定数
#define Y_SIZE 256       // 追加した定数
#define PI    3.1415926   // 追加した定数

(4)   Viewクラス 「 CZone_plate 」 の編集 (2)
・自動生成された「 OnZone_plate() 」 の内部に,以下に示す描画用のコードを追加する.


CClientDC   dc(this);
CDC       pM;
CBitmap        pB, *pOld;
int        ix, iy;
double     x, y;
double     r;

unsigned char    image[ Y_SIZE ][ X_SIZE ][ 4 ];
unsigned char    pixel;


for( iy = 0; iy < Y_SIZE; iy++){

    for( ix = 0; ix < X_SIZE; ix++){
       x = 128.0 - (double) ix;
       y = 128.0 - (double) iy;
       r = sqrt(x * x + y * y);
       pixel = (unsigned char) (128.0 + 100.0 * sin( PI * r * r / 256.0 ));
       image[ iy ][ ix ][ 0 ] = pixel;   // Blue
       image[ iy ][ ix ][ 1 ] = pixel;   // Green
       image[ iy ][ ix ][ 2 ] = pixel;   // Red
    }
}


pB.LoadBitmap( IDB_BITMAP1 );

pM.CreateCompatibleDC( &dc );
SetBitmapBits( pB, X_SIZE * Y_SIZE * 4, &image);

pOld = pM.SelectObject ( &pB );
dc.BitBlt (50, 50, X_SIZE, Y_SIZE, &pM, 0, 0, SRCCOPY);
pM.SelectObject( pOld );
(5)   描画用リソース 「 Bitmap 」 の生成
・メニューの 「 表示 」,「 リソースビュー 」 をクリックし,新しいリソースの 「 Bitmap 」を生成する.

・「 Bitmap 」のプロパティを開き,縦横の画素数をともに256に設定し,色の設定を「 Trueカラー 」とする.
(6) コンパイル , デバッグ および 実行
入門(その2) のステップ5〜7に同じ.


ステップ1. Microsoft Visual Studio2005 を起動する.

メニューの 「 ファイル 」 から 「 新規作成 」 の 「 プロジェクト 」 を指定します.
  

ステップ2. Visual C++ のMFC アプリケーションを立ち上げる.

プロジェクトの種類から「 Visual C++ 」 の 「 MFC 」 (Microsoft Foundation Class Library) を選択し,右側のテンプレートから 「 MFCアプリケーション 」 を指定します.
下の欄のプロジェクト名として,例えば 「 Zone_plate 」 と入力します.


ステップ3. MFC アプリケーション ウィザードに従ってスケルトン(雛形)を生成する.

MFCアプリケーション ウィザード 」 は,MFCアプリケーションの雛形を自動生成するツールです.
このウィザードに従って,スケルトンを生成します.
なお単純化するため,「
アプリケーションの種類 」 は「 シングル ドキュメント 」とし,「 高度な機能 」については,すべての チェックをはずし て下さい.

ステップ4. メニューのリソースを追加し,イベントハンドラを起動して,ソースファイルを編集する.

4-[a]
     以上の手順により,下に示す MFC アプリケーション の雛形が完成しました.



4-[b]

メニューの「 表示 」から 「 リソースビュー 」 を指定し,「 Zone_plate 」 プロジェクトの リソース一覧を表示します.
Zone_plate.rc 」 の「 Menu 」 をクリックし,ファイル一覧を表示します.

なお,一覧が表示されない場合は,上位のフォルダをダブルクリックすると,その下の階層が表示されます.

リソース一覧の中から 「 IDR_MAINFRAME 」 をダブルクリックして,MFC アプリケーションの画面を表示します.




4-[c]


ここへ入力 」 の欄の下端にマウスのカーソルを合わせ,左ダブルクリックして,「 描画 」 と入力します.
次に,「 描画 」 の下の 「 ここへ入力 」 の下端にマウスのカーソルを合わせ,左ダブルクリックして 「 ゾーンプレート 」 と入力します.




4-[d]

ゾーンプレート 」 の ”右側” ”にマウスのカーソルを合わせ,左ダブルクリックして,「 メニューエディタ 」 を起動します.
なお,メニュー欄の右端にあるアイコン 「
プロパティ ウィンドウ 」 を左クリックしても メニューエディタ」 が開きます.

画面左の「 メニューエディタ 」 の「 ID 」 の欄に,ユニークな名前,例えば,「 ID_ZONE_PLATE 」 を入力します.





4-[e]

メニューエディタ 」 を閉じた後,再びサブメニューの 「 ゾーンプレート 」 にマウスのカーソルを合わせ,今度は ”右” クリックして, 「 イベントハンドラの追加 」 を起動します.

イベント ハンドラ ウィザード 」 のクラス一覧から Viewクラス ,すなわち 「 CZone_plateView 」 を選択して,「 追加して編集 」 を起動します.
なお,「
メッセージ 」 の欄は 「 COMMAND 」 の状態で結構です.




4-[f]

    「 イベント ハンドラ ウィザード 」 により, Viewクラス の中に,新規メニューに対応する新しいクラス 「 OnZone_plate() 」 が自動的に生成されます





ステップ5. ソースファイルを編集する.

5-[a]

追加したソースコードの中で,「サイン(sin) 関数」を 数値演算ライブラリから呼び出すため,
Zone_plateViewクラス の先頭に,ヘッダーファイル 「 math.h 」 をインクルードし,定数をdefine文で定義します.


#include   "Zone_plateView.h"

#include   "math.h"        // 追加したヘッダーファイル

#define   X_SIZE   256     // 追加した定数
#define   Y_SIZE   256     // 追加した定数

#define   PI      3.1415926  // 追加した定数

5-[b]

次に,ゾーンプレートを表示するソースコードを作成します.
新しく生成したクラス 「 OnZone_plate() 」 の中に以下のソースコードを追加します.

CClientDC   dc(this);
CDC       pM;
CBitmap        pB, *pOld;
int        ix, iy;
double     x, y;
double     r;

unsigned char    image[ Y_SIZE ][ X_SIZE ][ 4 ];
unsigned char    pixel;


for( iy = 0; iy < Y_SIZE; iy++){

    for( ix = 0; ix < X_SIZE; ix++){
       x = 128.0 - (double) ix;
       y = 128.0 - (double) iy;
       r = sqrt(x * x + y * y);
       pixel = (unsigned char) (128.0 + 100.0 * sin( PI * r * r / 256.0 ));
       image[ iy ][ ix ][ 0 ] = pixel;   // Blue
       image[ iy ][ ix ][ 1 ] = pixel;   // Green
       image[ iy ][ ix ][ 2 ] = pixel;   // Red
    }
}

pB.LoadBitmap( IDB_BITMAP1 );
                    // ビットマップ(IDB_BITMAP1)をpB(処理用オブジェクト) に読み込む
pM.CreateCompatibleDC( &dc );                  // 互換性のある作業用デバイスコンテキストの作成
SetBitmapBits( pB, X_SIZE * Y_SIZE * 4, &image);      // pB(処理用オブジェクト) にサイズ等のパラメータをセットする
pOld = pM.SelectObject ( &pB );                  // pB(処理用オブジェクト)をメモリ(pM)に展開し,古いビットマップをpOldに保存する
dc.BitBlt (50, 50, X_SIZE, Y_SIZE, &pM, 0, 0, SRCCOPY);  // メモリ(pM)のビットマップイメージを表示用デバイスコンテキストに転送する
pM.SelectObject( pOld );                      // もとのビットマップに戻す

ここで 「 SetBitmapBits 」 では, pB オブジェクト のパラメータ(サイズ等)をセットしますが,「 X_SIZE * Y_SIZE * 4 」の「 4 」は,Windowsの画面の色が「 32bit(4Byte) 」であることを示しています.
もし,画面の色が「 24bit(3Byte) 」の場合は,「 3 」に修正する必要がありますので,注意が必要です.
 「 SelectObject 」 では,pB オブジェクトのデータを,メモリ上の pM に展開します.
また, 「 BitBlt 」 は,pMの座標(0,0)を基点とする画像データを,dcの座標(50,50)を基点とする幅(X_SIZE),高さ(Y_SIZE)の矩形領域に,そのまま(SRCCOPY)コピーすることを意味します.

以下にその編集画面を示します.




ステップ6. 描画用リソース 「BITMAP」 の生成.

6-[a]
VC++のメニュー 「 ビルド 」,「 リソースビュー 」 を左クリックして「 リソースの一覧 」を表示します.
リソースビュー 」 にマウスのカーソルを置き,右クリックして「 リソースの追加 」 を選択します.



6-[b]

ソースの追加 」,から「 Bitmap 」 を選択します.


6-[c]
新しい「 Bitmap 」が生成されました.
IDの名称は,「
IDB_BITMAP1 」 となり,自動的に番号が付加されます.
なお後ほど補足しますが,ユーザで指定することも可能です.



6-[d]
IDB_BITMAP1 」 を右クリックして,その「 プロパティ 」 を開きます.




6-[e]
プロパティ 」の右の白い空欄にカーソルを置いて右クリックすると, ビットマップエディタ 」が開き,詳細な「 プロパティ 」 が表示されます.



6-[f]
プロパティ 」に新たに 位置 」の項目が追加されますので,その「 Height 」 と 「 Width 」 の欄をともに 「 256 」 という値に変更します.




6-[g]
さらに 「 表示 」の Color 」の項目が追加されますので,その内容を 「 Trueカラー 」 に修正します.


以上で, 「 Bitmap 」 に関連する リソース 」 の修正は完了しました.

ステップ7. ソースコードのコンパイル(ビルド ・ リビルド).

VC++のメニュー 「 ビルド 」,「 ソリューションのビルド 」 をクリックして コンパイル(ビルド) します.
エラーが表示されたら,該当する箇所を修正します.



ステップ8. 作成したプログラムの実行

VC++ の メニュー「 デバッグ 」 の 「 デバッグなしで開始 」 をクリックして,作成したプログラムを実行します.




ステップ9. プログラムの実行結果

画面上に同心円上の「 ゾーンプレート 」 が表示されます.



まとめ
以上,VC++を用いて,ゾーンプレートを表示する方法について紹介しました.

何度も繰り返しますが,VC++の全体構造や各ソースコードの意味を理解することは容易ではありません.
何回も繰り返すことにより,とにかく慣れて下さい.
新しいプロジェクトを作ることが苦にならなくなってきたら,しめたものです.
試しに,「ファイル操作」や「データ入出力のインタフェース」等を追加してみて下さい.

そのとき,パソコンが「オシロスコープ」や「データレコーダ」,「アルゴリズムの開発と検証」等をすべてこなす万能ツールとして活用でき,新しいシステムの開発が大幅に効率化されることが実感できるものと思います.