質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

4578閲覧

C++でOpenCVのプログラミングをしたときの関数が文法上良くわからない

watarusugimoto

総合スコア47

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2016/12/30 09:03

###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という関数についてどう考えれば良いのか教えて頂けると助かります。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

()演算子のオーバーロードですね。

C++ではoperator+operator=で、+=の挙動をユーザ(プログラマ)自身が定義することが出来ます。
operator()も同様です。

参考: C++マニアック,オペレータ(演算子)のオーバーロード,operator overload

投稿2016/12/30 09:13

carimatics

総合スコア740

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

watarusugimoto

2016/12/30 09:14

素早い回答をありがとうございます。 助かります。
watarusugimoto

2016/12/30 11:25

ありがとうございます。自分が求めていたものでした。 何となくわかりました。 あと一点、教えて欲しいのですが、このソースコードを読んだ時に、 何故オーバーロードを使っているのでしょうか? 何を意図してオーバーロードを使っているのかが良く理解できていません。 宜しければ教えて下さい。
carimatics

2016/12/30 11:46 編集

挙動に関しては参考にされているサイトで詳しく書いてあります。 設計者では無いので設計の意図に関しては分かりかねます。 推測ですが、定義しているクラス自体が変換用のクラスですので、それを強調するためかと感じました。 single responsibility principleを意識したのかもしれませんし、サンプルプログラムとあるので特別な意味は無いかもしれません。
guest

0

ベストアンサー

こんにちは。

operator()は、()演算子という意味です。
なんじゃそりゃ?って感じですね。()は関数を呼び出すと言う「演算子」なのです。
ここの解説が分かり易いと思います。

他にも、+演算子を定義するoperator+など多数あります。

投稿2016/12/30 09:10

編集2016/12/30 09:12
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

watarusugimoto

2016/12/30 09:14

素早い回答をありがとうございます。 助かります。
watarusugimoto

2016/12/30 11:25

ありがとうございます。自分が求めていたものでした。 何となくわかりました。 あと一点、教えて欲しいのですが、このソースコードを読んだ時に、 何故オーバーロードを使っているのでしょうか? 何を意図してオーバーロードを使っているのかが良く理解できていません。 宜しければ教えて下さい。
Chironian

2016/12/30 11:59 編集

私もよく分からなかったです。普通にメソッドで処理して良いし、その方が分かり易いと思います。 operator()を定義するケースは、ファンクタ(関数オブジェクト)を作る時が多いです。 https://ja.wikipedia.org/wiki/%E9%96%A2%E6%95%B0%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88 ですが、ご提示のソースは戻り値がvoidなのでファンクタ的な使い方ではないです。 個人的にはあまり()演算子で処理しない方が良いケースのように感じます。
watarusugimoto

2016/12/30 11:56

理解していないままの質問なので、余計に分かりませんでした。 この後またじっくり勉強してみたいと思います。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問