C++ 从窗口截图匹配模板 我所做的
我有一个小的模板图像,用于在一个较大的屏幕截图图像中查找匹配子图像的坐标。屏幕截图本身在C++ 从窗口截图匹配模板 我所做的,c++,opencv,computer-vision,gdi,template-matching,C++,Opencv,Computer Vision,Gdi,Template Matching,我有一个小的模板图像,用于在一个较大的屏幕截图图像中查找匹配子图像的坐标。屏幕截图本身在BitBlt的帮助下被捕获到内存DC中,然后通过GetDIBits转换成cv::Mat,如下所示: HDC windowDc = GetWindowDC(hwndTarget); HDC memDc = CreateCompatibleDC(windowDc); // ... HBITMAP hbmp = CreateCompatibleBitmap(windowDc, width, height); S
BitBlt
的帮助下被捕获到内存DC中,然后通过GetDIBits
转换成cv::Mat
,如下所示:
HDC windowDc = GetWindowDC(hwndTarget);
HDC memDc = CreateCompatibleDC(windowDc);
// ...
HBITMAP hbmp = CreateCompatibleBitmap(windowDc, width, height);
SelectObject(memDc, hbmp);
BITMAPINFOHEADER bi =
{
sizeof(BITMAPINFOHEADER), // biSize
width, // biWidth
-height, // biHeight
1, // biPlanes
32, // biBitCount
BI_RGB, // biCompression
0, // biSizeImage
0, // biXPelsPerMeter
0, // biYPelsPerMeter
0, // biClrUser
0 // biClrImportant
};
// ...
BitBlt(memDc, 0, 0, width, height, windowDc, offsetX, offsetY, SRCCOPY);
matScreen.create(height, width, CV_8UC4);
GetDIBits(memDc, hbmp, 0, (UINT)height, matScreen.data, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
这似乎工作正常,一个快速的imshow(“Source”,matScreen)
会正确显示图像
然而。。。
由于此屏幕截图图像已创建为32位RGB内存位图,并使用cv_8UC4
标志放置在cv::Mat
中,因此它会使OpenCV中的多个断言失败(以及在使用多个OpenCV方法时输出异常结果)。最值得注意的是,matchTemplate
始终在以下行失败:
CV_Assert( (depth == CV_8U || depth == CV_32F) && type == _templ.type() && _img.dims() <= 2 );
CV_Assert((depth==CV_8U | | depth==CV_32F)&&type==temp.type()&&&img.dims()我已经包含了从桌面图像中查找模板图像的代码。希望这能解决您的问题
#include <fstream>
#include <memory>
#include <string>
#include <iostream>
#include <strstream>
#include <functional>
#include <Windows.h>
#include <iostream>
#include <string>
using namespace std;
using namespace cv;
Mat hwnd2mat(HWND hwnd){
HDC hwindowDC,hwindowCompatibleDC;
int height,width,srcheight,srcwidth;
HBITMAP hbwindow;
Mat src;
BITMAPINFOHEADER bi;
hwindowDC=GetDC(hwnd);
hwindowCompatibleDC=CreateCompatibleDC(hwindowDC);
SetStretchBltMode(hwindowCompatibleDC,COLORONCOLOR);
RECT windowsize; // get the height and width of the screen
GetClientRect(hwnd, &windowsize);
srcheight = windowsize.bottom;
srcwidth = windowsize.right;
height = windowsize.bottom; //change this to whatever size you want to resize to
width = windowsize.right;
src.create(height,width,CV_8UC4);
// create a bitmap
hbwindow = CreateCompatibleBitmap( hwindowDC, width, height);
bi.biSize = sizeof(BITMAPINFOHEADER); //http://msdn.microsoft.com/en-us/library/windows/window/dd183402%28v=vs.85%29.aspx
bi.biWidth = width;
bi.biHeight = -height; //this is the line that makes it draw upside down or not
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
// use the previously created device context with the bitmap
SelectObject(hwindowCompatibleDC, hbwindow);
// copy from the window device context to the bitmap device context
StretchBlt( hwindowCompatibleDC, 0,0, width, height, hwindowDC, 0, 0,srcwidth,srcheight, SRCCOPY); //change SRCCOPY to NOTSRCCOPY for wacky colors !
GetDIBits(hwindowCompatibleDC,hbwindow,0,height,src.data,(BITMAPINFO *)&bi,DIB_RGB_COLORS); //copy from hwindowCompatibleDC to hbwindow
// avoid memory leak
DeleteObject (hbwindow); DeleteDC(hwindowCompatibleDC); ReleaseDC(hwnd, hwindowDC);
return src;
}
bool NMultipleTemplateMatching(Mat mInput,Mat mTemplate,float Threshold,float Closeness,vector<Point2f> &List_Matches)
{
Mat mResult;
Size szTemplate= mTemplate.size();
Size szTemplateCloseRadius((szTemplate.width/2)* Closeness,(szTemplate.height/2)* Closeness);
matchTemplate(mInput, mTemplate, mResult, TM_CCOEFF_NORMED);
threshold(mResult, mResult, Threshold, 1.0, THRESH_TOZERO);
while (true)
{
double minval, maxval ;
Point minloc, maxloc;
minMaxLoc(mResult, &minval, &maxval, &minloc, &maxloc);
if (maxval >= Threshold)
{
List_Matches.push_back(maxloc);
rectangle(mResult,Point2f(maxloc.x-szTemplateCloseRadius.width,maxloc.y-szTemplateCloseRadius.height),Point2f(maxloc.x+szTemplateCloseRadius.width,maxloc.y+szTemplateCloseRadius.height),Scalar(0),-1);
}
else
break;
}
//imshow("reference", mDebug_Bgr);
return true;
}
int main(int argc, char** argv)
{
Mat mTemplate_Bgr,mTemplate_Gray;
mTemplate_Bgr= imread("Template.png",1);
imshow("mTemplate_Bgr",mTemplate_Bgr);
要扩展Balaji非常有用的答案,请确保传递给函数的所有Mat
与.type()
函数的类型相同。您可以将src.create(height,width,cv8uc4);
更改为与模板相同的类型(反之亦然)错误应该消失。我应该注意模板图像是一个32位PNG文件,以防matters@meneldal是的,但是我该怎么做才能在不损坏源图像的情况下纠正此问题呢?CV_8UC4
似乎是正确显示源图像的唯一标志……因此,也许有一种方法可以转换要使用的位图,比如说,CV_32F
?同样,断言检查失败。奇怪的是,在调试过程中,如果在断言后的下一行使用“Set Next Statement”,则不会发生崩溃,图像是(我相信)正确显示,但模板匹配坐标仍然错误。我认为如果我设法将位图数据转换为直接的CV_8U
或CV_32F
,OpenCV最终会玩得更好,但我不能100%确定如何更新此问题以包括源链接谢谢!不确定我做错了什么,但至少是这样有一个有效的解决方案。
HWND hDesktopWnd;
hDesktopWnd=GetDesktopWindow();
Mat mScreenShot= hwnd2mat(hDesktopWnd);
Mat mSource_Gray,mResult_Bgr= mScreenShot.clone();
float Threshold= 0.9;
float Closeness= 0.9;
vector<Point2f> List_Matches;
cvtColor(mScreenShot,mSource_Gray,COLOR_BGR2GRAY);
cvtColor(mTemplate_Bgr,mTemplate_Gray,COLOR_BGR2GRAY);
namedWindow("Screen Shot",WINDOW_AUTOSIZE);
imshow("Screen Shot",mSource_Gray);
NMultipleTemplateMatching(mSource_Gray,mTemplate_Gray,Threshold,Closeness,List_Matches);
for (int i = 0; i < List_Matches.size(); i++)
{
rectangle(mResult_Bgr,List_Matches[i],Point(List_Matches[i].x + mTemplate_Bgr.cols, List_Matches[i].y + mTemplate_Bgr.rows),Scalar(0,255,0), 2);
}
imshow("Final Results",mResult_Bgr);
waitKey(0);
return 0;
}