c++ opencv displaying image on a window - c++

I want to load an image using OpenCV and then display it on a window.
I know how to load an image using opencv and how to create a window using win32 but how do I go about putting the image / mat from Opencv on the window afterwards?
This is how I load the image from opencv:
#include <opencv2/core/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <string>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
string imageName("C:/image.jpg"); // by default
if (argc > 1)
{
imageName = argv[1];
}
Mat image;
image = imread(imageName.c_str(), IMREAD_COLOR);
if (image.empty())
{
cout << "Could not open or find the image" << std::endl;
return -1;
}
namedWindow("Display window", WINDOW_AUTOSIZE);
imshow("Display window", image);
waitKey(0);
return 0;
}
EDIT: The reason I want to do this is actually not to create a window during runtime and then display the image on it, but rather I want to find a window using win32's FindWindow function and then draw an image on that :D

I'm using this pretty often with my MFC projects. If you only have hwnd, not CWnd, then you may have to change a bit.
This works both with 8-bit RGB color and 1-channel monochrome image.
void DrawImage( CWnd *wnd, int width, int height, int bpp, const unsigned char *buffer)
{
RECT rect;
wnd->GetWindowRect(&rect);
CDC *dc = wnd->GetDC();
if( bpp == 3) // BGR
{
BITMAPINFO bmpinfo;
memset(&bmpinfo, 0, sizeof(bmpinfo));
bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpinfo.bmiHeader.biBitCount = 24;
bmpinfo.bmiHeader.biClrImportant = 0;
bmpinfo.bmiHeader.biClrUsed = 0;
bmpinfo.bmiHeader.biCompression = BI_RGB;
bmpinfo.bmiHeader.biWidth = width;
bmpinfo.bmiHeader.biHeight = -height;
bmpinfo.bmiHeader.biPlanes = 1;
bmpinfo.bmiHeader.biSizeImage = 0;
bmpinfo.bmiHeader.biXPelsPerMeter = 100;
bmpinfo.bmiHeader.biYPelsPerMeter = 100;
::SetStretchBltMode( dc->GetSafeHdc(), COLORONCOLOR);
::StretchDIBits( dc->GetSafeHdc(),
0,
0,
rect.right - rect.left,
rect.bottom - rect.top,
0,
0,
width,
height,
buffer,
&bmpinfo,
DIB_RGB_COLORS,
SRCCOPY);
}
else if ( bpp == 1) // monochrome.
{
char bitmapInfoBuf[sizeof(BITMAPINFO) + 4 * 256];
BITMAPINFO* pBmpInfo = (BITMAPINFO*)bitmapInfoBuf;
memset(pBmpInfo, 0, sizeof(BITMAPINFO) + 4 * 256);
pBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pBmpInfo->bmiHeader.biWidth = width;
pBmpInfo->bmiHeader.biHeight = -height;
pBmpInfo->bmiHeader.biCompression = BI_RGB;
pBmpInfo->bmiHeader.biPlanes = 1;
pBmpInfo->bmiHeader.biBitCount = 8;
for(int i = 0; i < 256; i++)
{
pBmpInfo->bmiColors[i].rgbBlue=i;
pBmpInfo->bmiColors[i].rgbGreen=i;
pBmpInfo->bmiColors[i].rgbRed=i;
pBmpInfo->bmiColors[i].rgbReserved=255;
}
::SetStretchBltMode( dc->GetSafeHdc(), COLORONCOLOR);
::StretchDIBits( dc->GetSafeHdc(),
0,
0,
rect.right - rect.left,
rect.bottom - rect.top,
0,
0,
width,
height,
buffer,
pBmpInfo,
DIB_RGB_COLORS,
SRCCOPY);
}
wnd->ReleaseDC(dc);
}
void DrawCVImage(cv::Mat image, CWnd *picture)
{
if (image.cols % 4 == 0)
{
DrawImage(picture,
image.cols,
image.rows,
image.channels() == 3 ? 3 : 1,
image.data);
}
else
{
Mat image2(image.rows, image.cols + ( 4 - image.cols % 4), image.type());
image2 = 0;
image.copyTo(image2(Rect(0, 0, image.cols, image.rows)));
DrawImage(picture,
image2.cols,
image2.rows,
image2.channels() == 3 ? 3 : 1,
image2.data);
}
}

Well...
Don't create a new window by calling "namedWindow()".
Then call imshow(nameOfExistingWindow, image).
Maybe it will work.

Related

openCV - Using matchTemplate() from a window using hWND C++

I am running an infinite loop and every frame I'm taking a screenshot from a desired window and turning it into a Mat then searching that Mat for a template image using matchTemplate. If I read in the template image and the entire image, I can use the function successfully using the TM_SQDIFF method. However, when I run the below code, a rectangle is always drawn even if the template isn't there and is never over the template if the template is present. Any ideas?
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include "opencv2/imgproc.hpp"
#include <Windows.h>
#include <iostream>
using namespace std;
using namespace cv;
Mat getMat(HWND hWND);
int main()
{
//Window capture
LPCWSTR windowTitle = L"imgName - Paint";
HWND hWND = FindWindow(NULL, windowTitle);
while (!hWND)
{
system("cls");
cout << "Start game" << endl;
hWND = FindWindow(NULL, windowTitle);
Sleep(100);
}
enum TemplateMatchModes
{
TM_SQDIFF = 0,
TM_SQDIFF_NORMED = 1,
TM_CCORR = 2,
TM_CCORR_NORMED = 3,
TM_CCOEFF = 4,
TM_CCOEFF_NORMED = 5
};
TemplateMatchModes option = TM_SQDIFF;
Mat templateImage = imread("images/templateImg.jpg", IMREAD_COLOR);
Mat otherThing;
templateImage.convertTo(otherThing, CV_8UC4);
namedWindow("Result", WINDOW_NORMAL);
while (true)
{
double minVal;
double maxVal;
Point minLoc;
Point maxLoc;
Point matchLoc;
Mat theImage = getMat(hWND);
Mat result;
Mat background;
theImage.copyTo(background);
cvtColor(theImage, theImage, COLOR_BGR2HSV);
matchTemplate(theImage, otherThing, result, option);
normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());
minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());
if (option == TM_SQDIFF || option == TM_SQDIFF_NORMED)
{
matchLoc = minLoc;
}
else
{
matchLoc = maxLoc;
}
rectangle(background, matchLoc, Point(matchLoc.x + otherThing.cols, matchLoc.y + otherThing.rows), Scalar(0, 255, 0), 2, 8, 0);
imshow("Result", background);
waitKey(30);
}
}
Mat getMat(HWND hWND)
{
HDC deviceContext = GetDC(hWND);
HDC memoryDeviceContext = CreateCompatibleDC(deviceContext);
RECT windowRect;
GetClientRect(hWND, &windowRect);
int height = windowRect.bottom;
int width = windowRect.right;
HBITMAP bitmap = CreateCompatibleBitmap(deviceContext, width, height);
SelectObject(memoryDeviceContext, bitmap);
BitBlt(memoryDeviceContext, 0, 0, width, height, deviceContext, 0, 0, SRCCOPY);
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = width;
bi.biHeight = -height;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 1;
bi.biYPelsPerMeter = 1;
bi.biClrUsed = 1;
bi.biClrImportant = 1;
Mat mat = Mat(height, width, CV_8UC4);
GetDIBits(memoryDeviceContext, bitmap, 0, height, mat.data, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
DeleteObject(bitmap);
DeleteDC(memoryDeviceContext);
ReleaseDC(hWND, deviceContext);
return mat;
}
There is no condition given for rectangle to not to be drawn. If you want it to be drawn only if the template found you should create a condition for that.
You may check some detection examples as well.

OpenCV image zoomed in

I'm using this function to make a screenshot of a window. It works fine but at games like Minecraft it's zoomed in.
Normal
Screenshot
cv::Mat getMat(HWND hWND) {
HDC deviceContext = GetDC(hWND);
HDC memoryDeviceContext = CreateCompatibleDC(deviceContext);
RECT windowRect;
GetClientRect(hWND, &windowRect);
int height = windowRect.bottom;
int width = windowRect.right;
HBITMAP bitmap = CreateCompatibleBitmap(deviceContext, width, height);
SelectObject(memoryDeviceContext, bitmap);
//copy data into bitmap
BitBlt(memoryDeviceContext, 0, 0, width, height, deviceContext, 0, 0, SRCCOPY);
//specify format by using bitmapinfoheader!
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = width;
bi.biHeight = -height;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0; //because no compression
bi.biXPelsPerMeter = 1;
bi.biYPelsPerMeter = 2;
bi.biClrUsed = 3;
bi.biClrImportant = 4;
cv::Mat mat = cv::Mat(height, width, CV_8UC4); // 8 bit unsigned ints 4 Channels -> RGBA
//transform data and store into mat.data
GetDIBits(memoryDeviceContext, bitmap, 0, height, mat.data, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
//clean up!
DeleteObject(bitmap);
DeleteDC(memoryDeviceContext); //delete not release!
ReleaseDC(hWND, deviceContext);
return mat;
}
According to the documentation, windowRect.bottom is not the height. Or windowRect.right is not the width. https://learn.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect
So, you should do something like this:
int height = windowRect.bottom - windowRect.top;
int width = windowRect.right - windowRect.left;
EDIT1:
I have found an issue similar to yours. Maybe it could help you as well.
ClientRect mysteriously smaller than WindowRect?
Cheers.

C++ Gdi+ convert image to grayscale

Trying to convert 32,24,16,8 bit images to their grayscale presentation. I read about using BitBlt, but maybe exist some light way built-in opportunity
in GDI+?
Code:
#include <vector>
...
class gdiplus_init
{
ULONG_PTR token;
public:
gdiplus_init()
{
Gdiplus::GdiplusStartupInput tmp;
Gdiplus::GdiplusStartup(&token, &tmp, NULL);
}
~gdiplus_init()
{
Gdiplus::GdiplusShutdown(token);
}
};
bool getbits(const wchar_t *filename, Gdiplus::PixelFormat pixelformat,
std::vector<BYTE> &bitmapinfo, std::vector<BYTE> &bits, int &w, int &h)
{
gdiplus_init init;
WORD bpp = 0;
int usage = DIB_RGB_COLORS;
int palettesize = 0;
switch(pixelformat)
{
case PixelFormat8bppIndexed:
bpp = 8;
usage = DIB_PAL_COLORS;
palettesize = 256 * sizeof(RGBQUAD);
break;
case PixelFormat16bppRGB555: bpp = 16; break;
case PixelFormat16bppRGB565: bpp = 16; break;
case PixelFormat24bppRGB: bpp = 24; break;
case PixelFormat32bppRGB: bpp = 32; break;
default:return false;
}
auto src = Gdiplus::Bitmap::FromFile(filename);
if(src->GetLastStatus() != Gdiplus::Status::Ok)
return false;
auto dst = src->Clone(0, 0, src->GetWidth(), src->GetHeight(),
pixelformat);
w = src->GetWidth();
h = src->GetHeight();
HBITMAP hbitmap;
Gdiplus::Color color;
dst->GetHBITMAP(color, &hbitmap);
//allocate enough memory for bitmapinfo and initialize to zero
//it's sizeof BITMAPINFO structure + size of palette
bitmapinfo.resize(sizeof(BITMAPINFO) + palettesize, 0);
//fill the first 6 parameters
BITMAPINFO* ptr = (BITMAPINFO*)bitmapinfo.data();
ptr->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); //don't skip
ptr->bmiHeader.biWidth = w;
ptr->bmiHeader.biHeight = h;
ptr->bmiHeader.biPlanes = 1;
ptr->bmiHeader.biBitCount = bpp;
ptr->bmiHeader.biCompression = BI_RGB;
//magic formula to calculate the size:
//this is roughly w * h * bytes_per_pixel, it's written this way
//to account for "bitmap padding"
DWORD size = ((w * bpp + 31) / 32) * 4 * h;
//allocate memory for image
bits.resize(size, 0);
//finally call GetDIBits to fill bits and bitmapinfo
HDC hdc = GetDC(0);
GetDIBits(hdc, hbitmap, 0, h, &bits[0], (BITMAPINFO*)&bitmapinfo[0], usage);
ReleaseDC(0, hdc);
//cleanup
delete src;
delete dst;
return true;
}
void CMFCApplicationColorsView::OnDraw(CDC* pDC)
{
...
std::vector<BYTE> bi; //automatic storage
std::vector<BYTE> bits;
int w, h;
//24-bit test
if(getbits(L"c:\\test\\24bit.bmp", PixelFormat24bppRGB, bi, bits, w, h))
StretchDIBits(dc, 0, 0, w, h, 0, 0, w, h,
bits.data(), (BITMAPINFO*)bi.data(), DIB_RGB_COLORS, SRCCOPY);
//8-bit test
if(getbits(L"c:\\test\\8bit.bmp", PixelFormat8bppIndexed, bi, bits, w, h))
StretchDIBits(dc, 0, 220, w, h, 0, 0, w, h,
bits.data(), (BITMAPINFO*)bi.data(), DIB_PAL_COLORS, SRCCOPY);
}
You can draw the GDI+ directly with various transformation. Use Gdiplus::Graphics to draw on device context.
For grayscale conversion, RGB values all have to be the same. Gdiplus::ColorMatrix can transform the colors. Green is usually more important, it gets more weight.
void draw(CDC *pdc)
{
//this line should be in OnCreate or somewhere other than paint routine
Gdiplus::Bitmap source(L"file.jpg");
//gray scale conversion:
Gdiplus::ColorMatrix matrix =
{
.3f, .3f, .3f, 0, 0,
.6f, .6f, .6f, 0, 0,
.1f, .1f, .1f, 0, 0,
0, 0, 0, 1, 0,
0, 0, 0, 0, 1
};
Gdiplus::ImageAttributes attr;
attr.SetColorMatrix(&matrix,
Gdiplus::ColorMatrixFlagsDefault, Gdiplus::ColorAdjustTypeBitmap);
Gdiplus::Graphics gr(pdc->GetSafeHdc());
Gdiplus::REAL w = (Gdiplus::REAL)source.GetWidth();
Gdiplus::REAL h = (Gdiplus::REAL)source.GetHeight();
Gdiplus::RectF rect(0, 0, w, h);
gr.DrawImage(&source, rect, 0, 0, w, h, Gdiplus::UnitPixel, &attr);
}
Note, I used rough values for grayscale matrix. See the answer mentioned in comment for a better matrix.
To convert the file, the process is similar, except use Gdiplus::Graphics to create memory dc and save it.
int GetEncoderClsid(const WCHAR* format, CLSID* clsid)
{
int result = -1;
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes
Gdiplus::GetImageEncodersSize(&num, &size);
if(size)
{
Gdiplus::ImageCodecInfo* codec = (Gdiplus::ImageCodecInfo*)(malloc(size));
GetImageEncoders(num, size, codec);
for(UINT j = 0; j < num; ++j)
if(wcscmp(codec[j].MimeType, format) == 0)
{
*clsid = codec[j].Clsid;
result = j;
}
free(codec);
}
return result;
}
bool convert_grayscale(const wchar_t *file_in, const wchar_t *file_out)
{
CStringW extension = PathFindExtensionW(file_out);
extension.Remove(L'.');
extension.MakeLower();
if(extension == L"jpg") extension = L"jpeg";
extension = L"image/" + extension;
CLSID clsid;
if(GetEncoderClsid(extension, &clsid) == -1)
return false;
Gdiplus::Bitmap source(file_in);
if(source.GetLastStatus() != Gdiplus::Status::Ok)
return false;
Gdiplus::REAL w = (Gdiplus::REAL)source.GetWidth();
Gdiplus::REAL h = (Gdiplus::REAL)source.GetHeight();
Gdiplus::RectF rect(0, 0, w, h);
Gdiplus::Bitmap copy((INT)w, (INT)h, source.GetPixelFormat());
Gdiplus::ColorMatrix matrix =
{
.3f, .3f, .3f, 0, 0,
.6f, .6f, .6f, 0, 0,
.1f, .1f, .1f, 0, 0,
0, 0, 0, 1, 0,
0, 0, 0, 0, 1
};
Gdiplus::ImageAttributes attr;
attr.SetColorMatrix(&matrix,
Gdiplus::ColorMatrixFlagsDefault, Gdiplus::ColorAdjustTypeBitmap);
Gdiplus::Graphics gr(&copy);
gr.DrawImage(&source, rect, 0, 0, w, h, Gdiplus::UnitPixel, &attr);
auto st = copy.Save(file_out, &clsid);
return st == Gdiplus::Status::Ok;
}
...
convert_grayscale(L"source.jpg", L"destination.jpg");

C++ How to get screen shot output in memory with 16 color (4bit) bitmap

I'm trying to get an image with 16 color bitmap.
I can not find a solution on the internet post.
Simple implementation here.
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
LPBITMAPINFO ConstructBitmapInfo(int nBits, int nX, int nY);
VOID RocketBuffer(LPVOID lpData);
int _tmain(int argc, _TCHAR* argv[])
{
HWND hDesktop = NULL;
HDC hCurrenDC = NULL;
INT nX, nY;
LPBITMAPINFO lpBmpInfo;
HBITMAP hBmpScreen;
LPVOID lpBmpBuffer = NULL;
if(NULL == (hDesktop = GetDesktopWindow()))
return GetLastError();
if (NULL == (hCurrenDC = GetDC(hDesktop)))
return GetLastError();
nX = GetSystemMetrics(SM_CXSCREEN);
nY = GetSystemMetrics(SM_CYSCREEN);
HDC hOrgMemDC = NULL;
hOrgMemDC = CreateCompatibleDC(hCurrenDC);
lpBmpInfo = ConstructBitmapInfo(4, nX, nY);
hBmpScreen = CreateDIBSection(hCurrenDC, lpBmpInfo, DIB_RGB_COLORS, &lpBmpBuffer, NULL, 0);
SelectObject(hOrgMemDC, hBmpScreen);
if(!BitBlt(hOrgMemDC, 0, 0, nX, nY, hCurrenDC, 0, 0, SRCCOPY))
{
return GetLastError();
}
LPBYTE lpWriteData = new BYTE[lpBmpInfo->bmiHeader.biSizeImage * 2];
memcpy(lpWriteData, lpBmpBuffer, lpBmpInfo->bmiHeader.biSizeImage);
RocketBuffer(lpBmpBuffer);
delete[] lpWriteData;
return 0;
}
LPBITMAPINFO ConstructBitmapInfo(int nBits, int nX, int nY)
{
int color_num = nBits <= 8 ? 1 << nBits : 0;
int nBISize = sizeof(BITMAPINFOHEADER) + (color_num * sizeof(RGBQUAD));
BITMAPINFO *lpbmi = (BITMAPINFO *) new BYTE[nBISize];
BITMAPINFOHEADER *lpbmih = &(lpbmi->bmiHeader);
lpbmih->biSize = sizeof(BITMAPINFOHEADER);
lpbmih->biWidth = nX;
lpbmih->biHeight = nY;
lpbmih->biPlanes = 1;
lpbmih->biBitCount = nBits;
lpbmih->biCompression = BI_RGB;
lpbmih->biXPelsPerMeter = 0;
lpbmih->biYPelsPerMeter = 0;
lpbmih->biClrUsed = 0;
lpbmih->biClrImportant = 0;
lpbmih->biSizeImage = (((lpbmih->biWidth * lpbmih->biBitCount + 31) & ~31) >> 3) * lpbmih->biHeight;
if (nBits >= 16)
return lpbmi;
HDC hDC = GetDC(NULL);
HBITMAP hBmp = CreateCompatibleBitmap(hDC, 1, 1);
GetDIBits(hDC, hBmp, 0, 0, NULL, lpbmi, DIB_RGB_COLORS);
ReleaseDC(NULL, hDC);
DeleteObject(hBmp);
return lpbmi;
}
VOID RocketBuffer(LPVOID lpData)
{
// ...
}
I can not output lpWriteData as a * .bmp file. It's not BMP format.
Therefore, the function RocketBuffer (LPVOID lpData) will not be able to perform its function correctly.
The problem is how to get screen shot output in memory with 16 color bitmap.
32 Bit Color Image
I want 4 bit image like this.
4 Bit Color Image
16 color 4-bit image includes a color table with 16 colors. The color table size is 16 * 4 bytes. BITMAPINFO should be large enough to receive the color palette through GetDIBits
The code below works for the following bitmaps:
1-bit bitmaps (monochrome) //bpp = 1
4-bit bitmaps (16 colors) //bpp = 4
8-bit bitmaps (256 colors) //bpp = 8
.
#include <iostream>
#include <fstream>
#include <vector>
#include <windows.h>
int main()
{
//4-bit bitmap: bpp = 4
//valid values with this method bpp = 1, 4, 8
WORD bpp = 4;
//color table:
int colorsize = (1 << bpp) * sizeof(RGBQUAD);
int width = GetSystemMetrics(SM_CXFULLSCREEN);
int height = GetSystemMetrics(SM_CYFULLSCREEN);
HDC hdc = GetDC(HWND_DESKTOP);
HBITMAP hbitmap = CreateCompatibleBitmap(hdc, width, height);
HDC memdc = CreateCompatibleDC(hdc);
HGDIOBJ oldbmp = SelectObject(memdc, hbitmap);
BitBlt(memdc, 0, 0, width, height, hdc, 0, 0, CAPTUREBLT | SRCCOPY);
SelectObject(memdc, oldbmp);
//size in bytes for pixel data:
DWORD size = ((width * bpp + 31) / 32) * 4 * height;
std::vector<BYTE> bi_memory;
bi_memory.resize(sizeof(BITMAPINFOHEADER) + colorsize, 0);
BITMAPINFO* bi = (BITMAPINFO*)&bi_memory[0];
bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi->bmiHeader.biWidth = width;
bi->bmiHeader.biHeight = height;
bi->bmiHeader.biPlanes = 1;
bi->bmiHeader.biBitCount = bpp;
bi->bmiHeader.biCompression = BI_RGB;
bi->bmiHeader.biClrUsed = 16;
std::vector<BYTE> pixels(size + colorsize);
GetDIBits(hdc, hbitmap, 0, height, &pixels[0], bi, DIB_RGB_COLORS);
std::ofstream fout(TEXT("c:\\test\\_4bit.bmp"), std::ios::binary);
if(fout)
{
//bitmap file header
//(54 = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER))
BITMAPFILEHEADER filehdr = { 'MB', 54 + colorsize + size, 0, 0, 54 };
fout.write((char*)&filehdr, sizeof(BITMAPFILEHEADER));
//bitmap info header
fout.write((char*)&bi->bmiHeader, sizeof(BITMAPINFOHEADER));
//color table
fout.write((char*)bi->bmiColors, colorsize);
//pixel data
fout.write((char*)pixels.data(), pixels.size());
}
//cleanup:
DeleteObject(memdc);
DeleteObject(hbitmap);
ReleaseDC(HWND_DESKTOP, hdc);
return 0;
}

OPENCV desktop capture Part II

Continuing in previous post from here OPENCV Destop Capture and this hwnd2mat function, a method to capture desktop as source in opencv is create a bitmap from the screen image with this hwnd2mat function. done.
this function is already create a bitmap from the screen image.but it gives weird effect like a trailing inside the video, i just want a normal video source more likely like this one . i've already try to find what cause it, but i don't know anymore.
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <Windows.h>
#include <iostream>
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 / 1; //change this to whatever size you want to resize to
width = windowsize.right / 1;
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;
}
int main(int argc, char **argv)
{
HWND hwndDesktop = GetDesktopWindow();
namedWindow("output", CV_WINDOW_NORMAL);
int key = 0;
while (key != 30 )
{
Mat src = hwnd2mat(hwndDesktop);
// you can do some image processing here
imshow("output", src);
key = waitKey(30); // you can change wait time
}
ReleaseCapture();
destroyAllWindows();
return 0;
}
Using GetDesktopWindow() will make infinite-mirror-effect, instead that, using what window you want capture, and me, i'm using FindWindowEx(), and use Spy++ to find what window you want to capture, that should works. but of course it will go to the next bug :).