OpenCV の特徴量検出器を使ってみる

プチロボ事始め | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/2416
プチロボで4軸構成にしてみる | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/2421
OpenCV を使ってエッジ抽出 | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/2452
OpenCV を使って顔認識 | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/2460
OpenCV のテンプレートマッチを使って駒を検出 | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/2468

の続き

試しに特徴量を検出してみると、下記な感じ。

#include <iostream>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace std ;

int main(int argc, char *argv[])
{
	cv::Mat img = cv::imread(argv[1], 1);
  	if(!img.data) return -1;

	// グレースケールに変換
	cv::Mat gray_img, canny_img ;
	cv::Mat gray_img2, canny_img2;
	cv::cvtColor(img, gray_img, CV_BGR2GRAY);
	cv::normalize(gray_img, gray_img, 0, 255, cv::NORM_MINMAX);
	cv::Canny( gray_img, canny_img, 10, 100, 3 );

	// keypoints を解放するとエラーになるので、対策として new しておく
  	vector<cv::KeyPoint> *keypoints = new vector<cv::KeyPoint>();
  	vector<cv::KeyPoint> *keypoints2 = new vector<cv::KeyPoint>();

  	// 固有値に基づく特徴点検出
  	// maxCorners=80, qualityLevel=0.01, minDistance=5, blockSize=3
  	cv::GoodFeaturesToTrackDetector detector(30, 0.01, 5, 3);
  	detector.detect(gray_img, *keypoints);
  	detector.detect(canny_img, *keypoints2);

	// キーポイントにマークを付ける
	cv::cvtColor(gray_img, gray_img2, CV_GRAY2BGR);
 	cv::Scalar color(0,200,255);
 	for( vector<cv::KeyPoint>::iterator itk = keypoints->begin();
 		 itk != keypoints->end();
 		 ++itk)
 	{
    	circle(gray_img2, itk->pt, 1, color, -1);
    	circle(gray_img2, itk->pt, itk->size, color, 1, CV_AA);
 		if( itk->angle >= 0 ) {
      		cv::Point pt2(itk->pt.x + cos(itk->angle)*itk->size, itk->pt.y + sin(itk->angle)*itk->size);
      		cv::line(gray_img2, itk->pt, pt2, color, 1, CV_AA);
    	}
 	}
	// キーポイントにマークを付ける
	cv::cvtColor(canny_img, canny_img2, CV_GRAY2BGR);
 	for( vector<cv::KeyPoint>::iterator itk = keypoints2->begin();
 		 itk != keypoints2->end();
 		 ++itk)
 	{
    	circle(canny_img2, itk->pt, 1, color, -1);
    	circle(canny_img2, itk->pt, itk->size, color, 1, CV_AA);
 		if( itk->angle >= 0 ) {
      		cv::Point pt2(itk->pt.x + cos(itk->angle)*itk->size, itk->pt.y + sin(itk->angle)*itk->size);
      		cv::line(canny_img2, itk->pt, pt2, color, 1, CV_AA);
    	}
 	}

	// 画面に表示
  	cv::namedWindow("Normal", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);
  	cv::namedWindow("Gray", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);
  	cv::namedWindow("Canny", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);

	cv::imshow("Normal", img);
	cv::imshow("Gray", gray_img2);
	cv::imshow("Canny", canny_img2);
  	cv::waitKey(0);

  	// エラーになるので解放しない
  	// delete keypoints ;

  	return 0;
}


 

普通にグレースケールにした場合と、エッジ検出後に特徴量を計算しています。
が、ここで使っている「特徴量」というのは、ひとつの画像の特徴的な部分を抽出するという意味で、HMM 法や(多分)SVM 法による他との比較による「特徴量」とは意味が違う…のだと思うんだけど、ちと専門用語になるので、詳細は割愛。

さて、先の駒のように「みかん」と「ダイヤモンド」では形状が違うので、グレースケールにしても大丈夫なわけですが、駒がだけで異なる場合はちょっと難しい…というか違いを検出するのは無理。


なので、特徴量を検出する場合は、

  1. 異なる駒同士の違いを検出するための「特徴量」を計算する。
  2. 盤面上の駒と比較してスコアを出す計算式が必要

になります。

いわゆる、自分自身を検出した時にだけスコアが高くなるような計算式を用意すればよいわけで。

と思っていたら、

Tercel::Diary: 形状マッチングで文字認識をさせようとして失敗してみた
http://tercel-sakuragaoka.blogspot.com/2011/05/blog-post.html

なところで、cvMatchShapes を使っているので、ちょっと試してみる。

カテゴリー: C++, プチロボ パーマリンク