如何将ATL::CImage转换成cv::Mat?
How to convert ATL::CImage to cv::Mat?
我想从 ATL::CImage
转换为 cv::Mat
以便在 opencv(C++) 中进行图像处理。
你能帮忙转换这个对象吗?
我从 windows 屏幕截图(使用 MFC)中得到了 CImage
。
然后,我想在 OpenCV Mat 对象中处理图像。
我不知道如何转换。
- C++ 项目(VC 2017)
- MFC
- OpenCV 3.4.6
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???
无法将 ATL::Image
转换为 cv::Mat
。
如果高度为正,CImage
创建一个 bottom-top 位图。您必须传递负高度才能为 mat
创建 top-bottom 位图
使用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)
发生冲突
#include <opencv2\opencv.hpp>
#include <opencv2/imgproc/types_c.h>
#include <atlimage.h>
using namespace cv;
Mat CImage2Mat(CImage cimg)
{
BITMAP bmp;
::GetObject(cimg.Detach(), sizeof(BITMAP), &bmp);
int nChannels = bmp.bmBitsPixel == 1 ? 1 : bmp.bmBitsPixel / 8;
int depth = bmp.bmBitsPixel == 1 ? IPL_DEPTH_1U : IPL_DEPTH_8U;
IplImage* img = cvCreateImageHeader(cvSize(bmp.bmWidth, bmp.bmHeight), depth, nChannels);
img->imageData = (char*)malloc(bmp.bmHeight * bmp.bmWidth * nChannels * sizeof(char));
memcpy(img->imageData, (char*)(bmp.bmBits), bmp.bmHeight * bmp.bmWidth * nChannels);
cvFlip(img, img, 0);
return cvarrToMat(static_cast<IplImage*>(img));
}
用法:
CImage cimg;
cimg.Load(L"resim.png");
Mat img = CImage2Mat(cimg);
我想从 ATL::CImage
转换为 cv::Mat
以便在 opencv(C++) 中进行图像处理。
你能帮忙转换这个对象吗?
我从 windows 屏幕截图(使用 MFC)中得到了 CImage
。
然后,我想在 OpenCV Mat 对象中处理图像。
我不知道如何转换。
- C++ 项目(VC 2017)
- MFC
- OpenCV 3.4.6
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???
无法将 ATL::Image
转换为 cv::Mat
。
CImage
创建一个 bottom-top 位图。您必须传递负高度才能为 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)
#include <opencv2\opencv.hpp>
#include <opencv2/imgproc/types_c.h>
#include <atlimage.h>
using namespace cv;
Mat CImage2Mat(CImage cimg)
{
BITMAP bmp;
::GetObject(cimg.Detach(), sizeof(BITMAP), &bmp);
int nChannels = bmp.bmBitsPixel == 1 ? 1 : bmp.bmBitsPixel / 8;
int depth = bmp.bmBitsPixel == 1 ? IPL_DEPTH_1U : IPL_DEPTH_8U;
IplImage* img = cvCreateImageHeader(cvSize(bmp.bmWidth, bmp.bmHeight), depth, nChannels);
img->imageData = (char*)malloc(bmp.bmHeight * bmp.bmWidth * nChannels * sizeof(char));
memcpy(img->imageData, (char*)(bmp.bmBits), bmp.bmHeight * bmp.bmWidth * nChannels);
cvFlip(img, img, 0);
return cvarrToMat(static_cast<IplImage*>(img));
}
用法:
CImage cimg;
cimg.Load(L"resim.png");
Mat img = CImage2Mat(cimg);