C++调用opencv和windows api完成桌面窗口截图——以梦幻西游为例

这篇具有很好参考价值的文章主要介绍了C++调用opencv和windows api完成桌面窗口截图——以梦幻西游为例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

程序简介

项目编写的C++程序,根据输入的字符串,遍历所有桌面窗口标题,查找包含该标题的窗口,对该桌面窗口进行截图,以梦幻西游为例

输入:桌面窗口包含的字符串 比如输入“梦幻”,程序就会截取桌面“梦幻西游”的窗口

输出:该桌面窗口的截图,数据类型为opencv的Mat矩阵

在这里插入图片描述

程序/数据集下载

点击进入下载地址

c++以句柄截屏窗口图像,功能,C++,c++,opencv,windows

本文章只发布于博客园爆米算法CSDN,被抄袭后可能排版错乱或下载失效,作者:爆米LiuChen

代码环境、文件结构

VS2019 注意链接器需要加入dwmapi.lib,用来调用windows的API opencv4.5.5

在这里插入图片描述# 代码分析

FindWindow.h声明了查找和定位窗口的函数,定义解析请看下文

#pragma once
#include <dwmapi.h>
#include <windows.h> 
#include <vector> 
#include <string>  
#include <iostream>

struct WindowData;

BOOL CALLBACK WindowEnumerationCallback(HWND hwnd, LPARAM lParam);

HWND getWindowHWND(std::string titleSection);

RECT getWindowLoc(HWND hwnd);

FindWindow.cpp中核心函数getWindowHWND可以根据输入的窗口标题字符串,定位到含有该字符串的窗口,返回窗口句柄HWND,然后将句柄输入getWindowLoc函数,得到窗口的位置,这里调用了windows api DwmGetWindowAttribute,如果用传统的方法GetWindowRect会得到错误的结果,因为传统方法没考虑到桌面缩放且自windows vista后的系统桌面窗口加入了“毛玻璃边缘”效果,得到的窗口位置会有偏移

#include "FindWindow.h"

struct WindowData {
    HWND handle;//窗口句柄
    char title[256];//窗口标题
};

std::vector<WindowData> windowDatas;

// 声明回调函数  
BOOL CALLBACK WindowEnumerationCallback(HWND hwnd, LPARAM lParam) {
    // 通过IsWindow函数检查窗口是否有效  
    if (IsWindow(hwnd)) {
        // 通过IsWindowEnabled函数检查窗口是否启用  
        if (IsWindowEnabled(hwnd)) {
            // 通过IsWindowVisible函数检查窗口是否可见  
            if (IsWindowVisible(hwnd)) {
                // 获取窗口的文本,并打印  
                char windowText[256];
                GetWindowTextA(hwnd, windowText, sizeof(windowText));
                WindowData windowData;
                windowData.handle = hwnd;
                memcpy(windowData.title, windowText, 256);
                windowDatas.push_back(windowData);
            }
        }
    }
    // 继续枚举其他窗口  
    return TRUE;
}

//返回包含titleSection的桌面窗口句柄
HWND getWindowHWND(std::string titleSection)
{
    HWND handle = NULL;
    //每次都要清空容器
    windowDatas.clear();
    // 使用EnumWindows函数枚举所有窗口,并传递给回调函数处理  
    EnumWindows(WindowEnumerationCallback, NULL);
    //一个个找包含指定字符串的
    for (auto it = windowDatas.begin(); it != windowDatas.end(); it++)
    {
        char title[256];
        memcpy(title, it->title, 256);
        std::string windowTitle(title);
        if (windowTitle.find(titleSection) != std::string::npos)
        {
            handle = it->handle;
        }
    }
    return handle;
}


//根据窗口句柄和桌面缩放获得窗口尺寸和位置
RECT getWindowLoc(HWND hwnd)
{
    RECT frame;
    DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &frame, sizeof(RECT));
    //std::cout << "窗口位置:(" << frame.left << ", " << frame.top << ")" << std::endl;
    //std::cout << "窗口大小:(" << frame.right-frame.left << ", " << frame.bottom-frame.top << ")" << std::endl;
    return frame;
}

WindowShot.h声明了根据坐标和尺寸的截图函数,定义解析请看下文

#pragma once
#include "FindWindow.h"
#include <opencv2/opencv.hpp>

struct WindowRect
{
    int x;
    int y;
    int width;
    int height;
};

class WindowShot
{
public:
    WindowShot();
    double static getZoom();
    cv::Mat getWindowMat(std::string titleSection);
    uchar* getWindowUchar(std::string titleSection);
    WindowRect windowRect;
    cv::Mat getDesktopMat();
    ~WindowShot();

private:
    int width;
    int height;
    double zoom;
    uchar* windowUchar;
    RECT rect;
    HDC screenDC;
    HDC compatibleDC;
    HBITMAP hBitmap;
    LPVOID shotData;
    HWND hwnd;
};

WindowShot.cpp定义了核心函数getWindowMat,该函数会调用FindWindow模块来查找窗口的句柄和位置,然后对整个屏幕具体的位置进行截图,当然同时也定义了getDesktopMat函数用来截图整个桌面,不同的是这个函数用到了个人桌面缩放率

#include "WindowShot.h"

//初始化变量
WindowShot::WindowShot()
{
    zoom = getZoom();//缩放率 比如1.25
}


//根据窗口标题是否包含该字符串,获得窗口截图
cv::Mat WindowShot::getWindowMat(std::string titleSection)
{
    hwnd = getWindowHWND(titleSection);
    //如果窗口小化 就将其展示 
    if (IsIconic(hwnd)) {
        ShowWindow(hwnd, SW_RESTORE);
    }
    SetForegroundWindow(hwnd); // 将窗口置顶  
    rect = getWindowLoc(hwnd); // 窗口位置
    width = rect.right - rect.left;
    height = rect.bottom - rect.top;
    windowRect.x = rect.left;
    windowRect.y = rect.top;
    windowRect.width = width;
    windowRect.height = height;
    shotData = new char[width * height * 4];
    screenDC = GetDC(NULL);// 获取屏幕 DC
    compatibleDC = CreateCompatibleDC(screenDC);//兼容新DC
    // 创建位图
    hBitmap = CreateCompatibleBitmap(screenDC, width, height);
    SelectObject(compatibleDC, hBitmap);
    // 得到位图的数据
    BitBlt(compatibleDC, 0, 0, width, height, screenDC, rect.left, rect.top, SRCCOPY);
    GetBitmapBits(hBitmap, width * height * 4, shotData);
    // 创建图像
    cv::Mat windowMat(height, width, CV_8UC4, shotData);
    return windowMat;
}

//根据窗口标题是否包含该字符串,获得窗口截图 将截图转为uchar* 供python使用
uchar* WindowShot::getWindowUchar(std::string titleSection)
{
    cv::Mat windowMat = this->getWindowMat(titleSection);
    int size = width * height * 4;
    free(windowUchar);
    windowUchar = (uchar*)malloc(sizeof(uchar) * size);
    memcpy(windowUchar, windowMat.data, size);
    return windowUchar;
}

cv::Mat WindowShot::getDesktopMat()
{
    width = GetSystemMetrics(SM_CXSCREEN) * zoom;
    height = GetSystemMetrics(SM_CYSCREEN) * zoom;
    rect.left = 0;
    rect.top = 0;
    rect.right = width;
    rect.bottom = height;
    width = rect.right - rect.left;
    height = rect.bottom - rect.top;
    shotData = new char[width * height * 4];
    screenDC = GetDC(NULL);// 获取屏幕 DC
    compatibleDC = CreateCompatibleDC(screenDC);//兼容新DC
    // 创建位图
    hBitmap = CreateCompatibleBitmap(screenDC, width, height);
    SelectObject(compatibleDC, hBitmap);
    // 得到位图的数据
    BitBlt(compatibleDC, 0, 0, width, height, screenDC, rect.left, rect.top, SRCCOPY);
    GetBitmapBits(hBitmap, width * height * 4, shotData);
    // 创建图像
    cv::Mat desktopMat(height, width, CV_8UC4, shotData);
    return desktopMat;
}

/* 获取屏幕缩放值 */
double WindowShot::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;
}

WindowShot::~WindowShot()
{
    DeleteObject(hBitmap);
    DeleteDC(compatibleDC);
}

结果展示

运行一下main.cpp,得到梦幻西游的窗口截图(文章开头已给出),对比下整个桌面截图

在这里插入图片描述文章来源地址https://www.toymoban.com/news/detail-832713.html

到了这里,关于C++调用opencv和windows api完成桌面窗口截图——以梦幻西游为例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Flink窗口(2)—— Window API

    目录 窗口分配器 时间窗口 计数窗口 全局窗口 窗口函数 增量聚合函数 全窗口函数(full window functions) 增量聚合和全窗口函数的结合使用 Window API 主要由两部分构成: 窗口分配器 (Window Assigners)和 窗口函数 (Window Functions) 在window()方法中传入一个窗口分配器; 在aggreg

    2024年01月16日
    浏览(37)
  • Windows API遍历桌面上所有文件

    要获取桌面上的图标,可以使用Windows API中的Shell API。以下是遍历桌面上所有文件的示例代码:   在这个示例中,通过调用`SHGetFolderPathW`函数来获取桌面文件夹的路径。然后使用`FindFirstFileW`和`FindNextFileW`遍历桌面上的所有文件和文件夹。我们只对文件感兴趣,所以在循环中排

    2024年02月16日
    浏览(49)
  • postman-使用Postman的模拟服务来模拟(mock)后端数据,完成前端模拟API调用

    最近项目上比较忙,任务多时间紧,导致后端开发任务繁多,无法及时开发完毕,但是前端同学已经把对应功能开发完成,需要进行前后端联调来验证API及一些交互问题;这不能因为后端的进度来影响前端的工作完成情况,因此,Postman的mock数据功能就用了,确实好用。 Set

    2024年02月11日
    浏览(49)
  • 从零开始学习调用百度地图网页API:二、初始化地图,鼠标交互创建信息窗口

    注 :需要将 你的ak 替换,从百度地图官网注册申请。 脚本中使用BMap创建Map实例,centerAndZoom()初始化地图设置中心点为北京,地图等级15。enableScrollWheelZoom()鼠标滚轮可缩放窗口。addEventListener监听鼠标点击事件,发生后,传递事件e至function(e),执行openInfoWindow,在鼠标点击坐

    2024年02月07日
    浏览(57)
  • 关于Windows桌面远程后,unity程序无法全屏显示或者显示窗口默认最小化解决方法

    按以下步骤操作 1、Win+R打开运行,然后输入regedit打开注册表 2、根据计算机HKEY_CURRENT_USERSoftwareDefaultCompany路径找到DefaultCompany的文件夹 3、在DefaultCompany文件夹下找到unity打包时exe文件对应名称的文件夹,右键删除整个文件夹,删除后再去启动unity.exe程序即可恢复正常显示画

    2024年04月10日
    浏览(81)
  • Qt开发_调用OpenCV(4.x)完成人脸检测并绘制马赛克(摄像头实时数据)

    这个基于Qt和OpenCV的人脸检测和人脸打码项目是通过实时视频流中的人脸识别来保护隐私。 该项目目的是保护隐私并确保人脸数据安全。在某些情况下,使用实时视频流进行人脸检测和识别可能涉及对个人隐私的侵犯。通过在图像中打码人脸区域,可以避免未经许可的人脸出

    2024年02月06日
    浏览(58)
  • 第11课 利用windows API捕获桌面图像并通过FFmpeg分享

    在上一章,我们已经实现了一对一音视频对话功能。在实际应用中,我们常需要把自己的电脑桌面分享给他人以实现桌面共享功能,这种功能在视频会议、在线教学等场景中很常见,这种功能如何实现呢?这节课我们就来解决这个问题。 1.备份demo9并修改demo9为demo11。 2.在fm

    2024年02月03日
    浏览(35)
  • API Monitor简易使用教程 监控Windows dll调用 监控Windows API调用 查看函数名,参数类型,参数,返回值

    1、API Filter窗口:选定要监听的dll函数或windows API,可以打断点 选中并右键勾上Breakpoint 选 Before Call 2、Monitor New Process 窗口 :选择要运行的exe 3、Summary窗口:会列出所有调用的函数。点函数,查看函数名,参数类型,参数,返回值等。还能设断点。 当调用到断点的函数调用时

    2024年01月21日
    浏览(50)
  • Opencv C++实现yolov5部署onnx模型完成目标检测

    头文件 命名空间 结构体 Net_config 里面存了三个阈值和模型地址,其中 置信度 ,顾名思义,看检测出来的物体的精准度。以测量值为中心,在一定范围内,真值出现在该范围内的几率。 endsWith()函数 判断sub是不是s的子串 anchors_640图像接收数组 根据图像大小,选择相应长度的

    2024年02月13日
    浏览(41)
  • Windows下使用QT+OpenCV完成人脸检测(获取摄像头的数据进行检测)

    Windows版本: Win10 X64 OpenCV版本: 2.4.13.6 QT版本: 5.12 OpenCV官网下载地址: ​ ​https://opencv.org​​​     目前官网OpenCV最新的版本是4.2.0 ,Windows版本的OpenCV在3.X版本后就不带X86的库,只有X64的库,如果需要X86的库,需要自己下载源码去重新编译。 由于我的QT软件在安装时没有安装

    2024年01月16日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包