20
15

More than 1 year has passed since last update.

OpenCvSharpでAKAZEを用いて特徴量を検出する

Last updated at Posted at 2019-11-20

概要

OpenCvSharpを用いての特徴点抽出の情報が少なく,実装まで苦労したのでメモついでに共有.pythonができないとは言ってない

今回は色々と使い勝手が良く,お気に入りのwindowsフォームアプリケーションで作成します

環境

windows10
Visual Studio 2019

実装

過去記事と同じ手順箇所は基本端折るので,不明なところがあればそっちに飛んで頂くか,コメントしてください

特徴点の抽出まで

1.NugetからOpenCvSharp4.Windowsをインストール

2.まずは定義
※画像の保存先パスはC:\cs_source\img\

Form1.cs
Mat mat     = new Mat(); //比較元画像
Mat temp    = new Mat(); //比較先画像
Mat output1 = new Mat(); //比較元画像の特徴点出力先
Mat output2 = new Mat(); //比較先画像の特徴点出力先
Mat output3 = new Mat(); //DrawMatchesの出力先

AKAZE akaze = AKAZE.Create(); //AKAZEのセットアップ
KeyPoint[] key_point1;        //比較元画像の特徴点
KeyPoint[] key_point2;        //比較先画像の特徴点
Mat descriptor1 = new Mat();  //比較元画像の特徴量
Mat descriptor2 = new Mat();  //比較先画像の特徴量

DescriptorMatcher matcher; //マッチング方法
DMatch[] matches; //特徴量ベクトル同士のマッチング結果を格納する配列

mat  = Cv2.ImRead(@"C:\cs_source\img\fish1.jpg");//比較元画像
temp = Cv2.ImRead(@"C:\cs_source\img\fish2.jpg");//比較先画像

今回はAKAZEという特徴量の計算アルゴリズムを使用
OpenCvSharp4ではこのようにMatは全て初期化しないと怒られるのでめんどうですね
ちなみに今回使用するジャイアントマンタくんの画像1と画像2(https://www.pakutaso.com/)
fish1.jpg
fish2.jpg

3.特徴点を出力する

Form1.cs

//特徴量の検出と特徴量ベクトルの計算
akaze.DetectAndCompute(mat, null, out key_point1, descriptor1);
akaze.DetectAndCompute(temp, null, out key_point2, descriptor2);

//画像1の特徴点をoutput1に出力
Cv2.DrawKeypoints(mat, key_point1, output1);
Cv2.ImShow("output1", output1);

//画像2の特徴点をoutput2に出力
Cv2.DrawKeypoints(temp, key_point2, output2);
Cv2.ImShow("output2", output2);

ここで実行すると下2つのウィンドウが表示される
image.png
image.png

特徴量をマッチングさせる

1.今回はBruteForceという総当たりマッチングを行う

Form1.cs
matcher = DescriptorMatcher.Create("BruteForce");
matches = matcher.Match(descriptor1, descriptor2);

2.マッチングした特徴量同士を線でつなぐ

Form1.cs
Cv2.DrawMatches(mat, key_point1, temp, key_point2, matches, output3);
Cv2.ImShow("output3", output3);

実行すると下のウィンドウが新たに表示される
image.png
なにもいじってないのに精度いいですね
流石OpenCV...

(おまけ)精度を上げる

まずmatchesの中身をコンソールで確認してみると
image.png
要素の説明はDMatchの公式リファレンスを参照してください
意外と距離あった・・・

精度関係で調べたらわかりますが,沢山の工夫された方法があります
ここでは,一番初歩的(主観)な方法であるDistanceに対して閾値を設定する方法で精度を上げていきたいと思います

百聞は一見に如かず,まずはコードを見てください(注:作者未だリーダブルコード未読)

Form1.cs
Mat output4           = new Mat(); //DrawMatchesの出力先
int good_match_length = 0;         //閾値以下の要素数を格納
int threshold         = 750;       //閾値

//閾値以下の要素数のカウント
for (int i = 0; i < key_point1.Length && i < key_point2.Length; ++i)
{
    if (matches[i].Distance < threshold)
    {
           ++good_match_length;
    }
}

DMatch[] good_matches = new DMatch[good_match_length];//閾値以下の要素数で定義

//good_matchesに格納していく
int j = 0;
for (int i = 0; i < key_point1.Length && i < key_point2.Length; ++i)
{
     if (matches[i].Distance < threshold)
     {
          good_matches[j] = matches[i];
          ++j;
     }
}

今回はビビッときた閾値750で実行
pythonじゃないのでDMatch[] good_matches;のようにただ定義するだけだと,未割当だかなんだかですぐ怒ってきます
まぁC#の利点っちゃあ利点とも言えますね
pythonゆとり仕様なんで(エアプ)

output3(チューン前)とoutput4(チューン後)の比較
image.png
ちょっと良くなったかも?

最後にコンソールから確認しましょう
image.png
いい感じに除外できてます

さいごに

今回は1番単純(超主観)な方法でチューンしていきましたが,ほかの方々の方法ではもっと精度が出ていますので,これは書き方の参考にでもするくらいの感じで見て頂ければ幸いです

これをきっかけにOpenCvSharpというニッチな世界に人が増えたらうれしいですね
参考資料は少ないし,配列付近のコマンドの自由性の低さとか苦労する点が多いです
本当にみんなpythonに行っちゃいそう

自分は使えないとかじゃないんで,環境がないだけなんで.ほんとに

参考URL

「OpenCV3でAKAZE特徴量を検出する」
https://dronebiz.net/tech/opencv3/akaze
「特徴点のマッチング」
http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_feature2d/py_matcher/py_matcher.html

20
15
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
15