###前提・実現したいこと
vc++2008でデスクトップ画面に指定画像が含まれるかを調べたいです。
マッチングは何回も行うので、キャプチャしたデスクトップ画面を画像ファイルに保存するのはハードディスクの事を考えると痛みそうなので避けたいです。
環境
パソコン:windows vista32ビット
開発ソフト:vc++2008(オフラインインソールしたもの)
win32アプリではなくコンソールアプリで行いたい
試した画像処理ライブラリ:opencv1.0(上位verインストールは難しいので断念)
opencv1.0で画像ファイルのIplImageを2つ取得して含まれるか調べるテンプレートマッチングは何とかできました。
しかし、デスクトップをキャプチャする方法はわからなかったので下記URLのソースコードを完全にコピペしてそれにテンプレートマッチングする記述を加えました。
https://oshiete.goo.ne.jp/qa/7001914.html
それを実行するとエラーのウィンドウがでます。
###発生している問題・エラーメッセージ
エラーのウィンドウには下記が書かれていました。
sizes of input arguments do not match (image and template should have the same(type)
in function cvMatchTemplate,
C\User\VP\opencv\cv\src\cvtemplmatch.cpp(333)
Press "About" to terminate application.
Press "Retry" to debug (if the app is running under debugger).
Press "Ignore" to continue (this is not safe).
コピペできず手書きなのでもしかしたら綴りミスなどあるかもしれません。すいません。
###該当のソースコード
c++言語
int main(){
HWND desktop;
RECT rc;
HDC hdc;
BITMAPINFO bmpInfo;
LPDWORD lpPixel;
HDC hMemDC;
HBITMAP hBitmap;
BITMAP bmBitmap;
int width, height;
IplImage *convertIplImg, *tmp_img;
int ans;
// スクリーンの情報を得る
desktop=GetDesktopWindow();
GetWindowRect(desktop,&rc);
width=rc.right;
height=rc.bottom;
// DIBの情報を設定する
bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biWidth=width;
bmpInfo.bmiHeader.biHeight=height;
bmpInfo.bmiHeader.biPlanes=1;
bmpInfo.bmiHeader.biBitCount=32;
bmpInfo.bmiHeader.biCompression=BI_RGB;
// DIBSection作成
hdc=GetDC(desktop);
hBitmap=CreateDIBSection(hdc,&bmpInfo,DIB_RGB_COLORS,(void**)&lpPixel,NULL,0);
hMemDC=CreateCompatibleDC(hdc);
SelectObject(hMemDC,hBitmap);
// スクリーンをDIBSectionにコピー
hdc=GetDC(desktop);
BitBlt(hMemDC,0,0,width,height,hdc,0,0,SRCCOPY);
ReleaseDC(desktop,hdc);
// ビットマップ情報の取得
GetObject(hBitmap, sizeof(BITMAP), &bmBitmap);
// Bitmap構造体からIplImageへコピー
convertIplImg = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 4);
memcpy(convertIplImg->imageData, bmBitmap.bmBits, widthheight4);
cvFlip(convertIplImg, convertIplImg, 0);
//===============================================
//書き加えた範囲
//===============================================
//画像ファイルからテンプレート画像(小さい方の画像)のIplImageを取得
tmp_img = cvLoadImage ("match/dvd.jpg", CV_LOAD_IMAGE_COLOR);
//IplImage型を2つ渡してマッチすれば1を返す自作関数(下の方に記述してます)
ans = img_match_iplimage(convertIplImg, tmp_img);
cout << "マッチ=1,マッチなし=0, 画像なし=-1" << endl;
cout << ans << endl;
//===============================================
//書き加えた範囲 終わり
//===============================================
// OpenCVウィンドウの作成&画像の表示
//cvNamedWindow("Desptop Image", CV_WINDOW_AUTOSIZE);
//cvShowImage("Desptop Image", convertIplImg);
// 何かキー入力を待つ
//cvWaitKey(0);
// 終了処理
//cvDestroyWindow("Desptop Image");
//cvReleaseImage(&convertIplImg);
DeleteDC(hMemDC);
DeleteObject(hBitmap);
PostQuitMessage(0);
return 0;
}
//========================================
//以下自作関数
int img_match_iplimage(
IplImage *src_img, //対象の画像(大きいほう)
IplImage *tmp_img //テンプレート画像、(小さい方)
){
int i, j, sum=0, ans;
double min_val, max_val;
CvPoint min_loc, max_loc;
CvSize dst_size;
IplImage *dst_img;
//マッチングの方法を指定する定数らしい
//それを配列にまとめた(全パターンで比較するため)
int method[] ={
CV_TM_SQDIFF_NORMED,
CV_TM_CCORR_NORMED,
CV_TM_CCOEFF_NORMED //サンプルのデフォはこれ
};
vector<vector<int>> xy;
xy.resize( arysize(method) ); //arysize()は配列の要素数を返す
//画像がなければ-1を返す
if (src_img==0 || tmp_img==0) return -1;
//マッチ座標(左上)を-1,-1にする
max_loc.x = -1;
max_loc.y = -1;
// (1)探索画像全体に対して,テンプレートのマッチング値(指定した手法に依存)を計算
dst_size = cvSize (src_img->width - tmp_img->width + 1, src_img->height - tmp_img->height + 1);
dst_img = cvCreateImage (dst_size, IPL_DEPTH_32F, 1);
for(i=0; i<arysize(method); i++){
//=====このcvMatchTemplate関数でエラーになる=====
cvMatchTemplate (src_img, tmp_img, dst_img, method[i]);
cvMinMaxLoc (dst_img, &min_val, &max_val, &min_loc, &max_loc, NULL);
//max_locのxかyがマイナスのままなら-2で返す
if(max_loc.x<0 || max_loc.y<0) return -2;
xy[i].push_back(max_loc.x);
xy[i].push_back(max_loc.y);
}
//画像インスタンスを破棄
cvReleaseImage (&dst_img);
//マッチング方法全パターンでの座標を比較する
for(i=0; i<(int)xy.size()-1; i++){
for(j=i+1; j<(int)xy.size(); j++){
if(xy[i][0]==xy[j][0] && xy[i][1]==xy[j][1]) sum++;
}
}
//同一の座標があれば1,なければ0を返す
ans =(sum >= 1)? 1 : 0;
return ans;
}
###試したこと
コピペのデスクトップ画面をウィンドウに出力するのを試した時は正常に表示されたのでデスクトップ画面をメモリにキャプチャするのはできていると思います。
自作関数は以下のソースで試してうまく動作しました。
int main(){
IplImage *desktop, *tmp_img;
int ans;
desktop = cvLoadImage ("match/desktop.jpg", CV_LOAD_IMAGE_COLOR);
tmp_img = cvLoadImage ("match/dvd.jpg", CV_LOAD_IMAGE_COLOR);
//IplImage型を2つ渡してマッチすれば1を返す自作関数(下記を見てください)
ans = img_match_iplimage(desktop, tmp_img);
cout << "マッチ=1,マッチなし=0, 画像なし=-1" << endl;
cout << ans << endl;
}
###補足情報(言語/FW/ツール等のバージョンなど)
エラー文を訳してみると
「入力引数のサイズが一致しません(画像とテンプレートは同じ(型)を持つ必要があります)
関数cvMatchTemplateで、」
となっていたのでキャプチャしたIplImageと画像ファイルからのIplImageでなんらかの画像の型?みたいなものが違うのかなと予想してみてコピペ先のソースコードの関数などを調べてみたのですがとても難しく画像の扱いだけでも今の自分が理解するのは無理でした。どうかご助言をお借りしたいです。
目的はデスクトップ画面(保存しない)と指定した画像(保存されたもの)との比較なので、私の環境でもできる全く別の方法があればそちらでもOKです。
opencvにこだわったりしてないのでもっと簡単な方法があればそちらの方がうれしいのが本音です。
下手な日本語ですいませんがよろしくお願いします。
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。