###Win32APIを用いてデスクトップキャプチャした画像をOpenCVのMat型に変換し、OpenCVで解析したい。
Win32APIを用いてデスクトップキャプチャを連続で行い、動画としてデスクトップの映像が見れるようにプログラミングを組みました。メモリデバイスコンテキストにビットマップを対応させ、画像をメモリに保存するところまではプログラミングが完成しています。
次にやりたいこととして、このメモリに保存されている画像データを、OpenCVのMat型変数の中に格納したいと考えています。
そこで、参考となるサイトとして、山本ワールドというサイトの「OpenCV Mat型とGDI BITMAPの相互変換サンプル」というコードを参考にさせて頂きました。
###理解できないコードの抜粋
C++の文法の話になるかもしれませんが、void operator()(HBITMAP hbmp)というように、()が連続して続くような関数は良いのか、または、何か決まった文法があるのかがわかりません。分からないのでひたすら調べているのですが、単にoperator()までが関数名なだけなのか、このように()を2回繰り返すのが文法上意味があるのかどうなのかがわかりません。
void operator()(HBITMAP hbmp){ BITMAP bmp; GetObject(hbmp, sizeof(bmp), &bmp); if (mat==0 || (mat && (bmp.bmHeight!=height || bmp.bmWidth!=width)) ){ delete mat; mat = new Mat(bmp.bmHeight, bmp.bmWidth, CV_8UC(bmp.bmBitsPixel / 8)); } width = bmp.bmWidth; height = bmp.bmHeight; size_t sz = bmp.bmWidth*bmp.bmHeight*(bmp.bmBitsPixel / 8); memcpy(mat->data, bmp.bmBits, sz); }
###該当のソースコード全体
C++
1// OpenCV Mat型とGDI BITMAPの相互変換サンプル 2// 3// test.jpgファイルをMat型に読み込み、GDI BITMAPに変換してウィンドウに描画 4// GDI BITMAPをMat型に変換してOpenCVでウィンドウを開いて表示 5// 6// Open CV 2.3.1/2.4.10 サポート 7// 例えばVisual C++ 2013でOpen CV 2.4.10でコンパイルする場合の設定は以下の通りとなる 8// VCのインクルードディレクトリに C:\opencv2.4.10\opencv\build\include; を付加 9// 動的リンクで作成した場合は、サンプルの実行には環境変数PATHに以下のフォルダーを登録する必要がある。 10// win64 C:\opencv2.4.10\opencv\build\x64\vc12\bin 11// win32 C:\opencv2.4.10\opencv\build\x86\vc12\bin 12// LIBファイルは本ソースのプラグマで設定しているので、CV_INST_DIR CV_INSt_DIR_SUBマクロでLIBファイルのパスを設定する必要がある。 13// 本ソースは、c:\opencvメジャー番号.マイナー番号.サブマイナー番号\opencv\build を想定 14// 動作確認 15// Visual C++ 2008 Standard Release 64bit 動的/静的 OpenCV 2.3.1 16// Visual C++ 2008 Standard Debug 64bit 動的/静的 OpenCV 2.3.1 17// Visual C++ 2008 Standard Release 32bit 動的/静的 OpenCV 2.3.1 18// Visual C++ 2008 Standard Debug 32bit 動的/静的 OpenCV 2.3.1 19// Visual C++ 2013 Express Debug 32bit 動的/静的 OpenCV 2.4.10 20// Visual C++ 2013 Express Release 32bit 動的/静的 OpenCV 2.4.10 21// Visual C++ 2013 Express Debug 64bit 動的/静的 OpenCV 2.4.10 22// Visual C++ 2013 Express Release 64bit 動的/静的 OpenCV 2.4.10 23 24#include <windows.h> 25#include <opencv2/opencv.hpp> 26#include <tchar.h> 27#include <commctrl.h> 28 29#ifdef _DLL // 動的リンク 30 #define CV_LINK_MODE "/lib/" 31#else // 静的リンク 32 #define CV_LINK_MODE "/staticlib/" 33#endif 34 35// バージョン取得 36#define CV_VERSION_STR CVAUX_STR(CV_MAJOR_VERSION) CVAUX_STR(CV_MINOR_VERSION) CVAUX_STR(CV_SUBMINOR_VERSION) 37 38#define CV_INST_SUB_DIR "opencv" ## CVAUX_STR(CV_MAJOR_VERSION) ## "." CVAUX_STR(CV_MINOR_VERSION) ## "." CVAUX_STR(CV_SUBMINOR_VERSION) 39 40#define CV_INST_DIR "c:/" ## CV_INST_SUB_DIR ## "/opencv/build" 41 42 43// 32bit/64bit ランタイムのリンクモード等に応じてLIBファイルのフォルダー名(CV_LIB_DIR)を作成 44 45#ifdef _WIN64 46 #ifdef _DLL 47 #define CV_LIB_DIR CV_INST_DIR ## "/x64/" ## CV_MS_VER ## "/lib/" 48 #else 49 #define CV_LIB_DIR CV_INST_DIR ## "/x64/" ## CV_MS_VER ## "/staticlib/" 50 #endif 51#else 52 #ifdef _DLL 53 #define CV_LIB_DIR CV_INST_DIR ## "/x86/" ## CV_MS_VER ## "/lib/" 54 #else 55 #define CV_LIB_DIR CV_INST_DIR ## "/x86/" ## CV_MS_VER ## "/staticlib/" 56 #endif 57#endif 58 59 60#if _MSC_VER==1500 61 #define VCVER 2008 62 #define CV_MS_VER "vc9" 63#endif 64 65#if _MSC_VER==1600 66 #define VCVER 2010 67 #define CV_MS_VER "vc10" 68#endif 69 70#if _MSC_VER==1700 71 #define VCVER 2012 72 #define CV_MS_VER "vc11" 73#endif 74 75#if _MSC_VER==1800 76 #define VCVER 2008 77 #define CV_MS_VER "vc12" 78#endif 79 80 81#ifdef _DEBUG // デバック 82#define CV_EXT_STR "d.lib" 83#else // リリース 84#define CV_EXT_STR ".lib" 85#endif 86// 87#pragma comment(lib, CV_LIB_DIR "opencv_core" CV_VERSION_STR CV_EXT_STR) 88#pragma comment(lib, CV_LIB_DIR "opencv_highgui" CV_VERSION_STR CV_EXT_STR) 89 90#ifdef _DLL // 動的リンク 91 92#else 93 #pragma comment(lib,"comctl32.lib") 94 95 #pragma comment(linker, "/nodefaultlib:\"msvcprt" CV_EXT_STR "\"") 96 #if CV_MAJOR_VERSION==2 && CV_MINOR_VERSION==4 && CV_SUBMINOR_VERSION==10 97 #pragma comment(lib, CV_LIB_DIR "IlmImf" CV_EXT_STR ) 98 #endif 99 #pragma comment(lib, CV_LIB_DIR "libjasper" CV_EXT_STR ) 100 #pragma comment(lib, CV_LIB_DIR "libjpeg" CV_EXT_STR ) 101 #pragma comment(lib, CV_LIB_DIR "libpng" CV_EXT_STR ) 102 #pragma comment(lib, CV_LIB_DIR "libtiff" CV_EXT_STR ) 103 #pragma comment(lib, CV_LIB_DIR "zlib" CV_EXT_STR ) 104#endif 105 106using namespace cv; 107 108// ウィンドウプロシージャー 109 110TCHAR* szClassName = _TEXT("GDI BitBlt"); 111 112 113// Mat型をメモリデバイスコンテキストに変換するクラス 114 115struct Mat2MemHDC{ 116 BITMAPINFO bmi; 117 HBITMAP hbmp; 118 BYTE *pBits; 119 HDC memHDC; 120 121 Mat2MemHDC(){ 122 pBits = 0; 123 } 124 ~Mat2MemHDC(){ 125 if (pBits){ 126 DeleteObject(hbmp); 127 DeleteDC(memHDC); 128 } 129 } 130 // Mat型の画像とメモリデバイスコンテキストに変換する 131 bool operator()(HDC hdc, Mat img){ 132 // 横幅を4の倍数に合わせる 133 int sx = img.cols; 134 if (sx % 4){ 135 sx = (sx + 4) & 0xfffffffc; 136 } 137 if (pBits == NULL || (pBits && (sx != bmi.bmiHeader.biWidth || img.rows != bmi.bmiHeader.biHeight)) ){ 138 DeleteObject(hbmp); 139 DeleteDC(memHDC); 140 bmi.bmiHeader.biSize = sizeof(bmi); 141 bmi.bmiHeader.biWidth = sx; 142 bmi.bmiHeader.biHeight = -img.rows; // 上下反転 143 bmi.bmiHeader.biBitCount = img.channels() * 8; 144 145 bmi.bmiHeader.biPlanes = 1; 146 bmi.bmiHeader.biCompression = BI_RGB; 147 bmi.bmiHeader.biSizeImage = 0; 148 bmi.bmiHeader.biXPelsPerMeter = 0; 149 bmi.bmiHeader.biYPelsPerMeter = 0; 150 bmi.bmiHeader.biClrUsed = 0; 151 bmi.bmiHeader.biClrImportant = 0; 152 153 hbmp = CreateDIBSection(NULL, &bmi, 0, (void**)&pBits, NULL, 0); 154 if (pBits == NULL){ // メモリ不足 155 return false; 156 } 157 memHDC = CreateCompatibleDC(hdc); 158 SelectObject(memHDC, hbmp); 159 } 160 161 // imgの横幅が4の倍数でない場合があるので、1ラインずつコピーする 162 for (int y = 0; y < height(); y++){ 163 memcpy(pBits + y*width()*img.channels(), img.data + y*img.cols*img.channels(), img.cols*img.channels()); 164 // 右横の余白を白にする 165 BYTE* p = pBits + (y*width()+img.cols)*img.channels(); 166 for (int x = img.cols; x < width(); x++){ 167 for (int n = 0; n < img.channels(); n++){ 168 *p++ = 0xff; 169 } 170 } 171 } 172 return true; 173 } 174 int width(void){ 175 return bmi.bmiHeader.biWidth; 176 } 177 int height(void){ 178 return -bmi.bmiHeader.biHeight; 179 } 180 void BitBlt(HDC hdc,int dx,int dy,DWORD rop){ 181 ::BitBlt(hdc, 0, 0, width(), height(), memHDC, dx, dy, rop); 182 } 183}; 184 185// ビットマップをMat型に変換するクラス 186 187struct MemHDC2Mat{ 188 Mat* mat; 189 int width, height; 190 MemHDC2Mat(){ 191 mat = 0; 192 } 193 void operator()(HBITMAP hbmp){ 194 BITMAP bmp; 195 GetObject(hbmp, sizeof(bmp), &bmp); 196 if (mat==0 || (mat && (bmp.bmHeight!=height || bmp.bmWidth!=width)) ){ 197 delete mat; 198 mat = new Mat(bmp.bmHeight, bmp.bmWidth, CV_8UC(bmp.bmBitsPixel / 8)); 199 } 200 width = bmp.bmWidth; 201 height = bmp.bmHeight; 202 size_t sz = bmp.bmWidth*bmp.bmHeight*(bmp.bmBitsPixel / 8); 203 memcpy(mat->data, bmp.bmBits, sz); 204 } 205 ~MemHDC2Mat(){ 206 if (mat) 207 delete mat; 208 } 209}; 210 211 212Mat2MemHDC mat2memHdc; 213MemHDC2Mat memHDC2Mat; 214 215Mat img; 216 217char* fileName = "test.jpg"; 218 219// ウィンドウを作成/閉じる/移動等のメッセージにより起動される関数 220LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp); 221 222 223int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPreInst, char* CmdLine, int nCmdShow){ 224 HWND hWnd; 225 MSG lpMsg; 226 WNDCLASS myProg; 227 228 if (!hPreInst) { 229 myProg.style = CS_HREDRAW | CS_VREDRAW; 230 myProg.lpfnWndProc = WndProc; 231 myProg.cbClsExtra = 0; 232 myProg.cbWndExtra = 0; 233 myProg.hInstance = hPreInst; 234 myProg.hIcon = NULL; 235 myProg.hCursor = LoadCursor(NULL, IDC_ARROW); 236 myProg.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 237 myProg.lpszMenuName = NULL; 238 myProg.lpszClassName = szClassName; 239 if (!RegisterClass(&myProg)) 240 return FALSE; 241 } 242 hWnd = CreateWindow(szClassName, 243 szClassName, 244 WS_OVERLAPPEDWINDOW, 245 CW_USEDEFAULT, 246 CW_USEDEFAULT, 247 CW_USEDEFAULT, 248 CW_USEDEFAULT, 249 NULL, 250 NULL, 251 hPreInst, 252 NULL); 253 ShowWindow(hWnd, nCmdShow); 254 UpdateWindow(hWnd); 255 while (GetMessage(&lpMsg, NULL, 0, 0)){ 256 TranslateMessage(&lpMsg); 257 DispatchMessage(&lpMsg); 258 } 259 260 return int(lpMsg.wParam); 261} 262 263// ウィンドウを作成/閉じる/移動等のメッセージにより起動される関数 264 265LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp){ 266 HDC hdc; 267 PAINTSTRUCT ps; 268 269 switch (msg) { 270 case WM_CREATE: 271 img = imread(fileName); // jpgファイルをimgにロードする 272 hdc = GetDC(hWnd); 273 mat2memHdc(hdc, img); // Mat型をメモリデバイスコンテキストに変換する 274 memHDC2Mat(mat2memHdc.hbmp); 275 276 namedWindow("OpenCV namedWindow", CV_WINDOW_AUTOSIZE); 277 imshow("OpenCV namedWindow", *memHDC2Mat.mat); 278 279 ReleaseDC(hWnd, hdc); 280 InvalidateRect(hWnd, 0, TRUE); 281 break; 282 case WM_PAINT: // ウィンドウの描画が必要な場合に呼び出される。 283 hdc = BeginPaint(hWnd, &ps); 284 mat2memHdc.BitBlt(hdc, 0, 0,SRCCOPY); // メモリデバイスコンテキストをウィンドウに表示 285 EndPaint(hWnd, &ps); 286 break; 287 case WM_DESTROY: // ウィンドウを閉じる場合に呼び出される。 288 PostQuitMessage(0); 289 break; 290 default: 291 return (DefWindowProc(hWnd, msg, wp, lp)); 292 } 293 return 0L; 294}
###試したこと
現在、C++の文法書を見直してそのような関数が定義できるのか、確認中ですが納得のいくような答えが出せていません。クラスについての知識があまりないので、その部分を見直しているのですが答えを出せていません。
このoperatorという関数についてどう考えれば良いのか教えて頂けると助かります。
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/12/30 09:14
2016/12/30 11:25
2016/12/30 11:46 編集