程序簡(jiǎn)介
項(xiàng)目編寫的C++程序,根據(jù)輸入的字符串,遍歷所有桌面窗口標(biāo)題,查找包含該標(biāo)題的窗口,對(duì)該桌面窗口進(jìn)行截圖,以夢(mèng)幻西游為例
輸入:桌面窗口包含的字符串 比如輸入“夢(mèng)幻”,程序就會(huì)截取桌面“夢(mèng)幻西游”的窗口
輸出:該桌面窗口的截圖,數(shù)據(jù)類型為opencv的Mat矩陣
程序/數(shù)據(jù)集下載
點(diǎn)擊進(jìn)入下載地址
本文章只發(fā)布于博客園、爆米算法、CSDN,被抄襲后可能排版錯(cuò)亂或下載失效,作者:爆米LiuChen
代碼環(huán)境、文件結(jié)構(gòu)
VS2019 注意鏈接器需要加入dwmapi.lib,用來調(diào)用windows的API opencv4.5.5# 代碼分析
FindWindow.h聲明了查找和定位窗口的函數(shù),定義解析請(qǐng)看下文
#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中核心函數(shù)getWindowHWND可以根據(jù)輸入的窗口標(biāo)題字符串,定位到含有該字符串的窗口,返回窗口句柄HWND,然后將句柄輸入getWindowLoc函數(shù),得到窗口的位置,這里調(diào)用了windows api DwmGetWindowAttribute,如果用傳統(tǒng)的方法GetWindowRect會(huì)得到錯(cuò)誤的結(jié)果,因?yàn)閭鹘y(tǒng)方法沒考慮到桌面縮放且自windows vista后的系統(tǒng)桌面窗口加入了“毛玻璃邊緣”效果,得到的窗口位置會(huì)有偏移
#include "FindWindow.h"
struct WindowData {
HWND handle;//窗口句柄
char title[256];//窗口標(biāo)題
};
std::vector<WindowData> windowDatas;
// 聲明回調(diào)函數(shù)
BOOL CALLBACK WindowEnumerationCallback(HWND hwnd, LPARAM lParam) {
// 通過IsWindow函數(shù)檢查窗口是否有效
if (IsWindow(hwnd)) {
// 通過IsWindowEnabled函數(shù)檢查窗口是否啟用
if (IsWindowEnabled(hwnd)) {
// 通過IsWindowVisible函數(shù)檢查窗口是否可見
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);
}
}
}
// 繼續(xù)枚舉其他窗口
return TRUE;
}
//返回包含titleSection的桌面窗口句柄
HWND getWindowHWND(std::string titleSection)
{
HWND handle = NULL;
//每次都要清空容器
windowDatas.clear();
// 使用EnumWindows函數(shù)枚舉所有窗口,并傳遞給回調(diào)函數(shù)處理
EnumWindows(WindowEnumerationCallback, NULL);
//一個(gè)個(gè)找包含指定字符串的
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;
}
//根據(jù)窗口句柄和桌面縮放獲得窗口尺寸和位置
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聲明了根據(jù)坐標(biāo)和尺寸的截圖函數(shù),定義解析請(qǐng)看下文
#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定義了核心函數(shù)getWindowMat,該函數(shù)會(huì)調(diào)用FindWindow模塊來查找窗口的句柄和位置,然后對(duì)整個(gè)屏幕具體的位置進(jìn)行截圖,當(dāng)然同時(shí)也定義了getDesktopMat函數(shù)用來截圖整個(gè)桌面,不同的是這個(gè)函數(shù)用到了個(gè)人桌面縮放率
#include "WindowShot.h"
//初始化變量
WindowShot::WindowShot()
{
zoom = getZoom();//縮放率 比如1.25
}
//根據(jù)窗口標(biāo)題是否包含該字符串,獲得窗口截圖
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
// 創(chuàng)建位圖
hBitmap = CreateCompatibleBitmap(screenDC, width, height);
SelectObject(compatibleDC, hBitmap);
// 得到位圖的數(shù)據(jù)
BitBlt(compatibleDC, 0, 0, width, height, screenDC, rect.left, rect.top, SRCCOPY);
GetBitmapBits(hBitmap, width * height * 4, shotData);
// 創(chuàng)建圖像
cv::Mat windowMat(height, width, CV_8UC4, shotData);
return windowMat;
}
//根據(jù)窗口標(biāo)題是否包含該字符串,獲得窗口截圖 將截圖轉(zhuǎn)為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
// 創(chuàng)建位圖
hBitmap = CreateCompatibleBitmap(screenDC, width, height);
SelectObject(compatibleDC, hBitmap);
// 得到位圖的數(shù)據(jù)
BitBlt(compatibleDC, 0, 0, width, height, screenDC, rect.left, rect.top, SRCCOPY);
GetBitmapBits(hBitmap, width * height * 4, shotData);
// 創(chuàng)建圖像
cv::Mat desktopMat(height, width, CV_8UC4, shotData);
return desktopMat;
}
/* 獲取屏幕縮放值 */
double WindowShot::getZoom()
{
// 獲取窗口當(dāng)前顯示的監(jiān)視器
HWND hWnd = GetDesktopWindow();
HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
// 獲取監(jiān)視器邏輯寬度
MONITORINFOEX monitorInfo;
monitorInfo.cbSize = sizeof(monitorInfo);
GetMonitorInfo(hMonitor, &monitorInfo);
int cxLogical = (monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left);
// 獲取監(jiān)視器物理寬度
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);
}
結(jié)果展示
運(yùn)行一下main.cpp,得到夢(mèng)幻西游的窗口截圖(文章開頭已給出),對(duì)比下整個(gè)桌面截圖文章來源:http://www.zghlxwxcb.cn/news/detail-832713.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-832713.html
到了這里,關(guān)于C++調(diào)用opencv和windows api完成桌面窗口截圖——以夢(mèng)幻西游為例的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!