Skip to content

Instantly share code, notes, and snippets.

@AhiyaHiya
Last active February 6, 2022 21:56
Show Gist options
  • Save AhiyaHiya/6e455a3a6c846766f1017044131bfab7 to your computer and use it in GitHub Desktop.
Save AhiyaHiya/6e455a3a6c846766f1017044131bfab7 to your computer and use it in GitHub Desktop.
Function to convert cv::Mat to Win32 HBITMAP aka BMP; function to paste HBITMAP to Windows clipboard.
#include <cassert>
#include "opencv2/opencv.hpp"
auto ConvertCVMatToBMP (cv::Mat frame) -> HBITMAP
{
auto convertOpenCVBitDepthToBits = [](const int32_t value)
{
auto regular = 0u;
switch (value)
{
case CV_8U:
case CV_8S:
regular = 8u;
break;
case CV_16U:
case CV_16S:
regular = 16u;
break;
case CV_32S:
case CV_32F:
regular = 32u;
break;
case CV_64F:
regular = 64u;
break;
default:
regular = 0u;
break;
}
return regular;
};
auto imageSize = frame.size();
assert(imageSize.width && "invalid size provided by frame");
assert(imageSize.height && "invalid size provided by frame");
if (imageSize.width && imageSize.height)
{
auto headerInfo = BITMAPINFOHEADER{};
ZeroMemory(&headerInfo, sizeof(headerInfo));
headerInfo.biSize = sizeof(headerInfo);
headerInfo.biWidth = imageSize.width;
headerInfo.biHeight = -(imageSize.height); // negative otherwise it will be upsidedown
headerInfo.biPlanes = 1;// must be set to 1 as per documentation frame.channels();
const auto bits = convertOpenCVBitDepthToBits( frame.depth() );
headerInfo.biBitCount = frame.channels() * bits;
auto bitmapInfo = BITMAPINFO{};
ZeroMemory(&bitmapInfo, sizeof(bitmapInfo));
bitmapInfo.bmiHeader = headerInfo;
bitmapInfo.bmiColors->rgbBlue = 0;
bitmapInfo.bmiColors->rgbGreen = 0;
bitmapInfo.bmiColors->rgbRed = 0;
bitmapInfo.bmiColors->rgbReserved = 0;
auto dc = GetDC(nullptr);
assert(dc != nullptr && "Failure to get DC");
auto bmp = CreateDIBitmap(dc,
&headerInfo,
CBM_INIT,
frame.data,
&bitmapInfo,
DIB_RGB_COLORS);
assert(bmp != nullptr && "Failure creating bitmap from captured frame");
return bmp;
}
else
{
return nullptr;
}
}
auto PasteBMPToClipboard(void* bmp) -> bool
{
assert(bmp != nullptr && "You need a bmp for this function to work");
if (OpenClipboard(NULL) && bmp != nullptr)
{
EmptyClipboard();
SetClipboardData(CF_BITMAP, bmp);
CloseClipboard();
return true;
}
else
{
return false;
}
}
int main(int argc, char const *argv[])
{
auto emptyFrame = cv::Mat{};
auto bmp = ConvertCVMatToBMP(emptyFrame);
if (bmp)
{
auto pasteResult = PasteBMPToClipboard(bmp);
(void)pasteResult; // examine result at your convenience
DeleteObject(bmp);
}
return 0;
}
@weituotian
Copy link

@AhiyaHiya

image

the image is Oblique,

i had no idea to modify the bitmap 's stride.

how to fix it?

@weituotian
Copy link

@AhiyaHiya

the problem can be happened that if the mat ' s cols is Not a multiple of 4

so when i resize the mat

	resize(frame, frame, Size(frame.cols / 4 * 4, frame.rows));

it correctly work!

and then i want you to Explain what is the real inner of this problem.

and finish to find a way keep the orginal size of the mat.

@weituotian
Copy link

@AhiyaHiya
when i translate gray mat into bitmap,
it become all blcak?
it happens always, you can check it!
please fix it!!!

@SolFluAndy
Copy link

I'm not keen on your coding style, but after a cosmetic cleanup, this example works just great.
The only thing I would suggest is that you release the device context using...

ReleaseDC(nullptr,dc);

The documentation is clear. Without that call you have a GDI handle leak.
Thanks for the timesaver.

@xuandong93
Copy link

auto dc = GetDC(nullptr); I get error for this. 'too many arguments in function call'
how come?
But i solved it when i use :
CDC* p = GetDC();
HDC dc = p->m_hDC;

Then i tried to display the HBITMAP using the following code but its not showing anything. Do you know why? thanks.

m_pic.GetClientRect(&rectStaticClient);
rectStaticClient.NormalizeRect();
m_size.cx = rectStaticClient.Size().cx;
m_size.cy = rectStaticClient.Size().cy;
m_size.cx = rectStaticClient.Width(); // zero based
m_size.cy = rectStaticClient.Height(); // zero based

	// Convert to screen coordinates using static as base,
	// then to DIALOG (instead of static) client coords 
	// using dialog as base
	m_pic.ClientToScreen(&rectStaticClient);
	ScreenToClient(&rectStaticClient);

	m_pt.x = rectStaticClient.left;
	m_pt.y = rectStaticClient.top;
	GetObject(m_hBmpNew, sizeof(BITMAP), &m_bmInfo);
	VERIFY(m_hBmpOld = (HBITMAP)SelectObject(m_dcMem, m_hBmpNew));
	offsetx = m_pt.x;
	offsety = m_pt.y;
	InvalidateRect(&rectStaticClient);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment