Visual Studio (VC++) 応用編 (その1)
− USBカメラの画像表示 −
信州大学工学部 井澤裕司
(H18.2.10)
課 題 1
Microsoft Visual Studio2005 の Visual C++ を用いて,以下の機能をもつプログラムを作成しなさい.
MFCアプリケーションのメニュー「
初期設定
」,サブメニューの「
解像度
」 を起動すると,接続したUSBカメラの画素数等の情報を設定するダイヤログが開くので,解像度を「
320×240
」,ピクセルビットを「
RGB24
」に設定する.次に,メニューの「
画像表示
」,サブメミューの「
静止画
」を指定すると,画面上に解像度「
320×240
」のフルカラー静止画像が表示される. |
|
・新規プロジェクト 「 cam_still 」 をシングルダイヤログ形式( SDI )で作成する.
・メニューの 「 表示 」,「 リソースビュー 」 をクリックし,「 Menu 」 の IDR_MAINFRAME を編集する.
・メニューの 「 表示 」,「 リソースビュー 」 をクリックし,「 Menu 」 の IDR_MAINFRAME を編集する.
・Viewクラス 「 Ccam_stillView() 」 の最初に,Video for Windowsのライブラリを呼び出すためのヘッダーファイル「 vfw32.h 」 をインクルードし,定数を定義する「 define文 」 等を追加する.
・デストラクタ「 Ccam_stillView::~Ccam_stillView() 」 の内部に,後処理用(リソースの解放)のコードを追加する.
・デストラクタ「 Ccam_stillView::~Ccam_stillView() 」 の後に,画像キャプチャ終了時に起動するコードを追加する.
・「 Ccam_stillView::PreCreateWindow(CREATESTRUCT& cs) 」 の内部に,描画準備用のコードを追加する.
・メニューの「解像度」に対応する「 OnInit() 」 の内部に,以下に示す初期設定のコードを追加する.
・自動生成された「 OnStillImage() 」 の内部に,以下に示す描画用のコードを追加する.
・メニューの 「 表示 」,「 リソースビュー 」 をクリックし,新しいリソースの 「 Bitmap 」を生成する.
・メニュー「 表示 」の 「 プロパティマネージャ 」,「 構成プロパティ 」 をクリックし,「 プロパティページ 」のダイヤログを開く.
・ 入門(その2) のステップ5〜7に同じ. |
ステップ1. Microsoft Visual Studio2005 を起動する.
- メニューの 「 ファイル 」 から 「 新規作成 」 の 「 プロジェクト 」 を指定します.
ステップ2.
Visual C++ のMFC アプリケーションを立ち上げる.
下の欄のプロジェクト名として,例えば 「 cam_still 」 と入力します.
- プロジェクトの種類から「 Visual C++ 」 の 「 MFC 」 (Microsoft Foundation Class Library) を選択し,右側のテンプレートから 「 MFCアプリケーション 」 を指定します.
ステップ3.
MFC アプリケーション ウィザードに従ってスケルトン(雛形)を生成する.
このウィザードに従って,スケルトンを生成します.
- 「MFCアプリケーション ウィザード 」 は,MFCアプリケーションの雛形を自動生成するツールです.
なお単純化するため,「 アプリケーションの種類 」 は「 シングル ドキュメント 」とし,「 高度な機能 」については,すべての チェックをはずし て下さい.
ステップ4.
メニューのリソースを追加し,イベントハンドラを起動して,ソースファイルを編集する.
4-[a]
以上の手順により,下に示す
MFC アプリケーション
の雛形が完成しました.
4-[b]
メニューの「 表示 」から 「 リソースビュー 」 を指定し,「 cam_still 」 プロジェクトの リソース一覧を表示します.
「 cam_still.rc 」 の「 Menu 」 をクリックし,ファイル一覧を表示します.
なお,一覧が表示されない場合は,上位のフォルダをダブルクリックすると,その下の階層が表示されます.
リソース一覧の中から 「 IDR_MAINFRAME 」 をダブルクリックして,MFC アプリケーションの画面を表示します.
4-[c]
「 ここへ入力 」 の欄の下端にマウスのカーソルを合わせ,左ダブルクリックして,「 初期設定 」 と入力します.
次に,「 初期設定 」 の下の 「 ここへ入力 」 の下端にマウスのカーソルを合わせ,左ダブルクリックして 「 解像度 」 と入力します.
「 解像度 」 の ”右側” ”にマウスのカーソルを合わせ,左ダブルクリックして,「 メニューエディタ 」 を起動します.
なお,メニュー欄の右端にあるアイコン 「 プロパティ ウィンドウ 」 を左クリックしても 「 メニューエディタ」 が開きます.
画面左の「 メニューエディタ 」 の「 ID 」 の欄に,ユニークな名前,例えば,「 ID_INIT 」 を入力します.
4-[d]
「 メニューエディタ 」 を閉じた後,再びサブメニューの 「 解像度 」 にマウスのカーソルを合わせ,今度は ”右” クリックして, 「 イベントハンドラの追加 」 を起動します.
イベント ハンドラ ウィザード 」 のクラス一覧から Viewクラス ,すなわち 「 Ccam_stillView 」 を選択して,「 追加して編集 」 を起動します.
なお,「 メッセージ 」 の欄は 「 COMMAND 」 の状態で結構です.
4-[e]
「 イベント ハンドラ ウィザード 」 により, Viewクラス の中に,新規メニューに対応する新しいクラス 「 OnInit() 」 が自動的に生成されます .
4-[f]
同様にして,今度は表示系のメニューを追加します.
「 ここへ入力 」 の欄の下端にマウスのカーソルを合わせ,左ダブルクリックして,「 画像表示 」 と入力します.
次に,「 画像表示 」 の下の 「 ここへ入力 」 の下端にマウスのカーソルを合わせ,左ダブルクリックして 「 静止画 」 と入力します. 「 静止画 」 の ”右側” ”にマウスのカーソルを合わせ,左ダブルクリックして,「 メニューエディタ 」 を起動します.
なお,メニュー欄の右端にあるアイコン 「 プロパティ ウィンドウ 」 を左クリックしても 「 メニューエディタ」 が開きます.
画面左の「 メニューエディタ 」 の「 ID 」 の欄に,ユニークな名前,例えば,「 ID_STILL_IMAGE 」 を入力します.
4-[g]
「 メニューエディタ 」 を閉じた後,再びサブメニューの 「 静止画 」 にマウスのカーソルを合わせ,今度は ”右” クリックして, 「 イベントハンドラの追加 」 を起動します.
イベント ハンドラ ウィザード 」 のクラス一覧から Viewクラス ,すなわち 「 Ccam_stillView 」 を選択して,「 追加して編集 」 を起動します.
なお,「メッセージ 」 の欄は 「 COMMAND 」 の状態で結構です.
「 イベント ハンドラ ウィザード 」 により, Viewクラス の中に,新規メニューに対応する新しいクラス 「 OnStillImage() 」 が自動的に生成されます .
ステップ5.
ソースファイルを編集する.
5-[a]
Viewクラス 「 Ccam_stillView() 」 の最初に,Video for Windowsのライブラリを呼び出すためのヘッダーファイル「 vfw32.h 」 をインクルードし,定数を定義する「 define文 」 等を追加します.
‥(略)‥
#include "cam_stillView.h"
#include "vfw.h" // 追加したヘッダーファイル
#include "winbase.h" // 追加したヘッダーファイル
#define X_SIZE 320 // 水平画素数
#define Y_SIZE 240 // 垂直画素数
#define COLOR 4 // 色(RGB(A) 4 Byte)
static unsigned char image[Y_SIZE][X_SIZE][COLOR];
CDC m_memDC; // メモリDC
HBITMAP m_hBitmap = NULL; // DIB Section
BITMAPINFOHEADER* m_lpImage = NULL;
static BYTE* m_lpData = NULL; // RGBデータ
HWND m_hCapWnd = NULL;
int size; // データサイズ
BOOL dispFlag = FALSE; // 表示終了フラグ
BITMAPINFOHEADER* GetDIBHeader(){
// DIB(Device Independent BMP)のヘッダ
return m_lpImage;
}
BOOL CreateDIBHeader(int size){ // DIB(Device Independent BMP)のヘッダ作成
m_lpImage = (BITMAPINFOHEADER*)malloc(size);
return (m_lpImage != NULL);
}
以下にその編集画面を示します.
5-[b]
デストラクタ「 Ccam_stillView::~Ccam_stillView() 」 の内部に,後処理用(リソースの解放)のコードを追加します.
Ccam_stillView::~Ccam_stillView()
{
capDriverDisconnect( m_hCapWnd );
::DestroyWindow( m_hCapWnd );
m_lpData = NULL;
free( m_lpImage );
m_lpImage = NULL;
DeleteDC( m_memDC );
DeleteObject( m_hBitmap );
}
以下にその編集画面を示します.
5-[c]
デストラクタ「 Ccam_stillView::~Ccam_stillView() 」 の後に,画像キャプチャ終了時に起動するコードを追加します.
static LRESULT FAR PASCAL CaptureImage(HWND hWnd,LPVIDEOHDR lpVHdr)
{
memcpy(m_lpData, (LPSTR)lpVHdr->lpData, m_lpImage->biSizeImage);
dispFlag = TRUE;
return (LRESULT)TRUE;
}
以下にその編集画面を示します.
5-[d]
「 Ccam_stillView::PreCreateWindow(CREATESTRUCT& cs) 」 の内部に,描画準備用のコードを追加します.
BOOL Ccam_stillView::PreCreateWindow(CREARESTRCT& cs)
{
dispFlag = FALSE;
m_hCapWnd = capCreateCaptureWindowA("cam_still", WS_OVERLAPPEDWINDOW,
0, 0, X_SIZE, Y_SIZE, NULL, NULL);
capDriverConnect(m_hCapWnd, 0);
capSetCallbackOnFrame( m_hCapWnd, CaptureImage);
size = capGetVideoFormatSize(m_hCapWnd);
CreateDIBHeader(size);
m_lpImage = GetDIBHeader();
capGetVideoFormat(m_hCapWnd, m_lpImage, size);
// DIBsectionの確保
m_hBitmap = CreateDIBSection( m_memDC.GetSafeHdc(), (BITMAPINFO*)m_lpImage,
DIB_RGB_COLORS, (void**)&m_lpData, NULL, 0 );
return CView::PreCreateWindow(cs);
}
以下にその編集画面を示します.
5-[e]
メニューの「解像度」に対応する「 OnInit() 」 の内部に,以下に示す描画用のコードを追加します.
void Ccam_stillView::OnInit()
{
capDlgVideoFormat(m_hCapWnd);
size = capGetVideoFormatSize(m_hCapWnd);
CreateDIBHeader(size);
m_lpImage = GetDIBHeader();
capGetVideoFormat(m_hCapWnd, m_lpImage, size);
m_hBitmap = CreateDIBSection( m_memDC.GetSafeHdc(),(BITMAPINFO*)m_lpImage,
DIB_RGB_COLORS, (void**)&m_lpData, NULL, 0 );
}
以下にその編集画面を示します.
5-[f]
自動生成された「 OnStillImage() 」 の内部に,以下に示す描画用のコードを追加します.
CClientDC dc(this);
CDC pM;
CBitmap pB, *pOld;
int ix, iy;
BYTE *m_lpData2;
dispFlag = FALSE;
capGrabFrame( m_hCapWnd ); // キャプチャ開始のコマンド
while( dispFlag == FALSE) { } // キャプチャ終了まで待つ
m_lpData2 = (BYTE*)m_lpData; // 画像メモリのポインタ
for( iy = 0; iy < Y_SIZE; iy++){
for( ix = 0; ix < X_SIZE; ix++){
image[ Y_SIZE-1-iy ][ ix ][ 0 ] = *m_lpData2; m_lpData2++; // Blue データは上下が反転している
image[ Y_SIZE-1-iy ][ ix ][ 1 ] = *m_lpData2; m_lpData2++; // Green このため上下を入れ替える
image[ Y_SIZE-1-iy ][ ix ][ 2 ] = *m_lpData2; m_lpData2++; // Red
}
}
pB.LoadBitmap( IDB_BITMAP1 ); // ビットマップ(IDB_BITMAP1)を処理用オブジェクト(pB)に読み込む
pM.CreateCompatibleDC( &dc ); // 互換性のある作業用デバイスコンテキストの作成
SetBitmapBits( pB, X_SIZE * Y_SIZE * COLOR, &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 ); // もとのビットマップに戻す
以下にその編集画面を示します.
ステップ6. 描画用リソース 「BITMAP」 の生成.
6-[a]VC++のメニュー 「 表示 」,「 リソースビュー 」 を左クリックして「 リソースの一覧 」を表示します.
「 リソースビュー 」 にマウスのカーソルを置き,右クリックして「 リソースの追加 」 を選択します.
6-[b]
「 ソースの追加 」,から「 Bitmap 」 を選択します.
新しい「 Bitmap 」が生成されました.
IDの名称は,「 IDB_BITMAP1 」 となり,自動的に番号が付加されます.
なお後ほど補足しますが,ユーザで指定することも可能です.
「 IDB_BITMAP1 」 を右クリックして,その「 プロパティ 」 を開きます.
「 リソースビュー 」の右の白い空欄にカーソルを置いて右クリックすると, 「 ビットマップエディタ 」が開き,詳細な「 プロパティ 」 が表示されます.
「 プロパティ 」に新たに 「 位置 」の項目が追加されますので,その「 Height 」 を 「 240 」 , 「 Width 」 を 「 320 」 という値に変更します.
さらに 「 表示 」の 「 Color 」の項目が追加されますので,その内容を 「 Trueカラー 」 に修正します.
ステップ7. Video for Windows のライブラリ 「vfw32.lib」 のリンク設定.
7-[a]メニュー「 表示 」の 「 プロパティマネージャ 」 をクリックします.
7-[b]
「 プロパティマネージャ 」のアイコンをダブルクリックし,「 構成プロパティ 」 を開きます.
画面左の「 構成プロパティ 」から「 リンカ 」,「 入力 」を選択して,右側の「 追加の依存ファイル 」の欄に「 vfw32.lib 」と入力します.
ステップ8. ソースコードのコンパイル(ビルド ・ リビルド).
VC++のメニュー 「 ビルド 」,「 ソリューションのビルド 」 をクリックして コンパイル(ビルド) します.
エラーが表示されたら,該当する箇所を修正します.
ステップ9. 作成したプログラムの実行
VC++ の メニュー「 デバッグ 」 の 「 デバッグなしで開始 」 をクリックして,作成したプログラムを実行します.
ステップ10. 作成したプログラムの実行
VC++ の メニュー「 デバッグ 」 の 「 デバッグなしで開始 」 をクリックして,作成したプログラムを実行します.
ステップ11 プログラムの実行結果(1)
メニュー「 初期設定 」 の下の サブメニュー「 解像度 」 をクリックします.
以下のような解像度設定用のダイヤログが表示されます.
「 解像度 」 を「 320×240 」 ,ピクセル深度を「 RBG24 」 に設定します.
ステップ12 プログラムの実行結果(2)
メニュー「 画像表示 」 の下にあるサブメニュー「 静止画 」 をクリックすると,USBカメラで撮影した静止画像がフルカラーで表示されます.
本編では,VC++を用いて,USBカメラの画像をキャプチャし,画面上に表示する方法について紹介しました.
説明に用いたプログラムでは,1枚の静止した画像が表示されますが,作成したクラスの中で for文などを用いてループを構成することにより,動画像に拡張することも可能です.
その場合は,ループする回数をダイヤログで入力する部分を追加すると良いでしょう.
なお,動画像のフレームレートは,USBカメラの性能や表示する画素数,パソコンの性能等により変わります.
また,初期設定のメニューで,USBカメラの解像度を選択する方法を用いていますが,USBカメラの種類によっては,正常に設定されないことがあります.
この場合は,USBカメラに添付するアプリケーションソフトや,Windowsのソフトウェア等を用いて,解像度を「320×240」に設定して下さい.
第2章では,静止画像ファイルを生成・表示するプログラムの実習を行います.