Comparing screen capturing using GDI+ and OpenCV on Windows in C++#
To follow up on my last two blogs (Capturing the screen on Windows in C++ using OpenCV & Capturing the screen on Windows in C++ using GDI+ ), we compare in this post both approaches. In order to compare both approaches, we examines their run-times and CPU usages.
Benchmarking Code#
To capture the run-times of each approach, we will need to add a Timer, that we will use to capture the start and end times of each approach. For this you can use whatever implementation you deem useful. I personally used the following snippet, which can be found here :
1#include <chrono>
2#include <iostream>
3
4/*
5 * Timer class to measure the run-times in seconds of code snippets.
6 */
7class Timer
8{
9public:
10 Timer() : beg_(clock_::now()) {}
11 void reset() { beg_ = clock_::now(); }
12 double elapsed() const { return std::chrono::duration_cast<second_> (clock_::now() - beg_).count();}
13
14private:
15 typedef std::chrono::high_resolution_clock clock_;
16 typedef std::chrono::duration<double, std::ratio<1> > second_;
17 std::chrono::time_point<clock_> beg_;
18};
The Testing setup#
Now let's write the main testing code. We already have all the components ready in the last two posts, so all we need is combine the previous screen-shooting codes with the timer calls.
1int main()
2{
3 // initializations
4 Timer tmr;
5 int repetitions = 50;
6 HWND hWnd = GetDesktopWindow();
7
8 tmr.reset();
9 double t = tmr.elapsed();
10
11 // Initialize GDI+.
12 GdiplusStartupInput gdiplusStartupInput;
13 ULONG_PTR gdiplusToken;
14 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
15
16 std::wcout << "Benchmarks for GDI+ variant of the screenshooter" << std::endl;
17 std::wcout << "***********************************************************" << std::endl;
18 // benchmarks for GDI+
19 tmr.reset();
20 for (int i = 0; i < repetitions; i++)
21 {
22 // capture and encode screenshot
23 std::vector<BYTE> data;
24 HBITMAP hBmp = GdiPlusScreenCapture(hWnd);
25 saveToMemory(&hBmp, data, "png");
26 data.clear();
27 }
28 GdiplusShutdown(gdiplusToken);
29 t = tmr.elapsed();
30 std::wcout << " | Number of Runs [#] = " << repetitions << std::endl;
31 std::wcout << " | Run duration [s] = " << t << std::endl;
32 std::wcout << " | Average Run duration [ms] = " << t / repetitions << std::endl;
33 std::wcout << "***********************************************************" << std::endl;
34
35 std::wcout << "Benchmarks for OpenCV variant of the screenshooter" << std::endl;
36 std::wcout << "***********************************************************" << std::endl;
37 // benchmarks for OpenCV
38 tmr.reset();
39 for (int i = 0; i < repetitions; i++)
40 {
41 // capture and encode screenshot
42 std::vector<uchar> buf;
43 Mat src = captureScreenMat(hWnd);
44 cv::imencode(".png", src, buf);
45 buf.clear();
46 src.release();
47 }
48 t = tmr.elapsed();
49 std::wcout << " | Number of Runs [#] = " << repetitions << std::endl;
50 std::wcout << " | Run duration [s] = " << t << std::endl;
51 std::wcout << " | Average Run duration [ms] = " << t / repetitions << std::endl;
52 std::wcout << "***********************************************************" << std::endl;
53 return 0;
54}
Benchmarking results#
The testing results confirms the previously mentioned intuition that screen shooting using GDI+ is faster than the OpenCV variant. However, upon examining the results in details, we realize that the right answer to the question of which library is better? is a complex one (as it is the case, almost always).
Benchmarks for GDI+ variant of the screenshooter
*********************************************************
| Number of Runs [#] = 50
| Run duration [s] = 7.3564
| Average Run duration [ms] = 0.147128
*********************************************************
Benchmarks for OpenCV variant of the screenshooter
*********************************************************
| Number of Runs [#] = 50
| Run duration [s] = 17.8956
| Average Run duration [ms] = 0.357913
*********************************************************
Conclusion#
To summarize, in this post we compared the previously implemented screen-shooting methods using GDI+ and OpenCV. The test results confirmed the previous intuition about the GDI+ being faster as it uses the native Windows API. However, the OpenCV variant is still a decent option and sometimes even a better one because -unlike GDI+- it supports various operating systems other than Windows.
References and Further readings#
GDI+, Microsoft, https://docs.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-gdi-start
About GDI+, Microsoft, https://docs.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-about-gdi--about
Does GDI+ have standard image encoder CLSIDs?, Stackoverflow, https://stackoverflow.com/questions/5345803/does-gdi-have-standard-image-encoder-clsids
GDI+ Bitmap Save problem, Stackoverflow, https://stackoverflow.com/questions/1584202/gdi-bitmap-save-problem
Capturing an Image, Microsoft, http://msdn.microsoft.com/en-us/library/windows/window/dd183402%28v=vs.85%29.aspx
OPENCV Desktop Capture, Stackoverflow, https://stackoverflow.com/questions/34466993/opencv-desktop-capture
How to capture the desktop in OpenCV (ie. turn a bitmap into a Mat)?, Stackoverflow, https://stackoverflow.com/questions/14148758/how-to-capture-the-desktop-in-opencv-ie-turn-a-bitmap-into-a-mat