前言

实现屏幕截屏需要用到 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 实现截屏的更多相关文章

  1. Linux系统安装MySql步骤及截屏

    ➠更多技术干货请戳:听云博客 如下是我工作中的记录,介绍的是linux系统下使用官方编译好的二进制文件进行安装MySql的安装过程和安装截屏,这种安装方式速度快,安装步骤简单! 需要的朋友可以按照如下 ...

  2. Android使用C++截屏并显示

    使用android底层自带的截屏源码进行修改后,将截取屏幕的内容再次显示在屏幕上,使屏幕呈现出暂停的效果. android自带的截屏代码在android\JB\frameworks\base\cmds ...

  3. FFmpeg 转码和截屏

    转码 (flv转码为MP4,libx264是MP4编码格式 , -b 3000k是码率,比特率) ffmpeg -i /home/ghr/mp4/mp4.flv -vcodec libx264 -b ...

  4. 使用Python中PIL图形库进行截屏

    目的:通过使用Python的一个图形库PIL(Python Image Library)对屏幕进行截图 步骤: 1.下载PIL(路径)并安装 2.新建文件“截屏.py”,右键Edit with IDL ...

  5. MonoGame 3.2 下,截屏与 Texture2D 的保存

    10月20日注:后来发现了这篇博文(英文),XNA 中的 Color 实际上是与 Alpha 值自左乘(premultiplied)的,这也解释了直接用 0xARGB 转译而颜色异常的原因. 注意,由 ...

  6. 纯C#实现屏幕指定区域截屏

    以前在别的地方见过一个通过调用系统API实现屏幕截图的例子,从内心来说我不太喜欢在C#代码中出现这种情况,现在什么都讲“和谐”,我觉得这种做法就是破坏了我们的“和谐”代码,呵呵,开玩笑,有的时候,不通 ...

  7. C#截屏

    本实例代码实现了WinForm截屏保存为图片,亲测可行. 界面截图: 下载:http://hovertree.com/h/bjaf/scjyuanma.htm 以下代码可以实际运行,在项目HoverT ...

  8. OpenGL 多视图与截屏

    最近看红宝书学习 OpenGL 一段时间了,写了简单的 demo 程序温习一下知识. 主要是 使用 glScissor 多视图显示画面和使用 glReadPixels 给画面截屏,使用显示列表(dis ...

  9. iOS检测用户截屏并获取所截图片

    iOS检测用户截屏并获取所截图片 微信可以检测到用户截屏行为(Home + Power),并在稍后点击附加功能按钮时询问用户是否要发送刚才截屏的图片,这个用户体验非常好.在iOS7之前, 如果用户截屏 ...

随机推荐

  1. Learning a Similarity Metric Discriminatively, with Application to Face Verification

    目录 概 主要内容 genuine 和 impostor 文1 文2 Chopra S, Hadsell R, Lecun Y, et al. Learning a similarity metric ...

  2. Java中对象的内存分配机制

    一.内存划分 Java把内存划分为两种,一种是栈内存,另一种是堆内存. 1.栈内存 在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配.当在一段代码块定义一个变量时,Java就在栈 ...

  3. Drools创建Maven工程

    1.说明 本文介绍创建Drools的Maven工程的方法, 仅使用Eclipse开发工具, 不使用Drools的相关插件, 先创建一个Maven工程, 然后引入Drools的相关依赖即可, 最后再写一 ...

  4. C#自定义转换(implicit 或 explicit)

    C#的类型转换分为显式转换和隐式转换,显式转换需要自己声明转换类型,而隐式转换由编译器自动完成,无需我们声明,如: //long需要显式转换成int long l = 1L; int i = (int ...

  5. Kafka基础教程(一):认识Kafka

    Kafka是Apache下的一个子项目,是一个高性能跨语言分布式发布/订阅消息队列系统,吞吐速率非常快,可以作为Hadoop的日志收集.Kafka是一个完全的分布式系统,这一点依赖于Zookeeper ...

  6. CSS基础 华为渐变色产品列表 综合实战

    华为网页链接:https://www.huawei.com/cn/?ic_medium=direct&ic_source=surlent html代码部分: <div class=&qu ...

  7. Python_魔法属性和方法

    魔法属性 __doc__:表示类或方法的描述信息 __moudle__:表示当前操作对象的模块,当前模块时,显示__main__ __class__:表示当前操作对象的类型 __name__:表示类或 ...

  8. JMeter_事务控制器

    性能测试的结果统计时我们一定会关注TPS,TPS代表的是每秒事务数,每个事务对应的是我们的请求.虽然JMeter能够帮我们把每个请求统计成一个事务,但有时候我们希望把多个操作统计成一个事务,JMete ...

  9. git clone 失败 ,提示 fatal: unable to access 'https://github.com/xxx.git/': OpenSSL SSL_read: Connection was reset, errno 10054

    怎么解决? 把原来的指令 $ git clone https://github.com/cen-xi/express.git 改成 $ git clone git://github.com/cen-x ...

  10. vue将HTML字符串解析为HTML标签

    如果返回的数据是html标签字符串的话,在vue里要通过v-html来渲染 <div v-html="rawHtml"></div> //v-html=&q ...