OpenCV
akazeLenna

OpenCV3から追加されたAKAZE特徴量で画像のマッチングをしてみました。言語はC#です。

環境と下準備

  • Windows 8.1 64bit
  • Visual Studio Community 2015
  • OpenCVSharp3-AnyCPU

Visual StudioのNuGetによるOpenCVSharp3の導入はすっ飛ばします。多くのページで紹介されているのでそちらを参考にしてください。コード内にusing OpenCvSharp;を忘れずに。

一番単純なコード

Mat src1 = new Mat(@"Lenna0.png");
Mat src2 = new Mat(@"Lenna1.png");

KeyPoint[] keypoints1, keypoints2;
MatOfFloat descriptors1 = new MatOfFloat();
MatOfFloat descriptors2 = new MatOfFloat();

AKAZE akaze = AKAZE.Create();

akaze.DetectAndCompute(src1, null, out keypoints1, descriptors1);
akaze.DetectAndCompute(src2, null, out keypoints2, descriptors2);

BFMatcher matcher = new BFMatcher();
DMatch[] matches = matcher.Match(descriptors1, descriptors2);

Mat outImg = new Mat();
Cv2.DrawMatches(src1, keypoints1, src2, keypoints2, matches, outImg);

using (new Window("outImg", outImg))
{
    Cv2.WaitKey();
}

解説

順を追って説明します。

画像の読み込み

Mat src1 = new Mat(@"Lenna0.png");
Mat src2 = new Mat(@"Lenna1.png");

最初の2行は画像を読み込んでMat型の変数に格納しています。
この場合、画像はプロジェクトのbin > Debugの中に入れています。面倒ならば絶対パスで書きましょう。

使用する変数の用意

KeyPoint[] keypoints1, keypoints2;
MatOfFloat descriptors1 = new MatOfFloat();
MatOfFloat descriptors2 = new MatOfFloat();

KeyPoint1,2は特徴点の位置やパラメータを保存する変数です。複数の値が入るので配列になっています。
descriptor1,2は特徴情報を記述するための変数です。

特徴点検出と抽出を行うオブジェクトの生成

AKAZE akaze = AKAZE.Create();

今回はAKAZE特徴量を使用するのでAKAZE.Create();としていますが、他の特徴料(ORBなど)を使いたければORB.Create();とすれば良いです。AKAZEと型指定せずvarにすれば楽でしょう。

特徴点検出と計算を実行

akaze.DetectAndCompute(src1, null, out keypoints1, descriptors1);
akaze.DetectAndCompute(src2, null, out keypoints2, descriptors2);

detectとcomputeはそれぞれ別で用意されていますが、画像・キーポイント用変数・特徴記述用変数を渡してあげるとまとめてやってくれます。第二引数は仮引数が”mask”となっているので、おそらく画像内の一部分を実行したい場合に指定するのでしょう。今回は全体で実行するのでnullです。

取り出した特徴点同士でマッチングを行う

BFMatcher matcher = new BFMatcher();
DMatch[] matches = matcher.Match(descriptors1, descriptors2);

BFMatcherというのはBruteForceMatcherの略で、和訳すると「総当りマッチング」です。
そのmatchメソッドに特徴情報を渡し、DMatchという型の変数に結果を格納させます。
matchesの中には、二枚の画像の何個目と何個目のKeyPointがマッチしたのかが格納されます。

マッチングしたポイントをカラフルな線でつなぐ

Mat outImg = new Mat();
Cv2.DrawMatches(src1, keypoints1, src2, keypoints2, matches, outImg);

まず先に出力用の画像を用意。 そして、DrawMatchesメソッドに画像・ポイント・マッチ結果配列・出力用画像を渡してあげます。

結果の表示

using (new Window("outImg", outImg))
{
    Cv2.WaitKey();
}

ウィンドウが閉じられたらデータを破棄するためにusing文を使用しています。
簡単に書くならnew Window("outImg", outImg)でOKです。