OpenCV 的 highgui 提供了简单的界面,然而在 Windows 下,它并未将消息机制封装的足够好,在使用的时候,若不考虑到消息机制,很容易使界面死掉,同时 OpenCV 本身的运转也会出问题。
Windows 下,界面的正常运作需要大量的消息传递与处理,然而 OpenCV 的函数,几乎都与消息无关,目前我只知道 cvWaitKey() 会接收并转发本线程的消息(恕我无知),但只仅限于被调用后的等待时间内,所以并不能完全保证消息机制的正常运作。程序至少需要考虑到主动接收与转发消息,以确保界面的正常运作。(也许这可以解释,为什么许多示例程序中都调用了 cvWaitKey() 函数。)
Windows 下的消息是线程相关的,启动新线程又会引出更多的问题。
下面程序从摄像头获取输入,并在窗口中显示。三个窗口使用一个线程。
我尝试过创建新线程,在新线程中使用 highgui 创建窗口,显示图像,然而,窗口的大小正确,却显示一片灰色(求指教!!)。
附源代码:
由于线程关系,我使用了最朴素的 Win32 API 。
OpenCV 2.1 + VS2010
1#include "resource.h"
2#include <Windows.h>
3#include <highgui.h>
4
5
6#ifdef _DEBUG
7/**//* debug */
8
9#pragma comment( lib, "cv210d.lib" )
10#pragma comment( lib, "cvaux210d.lib" )
11#pragma comment( lib, "cxcore210d.lib" )
12#pragma comment( lib, "cxts210d.lib" )
13#pragma comment( lib, "highgui210d.lib" )
14#pragma comment( lib, "ml210d.lib" )
15#pragma comment( lib, "opencv_ffmpeg210d.lib" )
16
17
18#else
19/**//* release */
20
21#pragma comment( lib, "cv210.lib" )
22#pragma comment( lib, "cvaux210.lib" )
23#pragma comment( lib, "cxcore210.lib" )
24#pragma comment( lib, "cxts210.lib" )
25#pragma comment( lib, "highgui210.lib" )
26#pragma comment( lib, "ml210.lib" )
27#pragma comment( lib, "opencv_ffmpeg210.lib" )
28
29
30#endif
31
32
33HWND ghDlg = NULL;
34INT gleft = 0;
35INT gright = 0;
36BOOL gexit = FALSE;
37
38
39void DealAllMsg() {
40 MSG msg;
41 while ( ::PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) {
42 if ( ::IsWindow(ghDlg) && ::IsDialogMessage(ghDlg,&msg) ) {
43 continue;
44 }
45 ::TranslateMessage( &msg );
46 ::DispatchMessage( &msg );
47 }
48}
49
50
51void DelayTime( DWORD delay ) {
52 DWORD start = ::GetTickCount();
53 do {
54 ::DealAllMsg();
55 ::Sleep( 2 );
56 } while ( (! gexit) && (::GetTickCount() - start < delay) );
57}
58
59
60INT_PTR CALLBACK DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
61 switch ( uMsg ) {
62 case WM_INITDIALOG :
63 ::CheckRadioButton( hDlg, IDC_RADIO1, IDC_RADIO3, IDC_RADIO1+gleft );
64 ::CheckRadioButton( hDlg, IDC_RADIO4, IDC_RADIO6, IDC_RADIO4+gright );
65 return 1;
66
67 case WM_COMMAND :
68 switch ( LOWORD(wParam) ) {
69 case IDC_RADIO1 :
70 case IDC_RADIO2 :
71 case IDC_RADIO3 :
72 gleft = LOWORD(wParam) - IDC_RADIO1;
73 ::CheckRadioButton( hDlg, IDC_RADIO1, IDC_RADIO3, IDC_RADIO1+gleft );
74 return 1;
75 case IDC_RADIO4 :
76 case IDC_RADIO5 :
77 case IDC_RADIO6 :
78 gright = LOWORD(wParam) - IDC_RADIO4;
79 ::CheckRadioButton( hDlg, IDC_RADIO4, IDC_RADIO6, IDC_RADIO4+gright );
80 return 1;
81 case IDCANCEL :
82 gexit = TRUE;
83 return 1;
84 }
85 break;
86 }
87 return 0;
88}
89
90
91INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR szCmd, INT nShow ) {
92 char *nameleft = "左窗口";
93 char *nameright = "右窗口";
94 CvCapture *cap = NULL;
95 IplImage *imgleft = NULL, *imgright = NULL;
96 int i;
97
98 cap = ::cvCreateCameraCapture( -1 );
99 ::DealAllMsg();
100 if ( NULL == cap ) {
101 ::MessageBox( NULL, TEXT("摄像头错误"), TEXT("错误"), MB_ICONERROR | MB_OK );
102 return 0;
103 }
104
105 ::cvNamedWindow( nameleft );
106 ::DealAllMsg();
107 ::cvNamedWindow( nameright );
108 ::DealAllMsg();
109
110 ghDlg = ::CreateDialogParam( hInst, MAKEINTRESOURCE(IDD_GARAGE_DIALOG), NULL, DlgProc, 0 );
111 ::ShowWindow( ghDlg, SW_SHOW );
112 ::DealAllMsg();
113
114 for ( ; ; ) {
115 for ( i = 0; i < 1; ++i ) {
116 imgleft = ::cvQueryFrame( cap );
117 ::DealAllMsg();
118 if ( NULL == imgleft ) {
119 break;
120 }
121 }
122 if ( NULL == imgleft ) {
123 break;
124 }
125
126 switch ( gleft ) {
127 case 0 :
128 ::cvShowImage( nameleft, imgleft );
129 break;
130 case 1 :
131 break;
132 case 2 :
133 ::cvDestroyWindow( nameleft );
134 break;
135 }
136 ::DealAllMsg();
137 if ( gexit ) {
138 break;
139 }
140
141 imgright = imgleft; // imgright = func( imgleft );
142 ::DealAllMsg();
143
144 switch ( gright ) {
145 case 0 :
146 ::cvShowImage( nameright, imgright );
147 break;
148 case 1 :
149 break;
150 case 2 :
151 ::cvDestroyWindow( nameright );
152 break;
153 }
154 ::DealAllMsg();
155 if ( gexit ) {
156 break;
157 }
158 }
159
160 ::DestroyWindow( ghDlg );
161
162 ::cvDestroyWindow( nameright );
163 ::cvDestroyWindow( nameleft );
164
165 ::cvReleaseCapture( &cap );
166
167 return 0;
168}
169
1//{{NO_DEPENDENCIES}}
2// Microsoft Visual C++ generated include file.
3// Used by Garage.rc
4//
5#define IDD_GARAGE_DIALOG 101
6#define IDC_RADIO1 1001
7#define IDC_RADIO2 1002
8#define IDC_RADIO3 1003
9#define IDC_RADIO4 1004
10#define IDC_RADIO5 1005
11#define IDC_RADIO6 1006
12
13
14// Next default values for new objects
15//
16#ifdef APSTUDIO_INVOKED
17#ifndef APSTUDIO_READONLY_SYMBOLS
18#define _APS_NEXT_RESOURCE_VALUE 102
19#define _APS_NEXT_COMMAND_VALUE 40001
20#define _APS_NEXT_CONTROL_VALUE 1007
21#define _APS_NEXT_SYMED_VALUE 101
22#endif
23#endif
24
1// Microsoft Visual C++ generated resource script.
2//
3#include "resource.h"
4
5#define APSTUDIO_READONLY_SYMBOLS
6/**////////////////////////////////////////////////////////////////////////////// 7//
8// Generated from the TEXTINCLUDE 2 resource.
9//
10#include "afxres.h"
11
12/**////////////////////////////////////////////////////////////////////////////// 13#undef APSTUDIO_READONLY_SYMBOLS
14
15/**////////////////////////////////////////////////////////////////////////////// 16// Chinese (Simplified, PRC) resources
17
18#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
19LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
20
21#ifdef APSTUDIO_INVOKED
22/**////////////////////////////////////////////////////////////////////////////// 23//
24// TEXTINCLUDE
25//
26
271 TEXTINCLUDE
28BEGIN
29 "resource.h\0"
30END
31
322 TEXTINCLUDE
33BEGIN
34 "#include ""afxres.h""\r\n"
35 "\0"
36END
37
383 TEXTINCLUDE
39BEGIN
40 "\r\n"
41 "\0"
42END
43
44#endif // APSTUDIO_INVOKED
45
46
47/**////////////////////////////////////////////////////////////////////////////// 48//
49// Dialog
50//
51
52IDD_GARAGE_DIALOG DIALOGEX 0, 0, 266, 156
53STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_THICKFRAME
54EXSTYLE WS_EX_APPWINDOW
55CAPTION "OpenCV 摄像头 - 尝试"
56FONT 8, "MS Shell Dlg", 0, 0, 0x1
57BEGIN
58 DEFPUSHBUTTON "退出",IDCANCEL,209,135,50,14
59 CONTROL "播放",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON | WS_GROUP,40,40,32,10
60 CONTROL "暂停",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,40,65,32,10
61 CONTROL "关闭",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,40,90,32,10
62 CONTROL "播放",IDC_RADIO4,"Button",BS_AUTORADIOBUTTON | WS_GROUP,185,40,32,10
63 CONTROL "暂停",IDC_RADIO5,"Button",BS_AUTORADIOBUTTON,185,65,32,10
64 CONTROL "关闭",IDC_RADIO6,"Button",BS_AUTORADIOBUTTON,185,90,32,10
65 GROUPBOX "左窗口",IDC_STATIC,23,20,65,86
66 GROUPBOX "右窗口",IDC_STATIC,168,20,65,86
67END
68
69
70/**////////////////////////////////////////////////////////////////////////////// 71//
72// DESIGNINFO
73//
74
75#ifdef APSTUDIO_INVOKED
76GUIDELINES DESIGNINFO
77BEGIN
78 IDD_GARAGE_DIALOG, DIALOG
79 BEGIN
80 LEFTMARGIN, 7
81 RIGHTMARGIN, 259
82 TOPMARGIN, 7
83 BOTTOMMARGIN, 149
84 END
85END
86#endif // APSTUDIO_INVOKED
87
88#endif // Chinese (Simplified, PRC) resources
89/**////////////////////////////////////////////////////////////////////////////// 90
91
92
93#ifndef APSTUDIO_INVOKED
94/**////////////////////////////////////////////////////////////////////////////// 95//
96// Generated from the TEXTINCLUDE 3 resource.
97//
98
99
100/**//////////////////////////////////////////////////////////////////////////////101#endif // not APSTUDIO_INVOKED
102
103