プログラムがうまく動作せず途方にくれていたところ、こちらの掲示板を見つけまして、何かヒントでも教えていただければと思い質問させていただきました。
■カメラで撮影した画像にテンプレートマッチングを行い、最も似ているところに矩形を表示するプログラムを作ろうとしています。
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