iOSからOpenCVを使った話
初めての画像処理とOpenCV, 一年ぶりくらいのObjective-Cである。
xcodeのprojectの設定メニューのUIが変わっていたことに戸惑ったことから始まったのは内緒
まずはOpenCVを入れるて、xcodeから読み込めるようにするところから始めるわけだが、これは簡単
gemでcocoapodsを入れる
$ sudo gem install cocoapods
次にxcodeでプロジェクトを作成する
作成したプロジェクトトップのディレクトリなかにPodfileというファイルを作成し、下記を記述
pod 'OpenCV'
インストールコマンドを実行
$ pod install
あとは待つだけ。
次に、プロジェクトをxcodeで開く
$ open <project名>.xcworkspace #xcodeprojではないので注意
あとは読み込む。
ただし、C++を使う時はファイルの拡張しを".m"から".mm"に変えておく必要がある。
#import <opencv2/opencv.hpp>
UIImage <-> cv::Matの変換用のメソッドが用意されているので、
処理対象の画像をUIImageで読み込んで、cv::Matに変換してしまえば、
C++と全く同じようにOpenCVが扱える。
最後に出力する画像をcv::MatからUIImageに変換して出力すればよい。
それぞれの変換メソッドのシグニチャは
// UIImageからcv::Matに変換 void UIImageToMat(const UIImage* image, cv::Mat& m, bool alphaExist = false) // cv::MatからUIImageに変換 UIImage* MatToUIImage(const cv::Mat& image)
んでポッキーをどう認識させるについて。
私は画像認識についてはド素人なので、
ネットでポッキーの画像を取得して、テンプレートマッチングさせた。
認識させる対象の画像に映るポッキーのサイズはカメラから取得される物のため、
スケールがわからない。
そのため、ポッキーの画像をスケールを変えながらスコアが閾値を超えたら矩形範囲を取得
という強引な手法をとった。処理速度はすこぶる遅い。
実際のコードは
//ポッキーの位置を探す画像 UIImage *img = [UIImage imageNamed:@"hoge.jpg"]; cv::Mat src_img; UIImageToMat(img, src_img); //ポッキーの画像 UIImage *pp = [UIImage imageNamed:@"pp.jpg"]; cv::Mat pp_img; UIImageToMat(pp, pp_img); // ポッキーの画像が小さいと問答無用でスコアが高くなるので、大きいスケールから順にスコアを計算する for (int i = 200; i > 0; i--) { CGFloat scale = i * 0.01; CGFloat scale_x = pp.size.width * scale; CGFloat scale_y = pp.size.height * scale; if (scale_x >= img_scale.size.width || scale_y >= img_scale.size.height) continue; UIGraphicsBeginImageContext(CGSizeMake(scale_x, scale_y)); [pp drawInRect:CGRectMake(0, 0, scale_x, scale_y)]; UIImage *pp_scale = UIGraphicsGetImageFromCurrentImageContext(); //cv::Matの画像 cv::Mat pp_scale_img; UIImageToMat(pp_scale, pp_scale_img); //マッチング cv::Mat result_img; cv::matchTemplate(src_img, pp_scale_img, result_img, CV_TM_CCOEFF_NORMED); //スコア取得 cv::Rect roi_rect(0, 0, pp_scale_img.cols, pp_scale_img.rows); cv::Point max_pt; double maxVal; cv::minMaxLoc(result_img, NULL, &maxVal, NULL, &max_pt); if (maxVal >= 0.55) { //閾値0.55はだいたい良さそうな結果が出た値 //サイズ設定 roi_rect.x = max_pt.x; roi_rect.y = max_pt.y; //ポッキーの位置を矩形表示 cv::rectangle(src_img, roi_rect, cv::Scalar(0,0,255), 2); break; } } // 枠線を入れた画像をUIImageに変換 UIImage *result = MatToUIImage(src_img);
ものぐさな私はデフォルトで初期画面であるUITableViewControllerの背景に結果画像を出力させて動作確認していたので、
謎の線が入っているが、結果はこんな感じである
まだまだド素人だが、画像認識もなかなか楽しそうである。