Я пишу демонстрационную программу для загрузки изображения из файла в формат OpenCV cv::Mat, затем конвертирую в растровое изображение и отображаю в окнах Win32. Это полный исходный код:
// Win32
#include <Windows.h>
// OpenCV
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#pragma comment(lib, "opencv_core310d.lib")
#pragma comment(lib, "opencv_imgcodecs310d.lib")
// Marco
#define WIN_CLASS_NAME TEXT("DisplayTest")
#define WIN_NAME TEXT("Display Test")
#define IMAGE_SRC "./image.jpg"
// Global object
cv::Mat imgMat;
HWND hwndWindow;
// Convert cv::Mat data to bitmap
HBITMAP ConvertCVMatToBMP(cv::Mat frame)
{
auto convertOpenCVBitDepthToBits = [](const INT32 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();
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");
DeleteDC(dc);
return bmp;
}
return nullptr;
}
// Attach image to windows
void attachImage()
{
HBITMAP bitImage = (HBITMAP)ConvertCVMatToBMP(imgMat);
// Display image
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwndWindow, &ps);
HDC imageDC = CreateCompatibleDC(hdc);
BITMAP bm;
HBITMAP imageBmpOld = (HBITMAP)SelectObject(imageDC, (HGDIOBJ)bitImage);
GetObject(bitImage, sizeof(bm), &bm);
BitBlt(
hdc, // tell it we want to draw to the screen
0, 0, // as position 0,0 (upper-left corner)
(int)bm.bmWidth, // width of the rect to draw
(int)bm.bmHeight, // height of the rect
imageDC, // the DC to get the rect from (our image DC)
0, 0, // take it from position 0,0 in the image DC
SRCCOPY // tell it to do a pixel-by-pixel copy
);
SelectObject(imageDC, (HGDIOBJ)imageBmpOld);
DeleteDC(imageDC);
DeleteObject((HGDIOBJ)imageBmpOld);
EndPaint(hwndWindow, &ps);
}
// WndProc callback
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
switch (message) {
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_PAINT:
attachImage();
break;
default:
return (DefWindowProc(hwnd, message, wparam, lparam));
}
}
// Register class
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASS wc = { 0 };
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.hCursor = LoadCursor(hInstance, IDC_ARROW);
wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = WIN_CLASS_NAME;
wc.style = CS_HREDRAW | CS_VREDRAW;
return RegisterClass(&wc);
}
int main(int argc, char* argv[])
{
// Register class
char t[500];
GetConsoleTitleA(t, 500);
HWND hwndConsole = FindWindowA(NULL, t);
HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwndConsole, GWL_HINSTANCE);
MyRegisterClass(hInstance);
// Init data
imgMat = cv::imread(IMAGE_SRC);
// Create Win32 windows
hwndWindow = CreateWindow(WIN_CLASS_NAME, WIN_NAME, WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
NULL, NULL, hInstance, NULL);
ShowWindow(hwndWindow, SW_SHOWNORMAL);
UpdateWindow(hwndWindow);
MSG msg;
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(109));
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0)) {
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
Этот код отлично работал у меня (Windows 10):
Но если он работает в Windows 7, после быстрого перетаскивания окон так, чтобы они исчезли с экрана:
И это результат после перемещения окна обратно на экран:
В этом случае assert(bmp != nullptr)
упадет и программа внезапно завершится.
Этого не происходит в Windows 10!
Почему CreateDIBitmap
возвращает null в этом случае???