将HBITMAP转换为cv::Mat
Convert HBITMAP to cv::Mat
我似乎无法弄清楚如何做到这一点,我在谷歌上搜索并找到了两个代码示例,一个来自github屏幕捕获库,另一个来自张贴组,它们似乎都没有工作。
我有一个结构体:struct ClacksScreen
{
HWND hDesktopWnd;
int width, height;
RECT wr, cr;
HDC hdcClacksScreen; // hardware ClacksScreen
HDC hdcMemDC; // ClacksScreen in memory
HBITMAP hbmClacksScreen; //hbitmap of the ClacksScreen
BITMAP bmpClacksScreen;
BITMAPINFOHEADER bi;
};
已更新。我定义了一些函数,包括一个将位图写入磁盘的函数,这很好,屏幕被捕获,bmp被写入磁盘,这就是我想要的。
现在我想将屏幕上的HBITMAP直接转换为OpenCV2.1的cv::Mat。
它的工作,除了图像是纯灰色的,它崩溃。很明显,我对c++还是个新手,所以可能有一些简单的东西是我没有注意到的。
static cv::Mat copyToCVMat(const ClacksScreen * s)
{
cv::Mat image;
image.create(s->bmpClacksScreen.bmWidth, s->bmpClacksScreen.bmHeight, CV_8UC4);
GetDIBits(s->hdcMemDC, s->hbmClacksScreen, 0,
(UINT)s->bmpClacksScreen.bmHeight,
image.data,
(BITMAPINFO *)&s->bi, DIB_RGB_COLORS);
return image;
}
当我换行cv::imwrite(image);在try catch中,我得到了一个严重的分配错误。显然,在这一点上,我们已经确定,我没有任何线索如何做到这一点,所以任何帮助将不胜感激。
如果我运行以下代码:
try {
cv::Mat screen = cv::imread("captureqwsx.jpg");
if (!screen.data) {
printf("no image data?");
}
cv::imwrite("out.jpg",screen);
} catch(std::exception e) {
printf("Exception %sn",e.what());
}
我得到了输出:
没有图像数据?异常分配错误
当我尝试运行高图形界面时,它和以前一样,写入磁盘的。jpg和。bmp都出现了问题,这些都可以在图像查看器和MS Paint中查看。
我尝试了一个完全不同的图像,一个来自网站的。png,同样的问题。
那么我在这一点上做错了什么?
来自OpenCV文档
data -指向用户数据的指针。获取数据的矩阵构造函数步进参数不分配矩阵数据。相反,他们只是初始化指向指定数据的矩阵头,即不复制数据。这种操作效率很高,可以用来使用OpenCV函数处理外部数据。外部数据则不是自动回收,请用户自行处理
我认为这就是重点,使用这个构造函数不会复制你传递给构造函数的缓冲区,所以你不应该释放这个数据,直到你不再需要cv::Mat。另外,我对这个东西几乎一无所知,但是为什么你要传递BITMAPINFOHEADER和BITMAPFILEHEADER到你的cv::Mat对象,这似乎根本不对。
我写了自己的函数来做类似的事情,希望它能帮助你:如何在OpenCV中捕获桌面(即。将位图转换为Mat)?
我不知道它是什么,但我一问问题,我就着迷于寻找答案。无论如何,这个问题的部分答案实际上是通过这个问题的答案解决的:
OpenCV 2.0 c++ API使用imshow:返回未处理的异常和"bad-flag"
在Visual c++中:
转到Project->Properties(或Alt-F7) Configuration属性->链接器->输入->附加依赖项
替换通常的"cv210"。自由cxcore210。自由highgui210。Lib " by "cv210d。自由cxcore210d。自由highgui210d。Lib"-这是调试库。
highgui仍然显示灰色并且不起作用,但是使用上述方法从HBITMAP读取现在可以工作了。我并不真的需要highgui,它只是用于测试。
此代码甚至比相同的OpenCV库更可靠。在OpenCV中有一个特定的函数来加载HBITMAPS,但它有一些问题,例如向后加载图像,我更喜欢控制我的代码。
cv::Mat LoadHBITMAPOpenCV(HBITMAP& HBitmap, Gdiplus::Rect rect = Gdiplus::Rect())
{
// Create a Bitmap object from the HBITMAP, avoid memory leaks
std::unique_ptr<Bitmap> bitmap(Bitmap::FromHBITMAP(HBitmap, NULL));
if (!bitmap)
{
// Error loading the HBITMAP
throw std::runtime_error("[LoadHBITMAPOpenCV] Error loading HBITMAP");
}
// Get the bitmap dimensions
int bitmapWidth = bitmap->GetWidth();
int bitmapHeight = bitmap->GetHeight();
// Check if the bitmap is valid
if (bitmapWidth <= 0 || bitmapHeight <= 0)
{
throw std::runtime_error("[LoadHBITMAPOpenCV] Corrupt HBITMAP");
}
int rectWidth = bitmapWidth;
int rectHeight = bitmapHeight;
// Check if a rect is provided, otherwise use the entire image as the rect
if (rect.IsEmptyArea())
{
rect = Gdiplus::Rect(0, 0, bitmapWidth, bitmapHeight);
}
else
{
// Check if the cropping rectangle is valid
rectWidth = rect.Width - rect.X;
rectHeight = rect.Height - rect.Y;
if (rectWidth <= 0 || rectHeight <= 0 || rect.X < 0 || rect.Y < 0 || rect.Width > bitmapWidth || rect.Height > bitmapHeight)
{
throw std::runtime_error("[LoadHBITMAPOpenCV] Invalid rect");
}
}
// Load the HBITMAP into cv::Mat using GDI+
cv::Mat mat(rectHeight, rectWidth, CV_8UC4);
BitmapData bitmapData;
Rect rect_cut(rect.X, rect.Y, rectWidth, rectHeight);
bitmap->LockBits(&rect_cut, ImageLockModeRead, PixelFormat32bppARGB, &bitmapData);
if (bitmapData.Stride < 0)
{
bitmap->UnlockBits(&bitmapData);
throw std::runtime_error("[LoadHBITMAPOpenCV] Corrupt HBITMAP stride");
}
BYTE* data = reinterpret_cast<BYTE*>(bitmapData.Scan0);
memcpy(mat.data, data, mat.total() * mat.elemSize());
bitmap->UnlockBits(&bitmapData);
cv::cvtColor(mat, mat, EXTERNAL_CTV_COLOR);
// cv::cvtColor(mat, mat, cv::COLOR_RGB2Lab);
return mat;
}
- 将CHW格式的浮点向量转换为cv::Mat
- C++:从GPU内存(cudaMemcpy2D)获取BGR图像(cv::Mat)
- 选择基于另一个垫子的非零像素的cv::Mat的一部分?
- 将 cv::mat 转换为 QImage
- 将 cv::Mat 转换为 std::vector 的通用函数
- 在 QML VideoOutput 中将 cv::mat 显示为 QVideoFrame
- 如何将 cv::Mat & Img 复制到未签名的 char* img?opencv
- 如何将 cv::Mat 转换为 vtkImageData?
- 如何将 vtkImageData 转换为 cv::Mat?
- 如何总结所有cv::Mat元素
- Qt-工作线程崩溃时将cv::Mat转换为QImage
- 在 cv::Mat 中生成 2D 坐标网格
- 将 cv::Mat 转换为无符号的 int 像素
- OpenCV 分段错误(核心转储)在使用 cv::Mat::at 时
- 如何将多个 cv::Mat 从 c++ dll 传递到 opencvsharp Mat c#?
- OpenCV(3.4.1) 错误:断言失败(变暗 <= 2 && step[0] > 0) in cv::Mat::locateROI
- 如何在不复制数据的情况下将 cv::Mat 转换为 2d 标准::矢量
- 如何使用 (*mpORBextractorLeft)(im,cv::Mat(),mvKeys,mDescriptors)
- 从数组创建 Mat 时,'cv::Mat' 和 'int' 类型不兼容
- 如何将 cv::mat 对象从 python 模块传递到 c++ 函数并返回返回的 cv::mat 类型为对象?