CImage
создает растровое изображение снизу вверх, если высота положительна.Вы должны передать отрицательную высоту, чтобы создать верхний-нижний битовый массив для mat
. Используйте CImage::GetBits
для получения битов следующим образом:
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());
Или принудительно выполните глубокое копирование следующим образом:
cv::Mat mat;
mat = cv::Mat(cy, cx, CV_8UC4, image.GetBits()).clone();
Обратите внимание: CImage
делает свое собственное распределение для данных пикселей.И Mat
нужно сделать собственное выделение, или он должен позаимствовать у CImage
, что может быть сложно.
Если вы просто делаете снимок экрана, вы можете сделать это с помощью простого Windows API, тогдапишите прямо на cv::Mat
.Таким образом, происходит одно выделение (немного быстрее), и mat
не зависит от других объектов.Пример:
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();
на
memcpy(mat.data, image.GetBits(), cy * cx * 4);
Изменено ReleaseDC(0, hdc)
на ::ReleaseDC(0, hdc)
, чтобы избежать конфликта с CWnd::ReleaseDC(dc)