如何使用 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;
}
如何使用 C++ 和 OpenCV 实现截屏的更多相关文章
- Linux系统安装MySql步骤及截屏
➠更多技术干货请戳:听云博客 如下是我工作中的记录,介绍的是linux系统下使用官方编译好的二进制文件进行安装MySql的安装过程和安装截屏,这种安装方式速度快,安装步骤简单! 需要的朋友可以按照如下 ...
- Android使用C++截屏并显示
使用android底层自带的截屏源码进行修改后,将截取屏幕的内容再次显示在屏幕上,使屏幕呈现出暂停的效果. android自带的截屏代码在android\JB\frameworks\base\cmds ...
- FFmpeg 转码和截屏
转码 (flv转码为MP4,libx264是MP4编码格式 , -b 3000k是码率,比特率) ffmpeg -i /home/ghr/mp4/mp4.flv -vcodec libx264 -b ...
- 使用Python中PIL图形库进行截屏
目的:通过使用Python的一个图形库PIL(Python Image Library)对屏幕进行截图 步骤: 1.下载PIL(路径)并安装 2.新建文件“截屏.py”,右键Edit with IDL ...
- MonoGame 3.2 下,截屏与 Texture2D 的保存
10月20日注:后来发现了这篇博文(英文),XNA 中的 Color 实际上是与 Alpha 值自左乘(premultiplied)的,这也解释了直接用 0xARGB 转译而颜色异常的原因. 注意,由 ...
- 纯C#实现屏幕指定区域截屏
以前在别的地方见过一个通过调用系统API实现屏幕截图的例子,从内心来说我不太喜欢在C#代码中出现这种情况,现在什么都讲“和谐”,我觉得这种做法就是破坏了我们的“和谐”代码,呵呵,开玩笑,有的时候,不通 ...
- C#截屏
本实例代码实现了WinForm截屏保存为图片,亲测可行. 界面截图: 下载:http://hovertree.com/h/bjaf/scjyuanma.htm 以下代码可以实际运行,在项目HoverT ...
- OpenGL 多视图与截屏
最近看红宝书学习 OpenGL 一段时间了,写了简单的 demo 程序温习一下知识. 主要是 使用 glScissor 多视图显示画面和使用 glReadPixels 给画面截屏,使用显示列表(dis ...
- iOS检测用户截屏并获取所截图片
iOS检测用户截屏并获取所截图片 微信可以检测到用户截屏行为(Home + Power),并在稍后点击附加功能按钮时询问用户是否要发送刚才截屏的图片,这个用户体验非常好.在iOS7之前, 如果用户截屏 ...
随机推荐
- hdu 5592 ZYB's Premutation(线段树优化)
设f_ifi是第ii个前缀的逆序对数,p_ipi是第ii个位置上的数,则f_i-f_{i-1}fi−fi−1是ii前面比p_ipi大的数的个数.我们考虑倒着做,当我们处理 ...
- mod4最优路径问题(转载)
原文链接:https://blog.csdn.net/ACdreamers/article/details/18501855 mod4最优路径问题 如下图: 从1到4找出一条路径,要求路径的总长度mo ...
- pytest之 fixture 实现机制
一.相同测试数据存放优化 在讲 fixture 实现机制之前,插入一段内容 上次有个小伙伴问我说,类似下面的用例代码情况,每条测试用例的数据都一样的,我们可以怎么进行优化吗? 当然是可以的 其实我们可 ...
- [C++]高效C/C ++编程tips
Effective C++ 视C++ 为一个语言联邦(C.Object-Oriented C++.Template C++.STL) 宁可以编译器替换预处理器(尽量以const.enum.inline ...
- [多线程]async异步操作的使用实例及不同策略的对比
#include <iostream> #include <thread> #include <mutex> #include <iostream> / ...
- CS5262设计DP转HDMI 4K60HZ +VGA 1080P方案芯片
CS5262是一款带嵌入式MCU的4通道DisplayPort1.4到HDMI2.0/VGA转换器芯片,设计用于将DP1.4信号源连接到HDMI2.0接收器.CS5262集成了DP1.4兼容接收机和H ...
- tcache BUUCTF gyctf_2020_signin
Ubuntu18.04的题 用到了两个特性: 一个是 calloc 的特点:不会分配 tcache chunk 中的 chunk 另一个是 tcache 的特点:在分配 fastbin 中的 chun ...
- Java实习生常规技术面试题每日十题Java基础(一)
目录 1.Java 的 "一次编写,处处运行"如何实现? 2.描述JVM运行原理. 3.为什么Java没有全局变量? 4.说明一下public static void main(S ...
- Java初学者作业——编写Java程序, 在控制台输入数字,计算表达式1-2+3-4……+(2*n-1)+2*n的结果。
返回本章节 返回作业目录 需求说明: 编写Java程序, 在控制台输入数字 计算表达式1-2+3-4--+(2*n-1)+2*n的结果. 实现思路: (1)声明变量 n 和 sum,用于存储用户输入的 ...
- 编写Java程序,前方有 3km 的道路障碍,4 辆普通车不能通过,必须等到清障车完成作业离开后,才能继续行驶。用程序来模拟这一过程的发生
查看本章节 查看作业目录 需求说明: 前方有 3km 的道路障碍,4 辆普通车不能通过,必须等到清障车完成作业离开后,才能继续行驶.用程序来模拟这一过程的发生 实现思路: 创建清障车Wrecker类和 ...