OpenCVをWin32ベースで利用するの5回目です。前回の4回目で一度終了したのですが、画面上の入出力用のコントロール、つまり、ラベル、エディット、コンボ等のコントロールがなかったので追加してみました。その今回のサンプルプログラムの画面は以下です。
内容としては、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版で英語ですが最新の情報もあるようです。また価格的にはいいかもしれないです。)