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
33
HWND ghDlg = NULL;
34
INT gleft = 0;
35
INT gright = 0;
36
BOOL gexit = FALSE;
37
38
39
void 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
51
void DelayTime( DWORD delay )
{
52
DWORD start = ::GetTickCount();
53
do
{
54
::DealAllMsg();
55
::Sleep( 2 );
56
} while ( (! gexit) && (::GetTickCount() - start < delay) );
57
}
58
59
60
INT_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
91
INT 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)
19
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
20
21
#ifdef APSTUDIO_INVOKED
22
/**////////////////////////////////////////////////////////////////////////////// 23
//
24
// TEXTINCLUDE
25
//
26
27
1 TEXTINCLUDE
28
BEGIN
29
"resource.h\0"
30
END
31
32
2 TEXTINCLUDE
33
BEGIN
34
"#include ""afxres.h""\r\n"
35
"\0"
36
END
37
38
3 TEXTINCLUDE
39
BEGIN
40
"\r\n"
41
"\0"
42
END
43
44
#endif // APSTUDIO_INVOKED
45
46
47
/**////////////////////////////////////////////////////////////////////////////// 48
//
49
// Dialog
50
//
51
52
IDD_GARAGE_DIALOG DIALOGEX 0, 0, 266, 156
53
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_THICKFRAME
54
EXSTYLE WS_EX_APPWINDOW
55
CAPTION "OpenCV 摄像头 - 尝试"
56
FONT 8, "MS Shell Dlg", 0, 0, 0x1
57
BEGIN
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
67
END
68
69
70
/**////////////////////////////////////////////////////////////////////////////// 71
//
72
// DESIGNINFO
73
//
74
75
#ifdef APSTUDIO_INVOKED
76
GUIDELINES DESIGNINFO
77
BEGIN
78
IDD_GARAGE_DIALOG, DIALOG
79
BEGIN
80
LEFTMARGIN, 7
81
RIGHTMARGIN, 259
82
TOPMARGIN, 7
83
BOTTOMMARGIN, 149
84
END
85
END
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