Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/samples/opengl/opengl_interop.cpp
16337 views
1
/*
2
// Sample demonstrating interoperability of OpenCV UMat with OpenGL texture.
3
// At first, the data obtained from video file or camera and placed onto
4
// OpenGL texture, following mapping of this OpenGL texture to OpenCV UMat
5
// and call cv::Blur function. The result is mapped back to OpenGL texture
6
// and rendered through OpenGL API.
7
*/
8
#if defined(_WIN32)
9
# define WIN32_LEAN_AND_MEAN
10
# include <windows.h>
11
#elif defined(__linux__)
12
# include <X11/X.h>
13
# include <X11/Xlib.h>
14
#endif
15
16
#include <iostream>
17
#include <queue>
18
#include <string>
19
20
#include <stdio.h>
21
22
#include "opencv2/core.hpp"
23
#include "opencv2/core/opengl.hpp"
24
#include "opencv2/core/ocl.hpp"
25
#include "opencv2/imgproc.hpp"
26
#include "opencv2/videoio.hpp"
27
28
#include "winapp.hpp"
29
30
#if defined(_WIN32)
31
# pragma comment(lib, "opengl32.lib")
32
# pragma comment(lib, "glu32.lib")
33
#endif
34
35
36
class GLWinApp : public WinApp
37
{
38
public:
39
enum MODE
40
{
41
MODE_CPU = 0,
42
MODE_GPU
43
};
44
45
GLWinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) :
46
WinApp(width, height, window_name)
47
{
48
m_shutdown = false;
49
m_use_buffer = false;
50
m_demo_processing = true;
51
m_mode = MODE_CPU;
52
m_modeStr[0] = cv::String("Processing on CPU");
53
m_modeStr[1] = cv::String("Processing on GPU");
54
m_cap = cap;
55
}
56
57
~GLWinApp() {}
58
59
virtual void cleanup() CV_OVERRIDE
60
{
61
m_shutdown = true;
62
#if defined(__linux__)
63
glXMakeCurrent(m_display, None, NULL);
64
glXDestroyContext(m_display, m_glctx);
65
#endif
66
WinApp::cleanup();
67
}
68
69
#if defined(_WIN32)
70
virtual LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) CV_OVERRIDE
71
{
72
switch (message)
73
{
74
case WM_CHAR:
75
if (wParam == '1')
76
{
77
set_mode(MODE_CPU);
78
return EXIT_SUCCESS;
79
}
80
if (wParam == '2')
81
{
82
set_mode(MODE_GPU);
83
return EXIT_SUCCESS;
84
}
85
else if (wParam == '9')
86
{
87
toggle_buffer();
88
return EXIT_SUCCESS;
89
}
90
else if (wParam == VK_SPACE)
91
{
92
m_demo_processing = !m_demo_processing;
93
return EXIT_SUCCESS;
94
}
95
else if (wParam == VK_ESCAPE)
96
{
97
cleanup();
98
return EXIT_SUCCESS;
99
}
100
break;
101
102
case WM_CLOSE:
103
cleanup();
104
return EXIT_SUCCESS;
105
106
case WM_DESTROY:
107
::PostQuitMessage(0);
108
return EXIT_SUCCESS;
109
}
110
111
return ::DefWindowProc(hWnd, message, wParam, lParam);
112
}
113
#endif
114
115
#if defined(__linux__)
116
int handle_event(XEvent& e) CV_OVERRIDE
117
{
118
switch(e.type)
119
{
120
case ClientMessage:
121
if ((Atom)e.xclient.data.l[0] == m_WM_DELETE_WINDOW)
122
{
123
m_end_loop = true;
124
cleanup();
125
}
126
else
127
{
128
return EXIT_SUCCESS;
129
}
130
break;
131
case Expose:
132
render();
133
break;
134
case KeyPress:
135
switch(keycode_to_keysym(e.xkey.keycode))
136
{
137
case XK_space:
138
m_demo_processing = !m_demo_processing;
139
break;
140
case XK_1:
141
set_mode(MODE_CPU);
142
break;
143
case XK_2:
144
set_mode(MODE_GPU);
145
break;
146
case XK_9:
147
toggle_buffer();
148
break;
149
case XK_Escape:
150
m_end_loop = true;
151
cleanup();
152
break;
153
}
154
break;
155
default:
156
return EXIT_SUCCESS;
157
}
158
return 1;
159
}
160
#endif
161
162
int init() CV_OVERRIDE
163
{
164
#if defined(_WIN32)
165
m_hDC = GetDC(m_hWnd);
166
167
if (setup_pixel_format() != 0)
168
{
169
std::cerr << "Can't setup pixel format" << std::endl;
170
return EXIT_FAILURE;
171
}
172
173
m_hRC = wglCreateContext(m_hDC);
174
wglMakeCurrent(m_hDC, m_hRC);
175
#elif defined(__linux__)
176
m_glctx = glXCreateContext(m_display, m_visual_info, NULL, GL_TRUE);
177
glXMakeCurrent(m_display, m_window, m_glctx);
178
#endif
179
180
glEnable(GL_TEXTURE_2D);
181
glEnable(GL_DEPTH_TEST);
182
183
glViewport(0, 0, m_width, m_height);
184
185
if (cv::ocl::haveOpenCL())
186
{
187
(void) cv::ogl::ocl::initializeContextFromGL();
188
}
189
190
m_oclDevName = cv::ocl::useOpenCL() ?
191
cv::ocl::Context::getDefault().device(0).name() :
192
(char*) "No OpenCL device";
193
194
return EXIT_SUCCESS;
195
} // init()
196
197
int get_frame(cv::ogl::Texture2D& texture, cv::ogl::Buffer& buffer, bool do_buffer)
198
{
199
if (!m_cap.read(m_frame_bgr))
200
return EXIT_FAILURE;
201
202
cv::cvtColor(m_frame_bgr, m_frame_rgba, cv::COLOR_RGB2RGBA);
203
204
if (do_buffer)
205
buffer.copyFrom(m_frame_rgba, cv::ogl::Buffer::PIXEL_UNPACK_BUFFER, true);
206
else
207
texture.copyFrom(m_frame_rgba, true);
208
209
return EXIT_SUCCESS;
210
}
211
212
void print_info(MODE mode, double time, cv::String& oclDevName)
213
{
214
#if defined(_WIN32)
215
HDC hDC = m_hDC;
216
217
HFONT hFont = (HFONT)::GetStockObject(SYSTEM_FONT);
218
219
HFONT hOldFont = (HFONT)::SelectObject(hDC, hFont);
220
221
if (hOldFont)
222
{
223
TEXTMETRIC tm;
224
::GetTextMetrics(hDC, &tm);
225
226
char buf[256+1];
227
int y = 0;
228
229
buf[0] = 0;
230
sprintf_s(buf, sizeof(buf)-1, "Mode: %s OpenGL %s", m_modeStr[mode].c_str(), use_buffer() ? "buffer" : "texture");
231
::TextOut(hDC, 0, y, buf, (int)strlen(buf));
232
233
y += tm.tmHeight;
234
buf[0] = 0;
235
sprintf_s(buf, sizeof(buf)-1, "Time, msec: %2.1f", time);
236
::TextOut(hDC, 0, y, buf, (int)strlen(buf));
237
238
y += tm.tmHeight;
239
buf[0] = 0;
240
sprintf_s(buf, sizeof(buf)-1, "OpenCL device: %s", oclDevName.c_str());
241
::TextOut(hDC, 0, y, buf, (int)strlen(buf));
242
243
::SelectObject(hDC, hOldFont);
244
}
245
#elif defined(__linux__)
246
247
char buf[256+1];
248
snprintf(buf, sizeof(buf)-1, "Time, msec: %2.1f, Mode: %s OpenGL %s, Device: %s", time, m_modeStr[mode].c_str(), use_buffer() ? "buffer" : "texture", oclDevName.c_str());
249
XStoreName(m_display, m_window, buf);
250
#endif
251
}
252
253
void idle() CV_OVERRIDE
254
{
255
render();
256
}
257
258
int render() CV_OVERRIDE
259
{
260
try
261
{
262
if (m_shutdown)
263
return EXIT_SUCCESS;
264
265
int r;
266
cv::ogl::Texture2D texture;
267
cv::ogl::Buffer buffer;
268
269
texture.setAutoRelease(true);
270
buffer.setAutoRelease(true);
271
272
MODE mode = get_mode();
273
bool do_buffer = use_buffer();
274
275
r = get_frame(texture, buffer, do_buffer);
276
if (r != 0)
277
{
278
return EXIT_FAILURE;
279
}
280
281
switch (mode)
282
{
283
case MODE_CPU: // process frame on CPU
284
processFrameCPU(texture, buffer, do_buffer);
285
break;
286
287
case MODE_GPU: // process frame on GPU
288
processFrameGPU(texture, buffer, do_buffer);
289
break;
290
} // switch
291
292
if (do_buffer) // buffer -> texture
293
{
294
cv::Mat m(m_height, m_width, CV_8UC4);
295
buffer.copyTo(m);
296
texture.copyFrom(m, true);
297
}
298
299
#if defined(__linux__)
300
XWindowAttributes window_attributes;
301
XGetWindowAttributes(m_display, m_window, &window_attributes);
302
glViewport(0, 0, window_attributes.width, window_attributes.height);
303
#endif
304
305
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
306
glLoadIdentity();
307
glEnable(GL_TEXTURE_2D);
308
309
texture.bind();
310
311
glBegin(GL_QUADS);
312
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 0.1f);
313
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, -1.0f, 0.1f);
314
glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, -1.0f, 0.1f);
315
glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f, 1.0f, 0.1f);
316
glEnd();
317
318
#if defined(_WIN32)
319
SwapBuffers(m_hDC);
320
#elif defined(__linux__)
321
glXSwapBuffers(m_display, m_window);
322
#endif
323
324
print_info(mode, m_timer.getTimeMilli(), m_oclDevName);
325
}
326
327
328
catch (cv::Exception& e)
329
{
330
std::cerr << "Exception: " << e.what() << std::endl;
331
return 10;
332
}
333
334
return EXIT_SUCCESS;
335
}
336
337
protected:
338
339
void processFrameCPU(cv::ogl::Texture2D& texture, cv::ogl::Buffer& buffer, bool do_buffer)
340
{
341
cv::Mat m(m_height, m_width, CV_8UC4);
342
343
m_timer.reset();
344
m_timer.start();
345
346
if (do_buffer)
347
buffer.copyTo(m);
348
else
349
texture.copyTo(m);
350
351
if (m_demo_processing)
352
{
353
// blur texture image with OpenCV on CPU
354
cv::blur(m, m, cv::Size(15, 15));
355
}
356
357
if (do_buffer)
358
buffer.copyFrom(m, cv::ogl::Buffer::PIXEL_UNPACK_BUFFER, true);
359
else
360
texture.copyFrom(m, true);
361
362
m_timer.stop();
363
}
364
365
void processFrameGPU(cv::ogl::Texture2D& texture, cv::ogl::Buffer& buffer, bool do_buffer)
366
{
367
cv::UMat u;
368
369
m_timer.reset();
370
m_timer.start();
371
372
if (do_buffer)
373
u = cv::ogl::mapGLBuffer(buffer);
374
else
375
cv::ogl::convertFromGLTexture2D(texture, u);
376
377
if (m_demo_processing)
378
{
379
// blur texture image with OpenCV on GPU with OpenCL
380
cv::blur(u, u, cv::Size(15, 15));
381
}
382
383
if (do_buffer)
384
cv::ogl::unmapGLBuffer(u);
385
else
386
cv::ogl::convertToGLTexture2D(u, texture);
387
388
m_timer.stop();
389
}
390
391
#if defined(_WIN32)
392
int setup_pixel_format()
393
{
394
PIXELFORMATDESCRIPTOR pfd;
395
396
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
397
pfd.nVersion = 1;
398
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
399
pfd.iPixelType = PFD_TYPE_RGBA;
400
pfd.cColorBits = 24;
401
pfd.cRedBits = 8;
402
pfd.cRedShift = 0;
403
pfd.cGreenBits = 8;
404
pfd.cGreenShift = 0;
405
pfd.cBlueBits = 8;
406
pfd.cBlueShift = 0;
407
pfd.cAlphaBits = 8;
408
pfd.cAlphaShift = 0;
409
pfd.cAccumBits = 0;
410
pfd.cAccumRedBits = 0;
411
pfd.cAccumGreenBits = 0;
412
pfd.cAccumBlueBits = 0;
413
pfd.cAccumAlphaBits = 0;
414
pfd.cDepthBits = 24;
415
pfd.cStencilBits = 8;
416
pfd.cAuxBuffers = 0;
417
pfd.iLayerType = PFD_MAIN_PLANE;
418
pfd.bReserved = 0;
419
pfd.dwLayerMask = 0;
420
pfd.dwVisibleMask = 0;
421
pfd.dwDamageMask = 0;
422
423
int pfmt = ChoosePixelFormat(m_hDC, &pfd);
424
if (pfmt == 0)
425
return EXIT_FAILURE;
426
427
if (SetPixelFormat(m_hDC, pfmt, &pfd) == 0)
428
return -2;
429
430
return EXIT_SUCCESS;
431
}
432
#endif
433
434
#if defined(__linux__)
435
KeySym keycode_to_keysym(unsigned keycode)
436
{ // note that XKeycodeToKeysym() is considered deprecated
437
int keysyms_per_keycode_return = 0;
438
KeySym *keysyms = XGetKeyboardMapping(m_display, keycode, 1, &keysyms_per_keycode_return);
439
KeySym keysym = keysyms[0];
440
XFree(keysyms);
441
return keysym;
442
}
443
#endif
444
445
bool use_buffer() { return m_use_buffer; }
446
void toggle_buffer() { m_use_buffer = !m_use_buffer; }
447
MODE get_mode() { return m_mode; }
448
void set_mode(MODE mode) { m_mode = mode; }
449
450
private:
451
bool m_shutdown;
452
bool m_use_buffer;
453
bool m_demo_processing;
454
MODE m_mode;
455
cv::String m_modeStr[2];
456
#if defined(_WIN32)
457
HDC m_hDC;
458
HGLRC m_hRC;
459
#elif defined(__linux__)
460
GLXContext m_glctx;
461
#endif
462
cv::VideoCapture m_cap;
463
cv::Mat m_frame_bgr;
464
cv::Mat m_frame_rgba;
465
cv::String m_oclDevName;
466
};
467
468
static const char* keys =
469
{
470
"{c camera | 0 | camera id }"
471
"{f file | | movie file name }"
472
};
473
474
using namespace cv;
475
using namespace std;
476
477
int main(int argc, char** argv)
478
{
479
cv::CommandLineParser parser(argc, argv, keys);
480
int camera_id = parser.get<int>("camera");
481
string file = parser.get<string>("file");
482
483
parser.about(
484
"\nA sample program demonstrating interoperability of OpenGL and OpenCL with OpenCV.\n\n"
485
"Hot keys: \n"
486
" SPACE - turn processing on/off\n"
487
" 1 - process GL data through OpenCV on CPU\n"
488
" 2 - process GL data through OpenCV on GPU (via OpenCL)\n"
489
" 9 - toggle use of GL texture/GL buffer\n"
490
" ESC - exit\n\n");
491
492
parser.printMessage();
493
494
cv::VideoCapture cap;
495
496
if (file.empty())
497
cap.open(camera_id);
498
else
499
cap.open(file.c_str());
500
501
if (!cap.isOpened())
502
{
503
printf("can not open camera or video file\n");
504
return EXIT_FAILURE;
505
}
506
507
int width = (int)cap.get(CAP_PROP_FRAME_WIDTH);
508
int height = (int)cap.get(CAP_PROP_FRAME_HEIGHT);
509
510
#if defined(_WIN32)
511
string wndname = "WGL Window";
512
#elif defined(__linux__)
513
string wndname = "GLX Window";
514
#endif
515
516
GLWinApp app(width, height, wndname, cap);
517
518
try
519
{
520
app.create();
521
return app.run();
522
}
523
catch (cv::Exception& e)
524
{
525
cerr << "Exception: " << e.what() << endl;
526
return 10;
527
}
528
catch (...)
529
{
530
cerr << "FATAL ERROR: Unknown exception" << endl;
531
return 11;
532
}
533
}
534
535