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;
}