株式会社インデペンデンスシステムズ横浜

システム開発エンジニアの西田五郎が運営しております。Raspberry Pi や Arduino その他新規開発案件のご依頼をお待ちしております。

OpenCV

OpenCVをWin32ベースで利用する(その5)GUIコントロールの追加

投稿日:2014年11月16日 更新日:

OpenCVをWin32ベースで利用するの5回目です。前回の4回目で一度終了したのですが、画面上の入出力用のコントロール、つまり、ラベル、エディット、コンボ等のコントロールがなかったので追加してみました。その今回のサンプルプログラムの画面は以下です。

0001

内容としては、OpenCVをWin32ベースで利用する(その1)ダイアログベースアプリ で作成したものとほぼ同じですが、入出力用のコントロールを追加しました。OpenCVのプログラムを作成する場合はやはりパラメータの数値、例えば、しきい値といった数値を画面から入力出来た方がいいです。ただ今回はWin32ベースなので例えば .NETベースのC#と比較してプログラミングが面倒であるとか、VC++のExpress Editionですとリソースエディタが使いない等の理由で最初はボタン以外の入出力のコントロールは実装していなかったですが今回作ってみました。ソース全体は以下からダウンロード出来ます。OpenCVはまだ含まれていません。(※必要な場合は用途に限らずご利用頂いて問題ありませんが、一切無保証です。弊社は一切の責任を負いません。)
今回のソースファイル一式

(※2015.04.24追記)
以下で、Visual Studio Community 2013のVisual C++で同様のプログラムを作成しました。
Visual Studio Community 2013のVisual C++でOpenCVを使う

ここからプログラムの説明です。
まず、Win32APIプログラミングですが、その1の回で書いた通りで言ってみれば古くさいプログラミング方法です。まあそれはそれとして以下のような特徴があります。

コントロール(GUI)を構成するすべての部品がWindowとして存在する。
それぞれのWindowにWindowハンドルがあってそのハンドルの変数で操作をする。
Windowを操作するにはメッセージのやり取りを行う。

今回のプログラムのコントロールの操作も上記のようなプログラムになっています。

実際のコントロールはリソースファイルとして定義しています。以下がそのファイルです。

IDD_MAIN_DIALOG DIALOGEX 0, 0, 720, 400
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Win32 Dialog OpenCV"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    DEFPUSHBUTTON   "読み込み",ID_READ,620,10,80,20
    DEFPUSHBUTTON   "保存",ID_SAVE,620,32,80,20
    DEFPUSHBUTTON   "値取得1",ID_EXEC1,620,62,80,20
    DEFPUSHBUTTON   "処理2",ID_EXEC2,620,85,80,20
    DEFPUSHBUTTON   "処理3",ID_EXEC3,620,108,80,20
    DEFPUSHBUTTON   "処理4",ID_EXEC4,620,132,80,20
    DEFPUSHBUTTON   "処理5",ID_EXEC5,620,156,80,20
    PUSHBUTTON      "終了",ID_CLOSE,619,188,80,20
    CONTROL         "",IDC_PICTURE,"Static",SS_BLACKFRAME,1,1,600,380
    LTEXT           "テキスト1",IDC_STATIC_TEXT1,622,219,80,8
    LTEXT           "テキスト2",IDC_STATIC_TEXT2,622,234,80,8
    EDITTEXT        IDC_EDIT1,659,249,54,14,ES_AUTOHSCROLL
    LTEXT           "エディット1",IDC_STATIC,622,252,32,8
    EDITTEXT        IDC_EDIT2,659,266,54,14,ES_AUTOHSCROLL
    LTEXT           "エディット2",IDC_STATIC,621,269,32,8
    CONTROL         "チェックボックス1",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,622,290,63,10
    CONTROL         "チェックボックス2",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,622,304,63,10
    COMBOBOX        IDC_COMBO1,659,319,51,60,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP
    LTEXT           "コンボ",IDC_STATIC_COMBO,621,322,32,9
    CONTROL         "",IDC_SLIDER1,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,617,355,100,15
    LTEXT           "スライダー",IDC_STATIC_SL,647,372,32,9
    LTEXT           "スライダー",IDC_STATIC_SL2,621,343,32,9
END

ここでのIDの定義がResource.hにあります。以下は一部です。

#define IDC_PICTURE                     1003
#define IDC_EDIT1                       1004
#define IDC_EDIT2                       1005
#define IDC_CHECK1                      1006
#define IDC_CHECK2                      1007
#define IDC_COMBO1                      1008
#define IDC_SLIDER1                     1009
#define IDC_STATIC_TEXT1                1101
#define IDC_STATIC_TEXT2                1102
#define IDC_STATIC_COMBO                1103
#define IDC_STATIC_SL                   1104
#define IDC_STATIC_SL2                  1105
#define IDC_STATIC                      -1

これらの編集方法は、その1の回で書いた通りですが、注意点があります。それは、「画面の大きさはピクセル単位ではない」ということです。フォントの大きさがベースになっているようでフォントの大きさを変えると画面の大きさが変わります。最初にフォントを決めてから画面を定義した方がいいと思います。

プログラムでの操作です。以下が初期化処理です。必要な場合は、変数の定義部分等のソース全体はお手数ですが、ダウンロードをして参照して下さい。

/*----------------------------------------------
コントロール初期化
-----------------------------------------------*/
void initialControls(HWND hDlg)
{
	InitCommonControls();

	 //テキスト初期化
	SetDlgItemText(hDlg, IDC_STATIC_TEXT1, "テキスト初期化1");
	SetDlgItemText(hDlg, IDC_STATIC_TEXT2, "テキスト初期化2");

	//エディット
	SetDlgItemText(hDlg, IDC_EDIT1, "0");
	SetDlgItemText(hDlg, IDC_EDIT2, "1");

	//チェックボックス
	SendMessage(GetDlgItem(hDlg, IDC_CHECK1), BM_SETCHECK, BST_CHECKED, 0);
	SendMessage(GetDlgItem(hDlg, IDC_CHECK2), BM_SETCHECK, BST_CHECKED, 0);

	//コンボボックス
	UINT i;
	WPARAM index;
	hCombo = GetDlgItem(hDlg, IDC_COMBO1);

	// コンボボックスにデータを詰めていく
	for (i = 0; i < 3; i++)
	{
		SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)strItem[i]);
	}
	// ウインドウ生成時にはじめに表示するデータを指定
	index = SendMessage(hCombo, CB_FINDSTRINGEXACT, -1, (LPARAM)TEXT("選択1"));
	SendMessage(hCombo, CB_SETCURSEL, index, 0);

	//スライダー
	hBar = GetDlgItem(hDlg, IDC_SLIDER1);
	Pos = 10;

	SendMessage(hBar, TBM_SETRANGE, TRUE, MAKELPARAM(0, 100)); // レンジを指定
	SendMessage(hBar, TBM_SETTICFREQ, 5, 0);   // 目盛りの増分
	SendMessage(hBar, TBM_SETPOS, TRUE, Pos);  // 位置の設定
	SendMessage(hBar, TBM_SETPAGESIZE, 0, 5); // クリック時の移動量
	sprintf(strBar, TEXT("%d %"), Pos);
	SetWindowText(GetDlgItem(hDlg, IDC_STATIC_SL), (LPCTSTR)strBar);
}

コントロールから値を取得する処理が以下です。ここでは取得しているだけです。値の確認はデバッガで確認しました。

/*----------------------------------------------
コントロール入力取得
-----------------------------------------------*/
void getControlValues(HWND hDlg)
{
	//エディット
	GetDlgItemText(hDlg, IDC_EDIT1, (LPTSTR)szBufEdit1, (int)sizeof(szBufEdit1));
	GetDlgItemText(hDlg, IDC_EDIT2, (LPTSTR)szBufEdit2, (int)sizeof(szBufEdit2));

	//チェックボックス
	bCheck1 = SendMessage(GetDlgItem(hDlg, IDC_CHECK1), BM_GETCHECK, 0, 0);
	bCheck2 = SendMessage(GetDlgItem(hDlg, IDC_CHECK2), BM_GETCHECK, 0, 0);

	//コンボ
	hCombo = GetDlgItem(hDlg, IDC_COMBO1);
	comNo = (UINT)SendMessage(hCombo, CB_GETCURSEL, 0, 0);

	//スライダーは、変数のPosの値
}

スライダーの処理は以下です

	case WM_HSCROLL:

		//スライダーの値取得
		if (GetDlgItem(hBar, IDC_SLIDER1) == (HWND)lParam){
			hBar = GetDlgItem(hDlg, IDC_SLIDER1);
		}

		Pos = SendMessage(hBar, TBM_GETPOS, NULL, NULL); // 現在の値の取得

		sprintf(strBar, TEXT("%d %"), Pos);
		SetWindowText(GetDlgItem(hDlg, IDC_STATIC_SL), (LPCTSTR)strBar);

		break;

ここではこういった書き方で使えますという程度にしておきます。もしより詳細が必要な場合はページ最後のの関連リンクのサイトや関連書籍を参照して頂ければと思います。

あと補足ですが以下のページの対応を行っています。
Visual C++ CRT(Cランタイムライブラリ)のビルドエラー

これからもOpenCVのプログラムはこれをベースに作って公開出来ればと思います。

関連リンク
インコのWindowsSDK
猫でもわかるプログラミング Windows SDK編 第1部
eternalwindows
(※いずれのサイトも歴史があり私も何かと参考にさせて頂いています。)

関連書籍
(※APIで学ぶWindows徹底理解は中古でしか手に入らないようですが私も持っています。)

(※OpenCV 2 プログラミングブックは私も持っています。)

(※ここからはKindle版で英語ですが最新の情報もあるようです。また価格的にはいいかもしれないです。)


AdSense

AdSense

-OpenCV

執筆者:

関連記事

OpenCVで背景差分とテスト的な動体検知

OpenCVで背景差分を試してみました。あとテスト的な動体検知も試してみました。背景差分とはあらかじめ取得した画像を背景画像として、観測時点の画像とその背景画像との差分を取ることによりその差分を前景領 …

Tesseract-OCRの導入(その3)OpenCVの出力を認識する

2019/07/20追記 この記事を書いてから随分と経過しました。完全に情報が古くなっています。外部のサイトですが必要な場合は以下等を参照して下さい。 PythonとTesseract OCRで文字認 …

OpenCVをWin32ベースで利用する(その4)カメラ入力からの動画処理

OpenCVをWin32ベースで利用するの4回目です。前回はカメラ入力からの画像処理(静止画)を扱いましたが、今回は動画を処理します。動画と言っても特に変わることはなくキャプチャしたフレームごとに処理 …

Raspberry Pi 4にOpenCVをインストールしてPythonで動作確認

Raspberry Pi 4にOpenCVをインストールして動作確認をしました。Pythonでのプログラミングを想定して動作確認はPythonで行いました。

OpenCVで輪郭抽出から隣接領域の切り出し(その2)輪郭の直線近似と切り出し

OpenCVで画像内の輪郭抽出からその輪郭の隣接領域(四角形)を求めてその領域を切り出すという処理を作ってみました。以下の画像がその結果の例です。(※実画像サイズは大きめです。) 今回はその2回目です …