株式会社インデペンデンスシステムズ横浜

システム開発エンジニアの西田五郎が運営しております。Raspberry Pi や Arduino その他新規開発案件のご依頼をお待ちしております。

OpenCV

OpenCVでのORBによる特徴点抽出とマッチング(その1)基本的な使い方

投稿日:

OpenCVでのORBアルゴリズムによる特徴点抽出とマッチングの処理についてです。特徴点抽出とマッチングの処理はOpenCVでは重要なテーマの一つだと思います。特徴点とは画像上での特徴となる点、代表的にはコーナーとなるでしょうか。この特徴点抽出、マッチングの課題としては、拡大縮小や回転された形状でも同じ特徴点が抽出出来るということがあります。これにより、動画上の物体追跡や物体認識に応用出来ます。(※これらの画像処理の理論的な内容についてはページ最後の関連リンク等を参照して下さい。)

ここではOpenCVでのORBアルゴリズムを使ってみます。ORBアルゴリズム以外にもいろいろなアルゴリズムが使えますが、特許が有効なアルゴリズムもあるので特許の制約がないORBを使ってみました。OpenCVでのプログラミングとしては他のアルゴリズムでも同様に使えます。

実際のプログラミングです。以下のインターフェースを利用して処理を行います。
特徴点検出 – Feature Detector インターフェース
特徴記述 – Descriptor Extractor インターフェース
特徴点マッチング – Descriptor Matcher インターフェース

以下のようなプログラムを作成しました。(※関数部分のみです。全体が必要な場合はお手数ですがプログラム一式をダウンロードして参照して下さい。)

プログラム一式は以下です。(※用途に関わらずご利用頂いて問題ありませんが、一切無保証です。不具合等の責任は負いかねます。)
プログラム一式
OpenCVを含むので33M程度のサイズです。

開発環境は、Visual Studio Community 2013 Visual C++ です。OpenCVはNuGetを使って以下で書いた方法で導入しています。
Visual Studio Community 2013のVisual C++でOpenCVを使う


//入力画像
char* imagePath1 = "c:\\data\\shapes1.jpg";
char* imagePath2 = "c:\\data\\shapes1-1.jpg";

/*-----------------------------
最も基本的な使い方
-------------------------------*/
void orbBasic(void)
{
	// 画像の読み込み
	Mat img1 = imread(imagePath1);
	Mat img2 = imread(imagePath2);

	// FeatureDetectorオブジェクトの生成
	Ptr<FeatureDetector> detector = FeatureDetector::create("ORB");
	
	// DescriptionExtractorオブジェクトの生成
	Ptr<DescriptorExtractor> extractor = DescriptorExtractor::create("ORB");

	// DescriptorMatcherオブジェクトの生成
	Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");

	// 特徴点情報を格納するための変数
	vector<KeyPoint> keypoints1;
	vector<KeyPoint> keypoints2;

	// 特徴点抽出の実行
	detector->detect(img1, keypoints1);
	detector->detect(img2, keypoints2);

	// 画像の特徴情報を格納するための変数
	Mat descriptor1;
	Mat descriptor2;

	// 特徴記述の計算を実行
	extractor->compute(img1, keypoints1, descriptor1);
	extractor->compute(img2, keypoints2, descriptor2);

	// 特徴点のマッチング情報を格納する変数
	vector<DMatch> dmatch;

	// 特徴点マッチングの実行
	matcher->match(descriptor1, descriptor2, dmatch);

	// マッチング結果画像の作成
	Mat result;
	drawMatches(img1, keypoints1, img2, keypoints2, dmatch, result);
	imshow("matching", result);

	cvWaitKey(0);
	return;
}

このプログラムで以下の画像について実行しました。同じ画像で実行しました。(※画像はクリックで拡大します。以下同様です。)
shapes1

以下のような結果になりました。
0001

確かに特徴点をとらえているのですが、三角形の頂点を全てとらえていないのと、四角形ではギザギザになっている点をとらえているのはいいのですが、肝心の頂点をとらえていないです。

それではどうするかというと、ORBのパラメータを指定します。ORBのパラメータはデフォルトで以下のように定義されています。
ORB(int nfeatures = 500, float scaleFactor = 1.2f, int nlevels = 8, int edgeThreshold = 31,int firstLevel = 0, int WTA_K=2, int scoreType=ORB::HARRIS_SCORE, int patchSize=31 );

(最大検出数=500、ピラミッドレイヤー間の縮小比率=1.2f、ピラミッドレベル数=8、エッジしきい値=31、最初のレベル=0、WTA_K=2、スコアタイプ=0、パッチサイズ=31)

それではこれをどのように指定するかということですが、私は画像処理の理論に詳しい訳ではありませんで、ここでは以下のページの数値を利用させて頂きました。(著者の石立喬先生ありがとうございます。)上記の日本語でのパラメータの表現も利用させて頂きました。

OpenCVとVisual C++による画像処理と認識(11)ORBを用いて特徴点のマッチングを行う

以下のように設定します。

// FeatureDetectorオブジェクト
Ptr<FeatureDetector> detector = new ORB(80, 1.25f, 4, 7, 0, 2, 0, 7);

// DescriptionExtractorオブジェクトの生成
Ptr<DescriptorExtractor> extractor = new ORB(80, 1.25f, 4, 7, 0, 2, 0, 7);

これで実行した結果が以下です。
0001

まず特徴点の数がデフォルトパラメータの場合と比較して少なくなっていますが、これは1個目のパラメータの影響です。デフォルトでは最大500となっていますが最大80に変更したので少なくなりました。実際には60個検出されました。それでも三角形の各頂点を検出してバランスよく対応しているのでいい結果だと思います。斜めに対応している点は回転を考慮したのかなと想像しています。(※申し訳ありませんが、他のパラメータの詳細等は上記のページを参照して下さい。私では説明出来ません。)

次により近似度の高い特徴点のみを抽出するという処理です。近似度が高いとは、Hamming距離が近いということのようで、その数値はマッチング結果のDMatch構造体のdistanceに格納されます。

ここでは、マッチング結果の中で最小のdistanceを取得して、そのdistanceより離れすぎの結果は除外するという処理を追加してみました。以下、その部分です。

// 特徴点マッチング
	matcher->match(descriptor1, descriptor2, dmatch);

	vector<DMatch> dmatchOK;

	int count = dmatch.size();
	int matchCount = 0;

	// 最小距離の取得
	double min_dist = DBL_MAX;
	for (int i = 0; i < (int)dmatch.size(); i++){
		double dist = dmatch[i].distance;

		if (dist < min_dist){
			min_dist = dist;
		}
	}
	if (min_dist < 1.0)
	{
		min_dist = 1.0;
	}

	// しきい値を設定する
	const double threshold = 2.0 * min_dist;//これが実験

	for (int i = 0; i < (int)dmatch.size(); i++){
		if (dmatch[i].distance < threshold){
			matchCount++;

			dmatchOK.push_back(dmatch[i]);
		}
	}

	// しきい値内の結果で、マッチング結果画像の作成
	Mat result;
	drawMatches(img1, keypoints1, img2, keypoints2, dmatchOK, result);
	imshow("matching prm thre", result);

	printf("match = %d\n", count);
	printf("matchOK = %d\n", matchCount);

ここでしきい値は以下です。
const double threshold = 2.0 * min_dist;

2.0はとりあえず設定値の例です。最適な値ということではないのでご了承ください。
これで実際にどうなったかということですが、テスト画像では同じ画像で比較したのが理由だと思いますが、特に除外されることもなく全て近似度の高い結果となりました。このしきい値の処理は次回に引き続き別の画像でテストします。

関連サイト、関連書籍
OpenCVとVisual C++による画像処理と認識(10) —– いろいろな特徴検出法を試し、道路標識に応用する —–
OpenCVとVisual C++による画像処理と認識(11)—– ORBを用いて特徴点のマッチングを行う —–

上記サイトの著者の石立喬先生の書籍です。Kindle版です。


(受注)書籍版、PDF版もあります。

AdSense

AdSense

-OpenCV

執筆者:

関連記事

OpenCVをWin32ベースで利用する(その2)OpenCVの組み込み

OpenCVをWin32ベースで利用するの2回目です。前回はベースになるダイアログベースのアプリケーションを作成しました。今回はこのアプリケーションにOpenCVを組み込んで実際に動かしてみます。 ( …

OpenCVでのORBによる特徴点抽出とマッチング(その2)GUIの利用

OpenCVでのORBアルゴリズムによる特徴点抽出とマッチングの処理についての2回目です。前回はVisual Studio Community 2013のVisual C++コンソールアプリでORBに …

OpenCV2 cv::Matクラスの基礎

OpenCV2のcv::Matクラスの基礎についてです。OpenCV 2.0からはC++のインターフェースが追加されました。cv::MatクラスはそのC++インターフェースで画像を扱うクラスです。まず …

OpenCVをWin32ベースで利用する(その1)ダイアログベースアプリ

OpenCVをWin32ベースのアプリケーションで利用してみます。今回はまず、Win32ベースとはどういう作り方かというところからベースになるダイアログベースのアプリを作成します。また、それをベースに …

OpenCVで輪郭抽出から隣接領域の切り出し(その3)凸包の取得

OpenCVで画像内の輪郭抽出からその輪郭の隣接領域(四角形)を求めてその領域を切り出すという処理を作ってみました。前回までのプログラムとほぼ同じですが、前回までは輪郭抽出 → 直線近似 → 隣接領域 …