Last active
February 6, 2022 21:56
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
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
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.