292 words
1 minute
如何使用 C++ 和 OpenCV 实现截屏
前言
实现屏幕截屏需要用到 Windows API,所以需要包括 Windows.h 头文件。同时我们想要对截图做进一步的处理,就需要用到 OpenCV。关于 OpenCV 的安装与编译可以参见 《再整理:Visual Studio Code(vscode)下的基于C++的OpenCV的最新搭建攻略解析》,亲测有效,但是 OpenCV 还有 MinGW 的版本最好和博客中保持一致,不然编译可能会失败。下面进入正题。
代码
头文件
Screenshot.h
#pragma once#include <Windows.h>#include <opencv2/opencv.hpp>
class Screenshot{public: Screenshot(); double static getZoom(); cv::Mat getScreenshot(); cv::Mat getScreenshot(int x, int y, int width, int height);
private: int m_width; int m_height; HDC m_screenDC; HDC m_compatibleDC; HBITMAP m_hBitmap; LPVOID m_screenshotData = nullptr;};源文件
在截图之前需要获取屏幕的分辨率,一种很直观的想法就是调用 GetSystemMetrics(SM_C*SCREEN) 函数来获取宽度或者高度。如下图所示,设置屏幕缩放 125% 之后,得到的值会偏小。如果是 1920 × 1080 的分辨率,GetSystemMetrics(SM_CXSCREEN) 和 GetSystemMetrics(SM_CYSCREEN) 返回分辨率会是 (1920, 1080) / 1.25 = (1536, 864)。所以我们需要先计算屏幕的缩放率。这个任务由 Screenshot::getZoom() 完成。剩下的步骤注释中解释的很充分了,不再赘述。

Screenshot.cpp
#include "Screenshot.h"using cv::Mat;
Screenshot::Screenshot(){ double zoom = getZoom(); m_width = GetSystemMetrics(SM_CXSCREEN) * zoom; m_height = GetSystemMetrics(SM_CYSCREEN) * zoom; m_screenshotData = new char[m_width * m_height * 4]; memset(m_screenshotData, 0, m_width);
// 获取屏幕 DC m_screenDC = GetDC(NULL); m_compatibleDC = CreateCompatibleDC(m_screenDC);
// 创建位图 m_hBitmap = CreateCompatibleBitmap(m_screenDC, m_width, m_height); SelectObject(m_compatibleDC, m_hBitmap);}
/* 获取整个屏幕的截图 */Mat Screenshot::getScreenshot(){ // 得到位图的数据 BitBlt(m_compatibleDC, 0, 0, m_width, m_height, m_screenDC, 0, 0, SRCCOPY); GetBitmapBits(m_hBitmap, m_width * m_height * 4, m_screenshotData);
// 创建图像 Mat screenshot(m_height, m_width, CV_8UC4, m_screenshotData);
return screenshot;}
/** @brief 获取指定范围的屏幕截图 * @param x 图像左上角的 X 坐标 * @param y 图像左上角的 Y 坐标 * @param width 图像宽度 * @param height 图像高度 */Mat Screenshot::getScreenshot(int x, int y, int width, int height){ Mat screenshot = getScreenshot(); return screenshot(cv::Rect(x, y, width, height));}
/* 获取屏幕缩放值 */double Screenshot::getZoom(){ // 获取窗口当前显示的监视器 HWND hWnd = GetDesktopWindow(); HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
// 获取监视器逻辑宽度 MONITORINFOEX monitorInfo; monitorInfo.cbSize = sizeof(monitorInfo); GetMonitorInfo(hMonitor, &monitorInfo); int cxLogical = (monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left);
// 获取监视器物理宽度 DEVMODE dm; dm.dmSize = sizeof(dm); dm.dmDriverExtra = 0; EnumDisplaySettings(monitorInfo.szDevice, ENUM_CURRENT_SETTINGS, &dm); int cxPhysical = dm.dmPelsWidth;
return cxPhysical * 1.0 / cxLogical;}测试
对于 1920 × 1080 的分辨率,截一次屏在 30ms 左右,下面是测试代码:
#include "Screenshot.h"using namespace cv;
int main(){ Screenshot screenshot; Mat img = screenshot.getScreenshot(); Mat img_ = screenshot.getScreenshot(1040, 132, 800, 880); imwrite("screenshot.jpg", img); imwrite("screenshot_part.jpg", img_); return 0;} Share
If this article helped you, please share it with others!
如何使用 C++ 和 OpenCV 实现截屏
https://blog.aegisr.xyz/posts/screenshot-with-cpp-opencv/ Some information may be outdated
Related Posts Smart
1
如何在pyqt中实现丝滑滚动字幕
技术 通过定时器定时刷新加绘制两段完整的字符串,实现 PyQt 中的丝滑滚动字幕效果.
2
如何美化 Matplotlib 的工具栏和绘图风格
技术 matplotlib 功能十分强大,就是工具栏丑了点。本文介绍如何魔改 matplotlib 的工具栏样式,并分享一份按照 MATLAB 编写的 matplotlib 样式文件。
3
如何美化 Matplotlib 3D坐标系
技术 ~mpl_toolkits.mplot3d 生成的3D坐标系背景色是灰色的,刻度线也向内延伸了。本文介绍如何修改背景色和刻度线方向,一劳永逸地解决这两个问题。
4
IDEA 添加 Maven Archetype 无效的处理
技术 在 IDEA 中点击新建 Maven 模块,会发现他已经为我们罗列出来了许多的 archetype,但有些时候满足不了我们的需求。
5
《声之形》:声音若有形状,那一定是和解的模样
小说 初看时,我以为它在讲校园欺凌;再看时,我发觉它在讲自我救赎。