I want to convert from ATL::CImage
to cv::Mat
for image handling in opencv(C++).
Could you please help to convert this object?
I got CImage
from windows screen shot(Using MFC).
Then, I want to handle image in OpenCV Mat object.
I did not know how to convert.
CImage image;
int cx;
int cy;
CWnd* pWndDesktop = CWnd::GetDesktopWindow();
CWindowDC srcDC(pWndDesktop);
Rect rcDesktopWindow;
::GetWindowRect(pWndDesktop->m_hWnd, %rcDesktopWindow);
cx = (rcDesktopWindow.right - rcDesktopWindow.left);
cy = (rcDesktopWindow.bottom - rcDesktopWindow.top);
image.create(cx, cy, srcDC.GetDeviceCaps(BITPIXEL));
CDC* pDC = CDC::FromHandle(image.GetDC());
pDC->BitBlt(0, 0, cx, cy, &srcDC, 0, 0, SRCCOPY);
image.ReleaseDC();
cv::Mat mat;
// I want set image to mat!
mat = image???
Can not convert ATL::Image
to cv::Mat
.
CImage
creates a bottom-top bitmap if height is positive. You have to pass a negative height to create top-bottom bitmap for mat
Use CImage::GetBits
to retrieve the bits as follows:
HDC hdc = GetDC(0);
RECT rc;
GetClientRect(GetDesktopWindow(), &rc);
int cx = rc.right;
int cy = rc.bottom;
CImage image;
image.Create(cx, -cy, 32);
BitBlt(image.GetDC(), 0, 0, cx, cy, hdc, 0, 0, SRCCOPY);
image.ReleaseDC();
ReleaseDC(0, hdc);
cv::Mat mat;
mat.create(cy, cx, CV_8UC4);
memcpy(mat.data, image.GetBits(), cy * cx * 4);
//or borrow pixel data from CImage
cv::Mat mat(cy, cx, CV_8UC4, image.GetBits());
Or force a deep copy as follows:
cv::Mat mat;
mat = cv::Mat(cy, cx, CV_8UC4, image.GetBits()).clone();
Note, CImage
makes its own allocation for pixel data. And Mat
needs to make its own allocation, or it has to borrow from CImage
which can be tricky.
If you are just taking a screen shot, you can do that with plain Windows API, then write directly to cv::Mat
. This way there is a single allocation (a bit faster) and mat
does not rely on other objects. Example:
void foo()
{
HDC hdc = ::GetDC(0);
RECT rc;
::GetClientRect(::GetDesktopWindow(), &rc);
int cx = rc.right;
int cy = rc.bottom;
cv::Mat mat;
mat.create(cy, cx, CV_8UC4);
HBITMAP hbitmap = CreateCompatibleBitmap(hdc, cx, cy);
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP oldbmp = (HBITMAP)SelectObject(memdc, hbitmap);
BitBlt(memdc, 0, 0, cx, cy, hdc, 0, 0, SRCCOPY);
BITMAPINFOHEADER bi = { sizeof(bi), cx, -cy, 1, 32, BI_RGB };
GetDIBits(hdc, hbitmap, 0, cy, mat.data, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
//GDI cleanup:
SelectObject(memdc, oldbmp);
DeleteDC(memdc);
DeleteObject(hbitmap);
::ReleaseDC(0, hdc);
}
mat.data = (unsigned char*)image.GetBits();
to memcpy(mat.data, image.GetBits(), cy * cx * 4);
Changed ReleaseDC(0, hdc)
to ::ReleaseDC(0, hdc)
to avoid conflict with CWnd::ReleaseDC(dc)