Convert Mat to Bitmap for Windows applications with GDI+ and surface crack detection - OpenCV Mat에서 비트맵으로 변환과 표면 크랙 검출
OpenCV 2019. 10. 26. 10:06 |GDI+ Bitmap class inherits from the Image class. The Image class provides methods for loading and saving vector images (metafiles) and raster images (bitmaps). You can build Windows applications with GDI+ and OpenCV.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#include <windows.h>
#include <gdiplus.h>
#include <opencv2/opencv.hpp>
#pragma comment(lib, "gdiplus")
using namespace cv;
using namespace Gdiplus;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCSTR lpszClass = "MatToBitmap";
Mat src; // source image
Mat org; // original image
Mat dst; // processed image
|
Prepare necessities.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
HWND hWnd;
MSG Message;
WNDCLASS WndClass;
g_hInst = hInstance;
ULONG_PTR gpToken;
GdiplusStartupInput gpsi;
if (GdiplusStartup(&gpToken, &gpsi, NULL) != Ok) {
MessageBox(NULL, TEXT("GDI+ start-up error."), TEXT("GDI+ Error"), MB_OK);
return 0;
}
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); //(HBRUSH)GetStockObject(WHITE_BRUSH);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hInstance = hInstance;
WndClass.lpfnWndProc = (WNDPROC)WndProc;
WndClass.lpszClassName = lpszClass;
WndClass.lpszMenuName = NULL;
WndClass.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&WndClass);
hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT,
670, 340, NULL, (HMENU)NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
while (GetMessage(&Message, 0, 0, 0)) {
TranslateMessage(&Message);
DispatchMessage(&Message);
}
GdiplusShutdown(gpToken);
return (int)Message.wParam;
}
|
Start GDI+ and change the background color to the radio button color and Window size.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
bool getFile(PTCHAR filename)
{
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = NULL;
ofn.lpstrFilter = TEXT("all(*.*)\0*.*\0jpg(*.jpg)\0*.jpg\0png(*.png)\0*.png\0bmp(*.bmp)\0*.bmp\0");
ofn.lpstrFile = filename;
ofn.nMaxFile = MAX_PATH;
if (GetOpenFileName(&ofn) != 0) {
//MessageBox(NULL, filename, TEXT("File opened."), MB_OK);
return true;
}
else {
MessageBox(NULL, TEXT("File open failed"), TEXT("No file selected"), MB_OK);
return false;
}
}
|
Retrieve an image file name.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
bool ImageLoad()
{
TCHAR filename[MAX_PATH] = "";
if (getFile(filename)) {
src = imread(filename);
if (src.empty()) {
MessageBox(NULL, TEXT("Image load failed"), TEXT("No image loaded"), MB_OK);
return false;
}
return true;
}
else {
return false;
}
}
|
Read the image from the file.
1
2
3
4
5
6
7
8
|
void ImageResize()
{
// maximum image display size: 320 X 240 with original ratio
double ratio = min((double)320 / (double)src.size().width, (double)240 / (double)src.size().height);
resize(src, src, cv::Size(), ratio, ratio);
org = src.clone();
cvtColor(org, org, COLOR_BGR2BGRA);
}
|
Resize an image.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
void ImageProcess(int direction)
{
cvtColor(src, dst, COLOR_BGR2GRAY);
float vertical[] = {
-2, 0, 2,
-2, 0, 2,
-2, 0, 2
};
float horizontal[] = {
-2, -2, -2,
0, 0, 0,
2, 2, 2
};
float diagonal[] = {
-2, -2, 0,
-2, 0, 2,
0, 2, 2
};
Mat emboss;
switch (direction)
{
case 0:
emboss = Mat(3, 3, CV_32FC1, vertical);
break;
case 1:
emboss = Mat(3, 3, CV_32FC1, horizontal);
break;
case 2:
emboss = Mat(3, 3, CV_32FC1, diagonal);
break;
default:
emboss = Mat(3, 3, CV_32FC1, vertical);
}
filter2D(dst, dst, -1, emboss, cv::Point(-1, -1), 128);
cvtColor(dst, dst, COLOR_GRAY2BGRA);
}
|
Process an image with embossing filter.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
void OnPaint(HDC hdc)
{
if (!dst.empty()) {
Graphics G(hdc);
Bitmap bitmapDst(dst.size().width, dst.size().height, dst.step, PixelFormat32bppARGB, dst.data);
Bitmap bitmapOrg(org.size().width, org.size().height, org.step, PixelFormat32bppARGB, org.data);
// stride(src.step): Integer that specifies the byte offset between the beginning of one scan line and
// the next. This is usually(but not necessarily) the number of bytes in the pixel format(for example,
// 2 for 16 bits per pixel) multiplied by the width of the bitmap. The value passed to this parameter
// must be a multiple of four.
G.DrawImage(&bitmapDst, 0, 0, bitmapDst.GetWidth(), bitmapDst.GetHeight());
G.DrawImage(&bitmapOrg, bitmapOrg.GetWidth() + 10, 0, bitmapOrg.GetWidth(), bitmapOrg.GetHeight());
}
else {
TextOut(hdc, 270, 110, TEXT("No image to display"), 19);
}
}
|
Draw original and processed images.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
enum { ID_R1 = 101, ID_R2, ID_R3 };
HWND r1, r2, r3;
int x = 10;
int y = 270;
int w = 90;
int h = 20;
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
switch (iMessage) {
case WM_CREATE:
if (ImageLoad()) {
ImageResize();
ImageProcess(0);
}
CreateWindow(TEXT("button"), TEXT("Filter type"), WS_CHILD | WS_VISIBLE |
BS_GROUPBOX, 5, 250, 290, 50, hWnd, (HMENU)0, g_hInst, NULL);
r1 = CreateWindow(TEXT("button"), TEXT("Vertical"), WS_CHILD | WS_VISIBLE |
BS_AUTORADIOBUTTON | WS_GROUP, x, y, w, h, hWnd, (HMENU)ID_R1, g_hInst, NULL);
r2 = CreateWindow(TEXT("button"), TEXT("Horizontal"), WS_CHILD | WS_VISIBLE |
BS_AUTORADIOBUTTON, x + 90, y, w, h, hWnd, (HMENU)ID_R2, g_hInst, NULL);
r3 = CreateWindow(TEXT("button"), TEXT("Diagonal"), WS_CHILD | WS_VISIBLE |
BS_AUTORADIOBUTTON, x + 180, y, w, h, hWnd, (HMENU)ID_R3, g_hInst, NULL);
CheckRadioButton(hWnd, ID_R1, ID_R3, ID_R1);
return 0;
case WM_COMMAND:
if (!dst.empty()) {
switch (LOWORD(wParam)) {
case ID_R1:
ImageProcess(0);
break;
case ID_R2:
ImageProcess(1);
break;
case ID_R3:
ImageProcess(2);
break;
}
InvalidateRect(hWnd, NULL, TRUE);
}
return 0;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
OnPaint(hdc);
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
|
Define the necessary variables and handle window messages.
Run the application and select an image file.
Processed and original image with a vertical filter.
Processed and original image with a horizontal filter.
Processed and original image with a diagonal filter.