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

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

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

Q&A

解決済

2回答

1537閲覧

vc++2008で画面に表示されている部分に画像の絵が含まれるかをチェックしたい

koharulibrary

総合スコア6

0グッド

0クリップ

投稿2017/10/15 04:35

###前提・実現したいこと
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にこだわったりしてないのでもっと簡単な方法があればそちらの方がうれしいのが本音です。

下手な日本語ですいませんがよろしくお願いします。

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

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

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

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

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

guest

回答2

0

自己解決

解決しました。色々とドツボにはまってかなり時間がかかりましたがKoichiSugiyamaさんがおっしゃられたように画像の型みたいなもの?の違いでした。

以下2点に書き換えたところ無事思い通りの動作になりました。

bmpInfo.bmiHeader.biBitCount=24;
convertIplImg = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);

本当にありがとうございました。

投稿2017/10/18 02:50

koharulibrary

総合スコア6

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

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

0

OpenCVはほとんど触ったことがないので、あくまでエラーメッセージと提示されたコードから疑問に思った点を書いてみます。

デスクトップをキャプチャした画像を

convertIplImg = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 4);

で作成しています。これに対してテンプレート画像はもともと用意した画像を使用されていますが、デスクトップをキャプチャした画像と、テンプレートの画像でビットあたりの画素数やチャンネル数などのパラメータが違うのではないでしょうか?

Visual Studioデバッガで、それぞれの構造体の内部を表示してnChanelsやdepthといったメンバに設定されている値を比較してみてください。

投稿2017/10/15 12:03

KoichiSugiyama

総合スコア3041

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

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

koharulibrary

2017/10/16 15:49

まずデバッグ方法を知らなかったので初めてできるようになりました。ありがとうございます。 キャプチャした方の構造体は赤く表示されていて、変数が正常でない感じでした。 で、もっと手前の他の変数宣言も調べたところ赤く「unused = CXX0030: エラーです: 式を評価できません」となっていました。  ググって見るとhwndなどはwin32アプリ作成などで使う型みたいなのでそれが原因かと推察しています。 コンソール系アプリ以外は作ったことないので少しwin32アプリを学習してみましたが、かなり時間がかかりそうです。そして今組んでいるのはコンソールアプリなので、他の方法で「メモリ上にデスクトップ画像を取得⇒IplImageに変換」する方法を調べてみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問