Objective-CでOpenCVを使ったテンプレートマッチングが…

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ru-ti

Objective-CでOpenCVを使ったテンプレートマッチングが…

#1

投稿記事 by ru-ti » 12年前

初めまして、ru-tiと申します。
プログラムがうまく動作せず途方にくれていたところ、こちらの掲示板を見つけまして、何かヒントでも教えていただければと思い質問させていただきました。

■カメラで撮影した画像にテンプレートマッチングを行い、最も似ているところに矩形を表示するプログラムを作ろうとしています。
ipad上で起動してみたところ、ずれた位置に矩形が表示される状態で、これをどうにかしようと悩んでいます。(矩形表示位置のy座標もずれていますが、x座標であるmax_pt.xの値が51から変動しません。)
Domachinglメソッドの引数「image」にはカメラが取得した画像(UIImage型)が入っています。戻り値は画面に表示されるものです。
探索するテンプレート画像は事前にカメラで撮った画像から切り出したものを「temp2.jpg」として使っています。
以下のサイトを参考にしました。

・パターンマッチングの処理を参考
[Moonmile Solutions Blog - OpenCVテンプレートマッチングと低解像度化で、駒を検出する]
http://www.moonmile.net/blog/archives/2492
・UIImageとCVMatの変換を参考
[Qiita - OpenCV for iOSの使い方]
http://qiita.com/shu223/items/3ff48a8bd6edd910e780

Objective-CとOpenCVも共に勉強し始めてたばかりで、書き方が汚い上に長くて申し訳ないですが、どうぞよろしくお願いします。

コード:

  
 //縮小用
cv::Mat *_org_img;
cv::Mat *_reso_img;
cv::Mat *_reso_org;
cv::Mat tmp_img2;
int _reso ;
int _reso_width ;
int _reso_height ;

int FirstCount = 0;

//縮小比率
int reso = 3 ;

UIImage * image2 = [UIImage imageNamed:@"temp2.jpg"];
cv::Mat cvMatFist_img2 = [OpenCVUtil cvMatFromUIImage:image2];

@implementation OpenCVUtil

// 低解像度を作成
cv::Mat& syukusyouDo( cv::Mat& img ){
    int width  = img.cols / reso;
    int height = img.rows / reso;
    _org_img = &img;
    _reso_img = new cv::Mat(height,width,CV_MAKETYPE(img.depth(), img.channels()));
    for (int y=0; y<height; ++y) {
        for (int x=0; x<width; x++) {
            int x1 = (reso+1) /2 + reso * x;
            int y1 = (reso+1) /2 + reso * y;
            cv::Vec3b &v = _org_img->at<cv::Vec3b>(y1,x1);
            // cout << x << "," << y << endl;
            _reso_img->at<cv::Vec3b>(y,x) = v;
        }
    }
    return *_reso_img;
}

//うまく利用できなかったのと必要ないと思ったのでコメントアウトしました
// 確認用に元の画像の大きさに戻す
/*
cv::Mat& syukusyouRe( cv::Mat& img){
    if ( _reso_org == NULL ) {
        _reso_org = new cv::Mat(
                                _org_img->rows, _org_img->cols,
                                CV_MAKETYPE(_org_img->depth(),_org_img->channels()));
    }
    for ( int y=0; y<_reso_height; ++y ) {
        for ( int x=0; x<_reso_width; ++x ) {
            cv::Vec3b &v = _reso_img->at<cv::Vec3b>(y,x);
            for ( int y1=0; y1<_reso; ++y1 ) {
                for ( int x1=0; x1<_reso; ++x1 ) {
                    _reso_org->at<cv::Vec3b>(y*_reso+y1,x*_reso+x1) = v ;
                }
            }
        }
    }
    return *_reso_org;
}

 void RowReso()
{
    _org_img = NULL;
    _reso_img = NULL;
    _reso_org = NULL;
    
    if ( _reso_img != NULL ) delete _reso_img;
    if ( _reso_org != NULL ) delete _reso_org;
};
 */


+ (UIImage *)Domaching:(UIImage *)image
{
    cv::Mat search_img = [OpenCVUtil cvMatFromUIImage:image];
   
    cv::Mat result_img;
    
    if (FirstCount == 0) {
        tmp_img2 = syukusyouDo(cvMatFist_img2);
        FirstCount ++ ;
    }
    
    cv::Mat search_img2 = syukusyouDo(search_img);

    cv::matchTemplate(search_img2, tmp_img2, result_img, CV_TM_CCOEFF_NORMED);

    cv::Point max_pt;
    double maxVal;
    cv::minMaxLoc(result_img, NULL, &maxVal, NULL, &max_pt);
    
    if(maxVal<0.5) return image; //マッチなければ終了
    
    cv::Rect roi_rect(0, 0, tmp_img2.rows, tmp_img2.cols);
    roi_rect.x = max_pt.x  ;
    roi_rect.y = max_pt.y  ;
    std::cout << "(" << max_pt.x << ", " << max_pt.y << "), score=" << maxVal << std::endl;
    
    cv::Rect roi_rect_org( roi_rect.x * reso , roi_rect.y * reso , tmp_img2.cols*reso, tmp_img2.rows*reso );

    // 探索結果の場所に矩形を描画    
    cv::rectangle(search_img, roi_rect_org, cv::Scalar(255,0,0), 3);
    
    return [OpenCVUtil UIImageFromCVMat:search_img];
}


//UIImageとCVMatをそれぞれに変換するメソッド
+ (UIImage *)UIImageFromCVMat:(cv::Mat)cvMat
{
//省略 
}
+ (cv::Mat)cvMatFromUIImage:(UIImage *)image
{
//省略
}

@end
    

ru-ti

Re: Objective-CでOpenCVを使ったテンプレートマッチングが…

#2

投稿記事 by ru-ti » 12年前

書き忘れていたので追記します。

・カメラ画像「image」のサイズ 640*480
縮小したサイズ 213*160
・テンプレート画像「temp2.jpg」のサイズ 175*279
縮小したサイズ 58*93
・result_img のサイズ 156*68

以上のように、縮小はうまくできているようなので、なぜちゃんとした位置に矩形が表示されていないか分かりません><
UIImageとCVMatを変換して処理しているのでうまくいかないのでしょうか…。

アバター
h2so5
副管理人
記事: 2212
登録日時: 15年前
住所: 東京
連絡を取る:

Re: Objective-CでOpenCVを使ったテンプレートマッチングが…

#3

投稿記事 by h2so5 » 12年前

コード:

cv::Rect roi_rect_org( roi_rect.x * reso , roi_rect.y * reso , tmp_img2.cols*reso, tmp_img2.rows*reso );
結果の矩形に縮小倍率を掛けているので、縮小前の画像の位置に矩形を表示してしまっていると思います。

ru-ti

Re: Objective-CでOpenCVを使ったテンプレートマッチングが…

#4

投稿記事 by ru-ti » 12年前

質問者のru-tiです。
閲覧・解答していただきありがとうございます!

画面に表示したいのは縮小前の解像度が大きな画像、と思っていました。
なので、矩形はカメラ画像「search_img」(縮小していない)へ描画するため、縮小倍率をかけ直しもとの大きさと位置にしていました。
なにか根本的に考え方が間違っているのでしょうか…(´・ω・)

99行目の

コード:

  std::cout << "(" << max_pt.x << ", " << max_pt.y << "), score=" << maxVal << std::endl;
この部分でmax_pt.xとmax_pt.yを確認のために表示しているのですが、この時点で既にmax_pt.xの値が変動せず一定となっており、max_pt.xが正しい値になっていないと思います…。マッチングの処理はほぼサンプルと変えていないのですがなぜなのでしょうか…?
max_pt.yの方はカメラに写っているテンプレートの位置にを合わせて動いているようです…。

アバター
usao
記事: 1892
登録日時: 13年前
連絡を取る:

Re: Objective-CでOpenCVを使ったテンプレートマッチングが…

#5

投稿記事 by usao » 12年前

まず,どの時点で問題が起きているのかを 突き止めるべきでしょう.
例えば,当然以下のような事柄を一つずつ調べるべきです.
(言われるまでもなく当然やられているのだと思うのですが,であれば,その結果の情報も提示した方が早いと思いますよ)

(1)matchTemplateの結果である result_img を可視化したら,それらしい絵になっているのか?
 →なってないなら,matchTemplate自体がバグっているか,引数がおかしいということ.
 →なっているならminMaxLoc()以降がおかしいということ.

(2)解像度をどうの という話をやらないで 素の入力画像とテンプレート画像を用いればうまく動くのか?
 →うまくいくなら,低解像度化まわりの話でバグを仕込んでしまっている.

(3)低解像度化の処理はまともな結果を生むのか?(OpenCVの関数を使わずに自前で実装しているのはなぜ?)
 →絵が狂っていれば当然うまくいかないよね.

(4)UIImageとCVMatをそれぞれに変換する ← そもそもこれってうまくいってるんだよね?

閉鎖

“C言語何でも質問掲示板” へ戻る