如何在OpenCV中捕获桌面(即将位图转换为Mat)?
我想使用OpenCV来处理我的桌面,就好像它是一个videostream。
我熟悉OpenCV。
我不熟悉Windows API。 我意识到还有其他方法来捕获屏幕,但为了我的问题,我需要使用OpenCV来完成。
这是我的(超天真的)代码:
HWND hDesktopWnd; HDC hDesktopDC; hDesktopWnd=GetDesktopWindow(); hDesktopDC=GetDC(hDesktopWnd); // get the height and width of the screen int height = GetSystemMetrics(SM_CYVIRTUALSCREEN); int width = GetSystemMetrics(SM_CXVIRTUALSCREEN); // create a bitmap HBITMAP hbDesktop = CreateCompatibleBitmap( hDesktopDC, width, height); Mat src(height,width,CV_8UC4); src.data = (uchar*)hbDesktop; imshow("output",src); //fails :(
在StackOverflow上也有类似的问题,但是它们是旧式的OpenCV或者Android操作系统。
我在Windows 7 64x
Opencv 2.4.3
谢谢能回答这个问题的人。
经过很长时间的反复试验,我设法写了一个函数来做到这一点。 这里是任何人想要的:
#include "stdafx.h" #include "opencv2/core/core.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <opencv2/highgui/highgui.hpp> #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/2; //change this to whatever size you want to resize to width = windowsize.right/2; 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; }
做一个更好的方法就是将内存分配给像素一次。 所以这里唯一完成的是BitBlt制作的
int main() { int x_size = 800, y_size = 600; // <-- Your res for the image HBITMAP hBitmap; // <-- The image represented by hBitmap Mat matBitmap; // <-- The image represented by mat // Initialize DCs HDC hdcSys = GetDC(NULL); // Get DC of the target capture.. HDC hdcMem = CreateCompatibleDC(hdcSys); // Create compatible DC void *ptrBitmapPixels; // <-- Pointer variable that will contain the potinter for the pixels // Create hBitmap with Pointer to the pixels of the Bitmap BITMAPINFO bi; HDC hdc; ZeroMemory(&bi, sizeof(BITMAPINFO)); bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth = x_size; bi.bmiHeader.biHeight = -y_size; //negative so (0,0) is at top left bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 32; hdc = GetDC(NULL); hBitmap = CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, &ptrBitmapPixels, NULL, 0); // ^^ The output: hBitmap & ptrBitmapPixels // Set hBitmap in the hdcMem SelectObject(hdcMem, hBitmap); // Set matBitmap to point to the pixels of the hBitmap matBitmap = Mat(y_size, x_size, CV_8UC4, ptrBitmapPixels, 0); // ^^ note: first it is y, then it is x. very confusing // * SETUP DONE * // Now update the pixels using BitBlt BitBlt(hdcMem, 0, 0, x_size, y_size, hdcSys, 0, 0, SRCCOPY); // Just to do some image processing on the pixels.. (Dont have to to this) Mat matRef = matBitmap(Range(100, 200), Range(100, 200)); // y1 y2 x1 x2 bitwise_not(matRef, matRef); // Invert the colors in this x1,x2,y1,y2 // Display the results through Mat imshow("Title", matBitmap); // Wait until some key is pressed waitKey(0); return 0; }
请注意,没有error handling在这里做了简单的理解,但你必须在你的代码中进行error handling!
希望这可以帮助