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

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

OpenCV

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

投稿日:

OpenCVでのORBアルゴリズムによる特徴点抽出とマッチングの処理についての2回目です。前回はVisual Studio Community 2013のVisual C++コンソールアプリでORBによる特徴点抽出の基本的と思われる処理を作成しました。今回はGUIを使ってマッチング処理を試してみました。

処理としては、1枚の画像を最大10枚の画像とORBによる特徴点抽出とマッチングを行い、10枚の中で有効なマッチングの数が多かった画像とのマッチング画像を表示します。

今回テストした内容です。数字の画像(以下は例として2の画像)を用意しました。0から9までの数字で、MS Pゴシックのサイズ250のフォントです。
2

これで同じ画像の2を0から9までと比較してみます。もちろん同じ2の画像で最大の有効なマッチングの個数が得られます。今回のプログラムで以下のように実行します。

まず、0から9までの画像を同じディレクトリに用意します。ここでは、C:\image配下に用意しました。
0005

プログラムを以下のように実行していきます。まず起動直後の画面です。
0006

0から9までの画像の場所を指定します。ここでは初期設定のC:\imageのままです。画像の種類も初期設定のJPEGです。
0007

元画像を読み込みます。ここで元画像というのは0.jpgから9.jpgの画像のことです。
0008

対象画像を読み込みます。ここでは2ですが、もちろんどれでもいいです。画面に表示されます。
0009

マッチング実行ボタンで実行します。
0010

有効なマッチング数が最大のマッチング画像が表示されます。もちろん同じ画像の2です。
0011

実際のマッチングの結果
実際のマッチングの結果はデバッグ画面に表示するようにしています。デバッガを起動して以下のように出力画面に表示されます。
0001

実際の数値は以下です。それぞれ70個の特徴点が抽出され、ハミング距離がしきい値内の個数が以下となりました。
2 – 70
3 – 35
8 – 35
0 – 34
6 – 33
9 – 30
5 – 27
7 – 16
1 – 19
4 – 6

しきい値を1.0にしてみました。より似ていると評価される点に絞るという意味合いです。
2 – 70
3 – 23
8 – 21
0 – 20
6 – 16
9 – 15
5 – 9
7 – 7
1 – 7
4 – 1

しきい値を3.0にしてみました。より多くの特徴点を有効にしています。順番が変わりました。
2 – 70
3 – 49
0 – 42
9 – 41
6 – 39
5 – 38
8 – 37
1 – 27
7 – 20
4 – 11

この数字が何を意味しているかというと、このフォントでこの大きさで2とどれが似ているかということだと思うのですが、いかがでしょうか。確かに3や8の方が1や4と比較して似ているとは思います。

次にORBで得意とされる回転を試します。3を回転しました。
3Rote

これで実行します。3に最も似ていると判断したようです。
0002

7、8も最も似ていると判定しました。
0003

0004

縮小も試しました。3を90%にして試したのですが、0,2,8,9 あたりと同じような特徴になるようです。

以上、何とか特徴点を捉えたかなという結果です。

ここからプログラムの説明です。

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

プログラムとしては、前回の処理を以下のGUIプログラムで実行しているということです。OpenCVをNuGetで組み込んで、前回の処理をこのGUI上で実行しています。
Visual Studio Community 2013のVisual C++でOpenCVを使う

プログラムの主な部分の説明です。まず最大10枚分の画像を読む処理です。元画像読み込みボタンで実行されます。指定されたディレクトリの配下の0.jpgまたは0.pngから順に9.jpgまたは9.pngまで読み込みます。必ず0から読みますが、9までのファイルがなければループを抜けます。

変数の宣言部分等全体はお手数ですが、プログラム一式をダウンロードして参照して下さい。

/*----------------------------------------------
マッチング元画像の読み込み
-----------------------------------------------*/
void readImagesForMatch()
{
	int idx = 0;
	string imgPath = "";

	imagesFromFiles.clear();

	//画像形式
	hCombo = GetDlgItem(hwMain, IDC_COMBO1);
	comNo = (UINT)SendMessage(hCombo, CB_GETCURSEL, 0, 0);
	char imgExt[10];
	if (comNo == 0){
		strcpy(imgExt, ".jpg");
	}
	else
	{
		strcpy(imgExt, ".png");
	}

	//ディレクトリ名
	GetDlgItemText(hwMain, IDC_EDIT1, (LPTSTR)szBufEdit1, (int)sizeof(szBufEdit1));
	imgDirPath = szBufEdit1;
	imgDirPath += "\\";

	//0.jpgから9.jpgまで順に読み込み
	for (idx = 0; idx < 10; idx++){
		imgPath = imgDirPath + to_string(idx) + imgExt;

		//ファイル存在チェック
		ifstream file(imgPath.c_str());
		if (!file){
			break;
		}

		Mat img = imread(imgPath);
		imagesFromFiles.push_back(img);
	}
}

マッチング処理は以下です。対象画像読み込みボタンで画面上の読み込んだ画像と、上記で読み込んだ最大10枚の画像を順にマッチングして、有効な特徴点の数が多い画像とのマッチング結果を表示します。ORBの部分は、前回を参照して下さい。

/*----------------------------------------------
マッチング実行
-----------------------------------------------*/
void matching()
{
	// FeatureDetectorオブジェクトの生成
	Ptr<FeatureDetector> detector = new ORB(80, 1.25f, 4, 7, 0, 2, 0, 7);
	Ptr<DescriptorExtractor> extractor = new ORB(80, 1.25f, 4, 7, 0, 2, 0, 7);

	// 特徴点情報
	vector<KeyPoint> keypoints1;
	vector<KeyPoint> keypoints2;

	// 対象画像の処理
	Mat descriptor1;

	detector->detect(imgMatRead, keypoints1);
	extractor->compute(imgMatRead, keypoints1, descriptor1);

	//個数が最大の番号
	int maxIdx = -1;

	//カウンタ
	int count = 0;
	int matchCount = 0;
	int matchCountMax = -1;

	//しきい値内の個数
	vector<DMatch> dmatchOK;

	//各画像でマッチング
	int idx = 0;

	for (idx = 0; idx < (int)imagesFromFiles.size(); idx++){

		detector->detect(imagesFromFiles[idx], keypoints2);

		// 特徴情報
		Mat descriptor2;

		// 特徴記述の計算
		extractor->compute(imagesFromFiles[idx], keypoints2, descriptor2);

		// DescriptorMatcher生成
		Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");

		// 特徴点のマッチング情報
		vector<DMatch> dmatch;

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

		count = dmatch.size();
		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;
		}

		// しきい値を設定する
		double dThrs = (double)Pos / (double)10.0;
		const double threshold = dThrs * min_dist;

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

		//デバッグ用出力
		OutputDebugStringForThis("%d - %d\n", idx, count);
		OutputDebugStringForThis("%d - %d\n", idx, matchCount);

		//しきい値以内の個数のカウント
		if (matchCount > matchCountMax){
			maxIdx = idx;
			matchCountMax = matchCount;

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

	// しきい値内の結果で最大の個数であったマッチング結果画像の作成
	Mat result;
	drawMatches(imgMatRead, keypoints1, imagesFromFiles[maxIdx], keypoints2, dmatchOK, result);
	imshow("matching", result);
}

以上、今回は、ORBアルゴリズムでの特徴点抽出でした。OpenCVはまだまだいろいろとテーマがあるのでこれからも書けたらと思います。

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

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


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

AdSense

AdSense

-OpenCV

執筆者:

関連記事

OpenCVで背景差分とテスト的な動体検知

OpenCVで背景差分を試してみました。あとテスト的な動体検知も試してみました。背景差分とはあらかじめ取得した画像を背景画像として、観測時点の画像とその背景画像との差分を取ることによりその差分を前景領 …

Raspberry Pi 4にOpenCVをインストールしてPythonで動作確認

Raspberry Pi 4にOpenCVをインストールして動作確認をしました。Pythonでのプログラミングを想定して動作確認はPythonで行いました。

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

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

Tesseract-OCRの導入(その3)OpenCVの出力を認識する

2019/07/20追記 この記事を書いてから随分と経過しました。完全に情報が古くなっています。外部のサイトですが必要な場合は以下等を参照して下さい。 PythonとTesseract OCRで文字認 …

Visual Studio Community 2013のVisual C++でOpenCVを使う

Visual Studio Community 2013のVisual C++でOpenCVを使う方法についてです。Visual Studio Community 2013については前回書きましたが、 …