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

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

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

#環境
windows10
Visual Studio 2019
#実装
[過去記事](https://qiita.com/miwazawa/items/50cf5b913b058f59daa6)と同じ手順箇所は基本端折るので，不明なところがあればそっちに飛んで頂くか，コメントしてください
##特徴点の抽出まで
1.NugetからOpenCvSharp4.Windowsをインストール


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

```cs: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は全て初期化しないと怒られるのでめんどうですね
ちなみに今回使用するジャイアントマンタくんの画像１と画像２（https://www.pakutaso.com/）
![fish1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518001/60104d53-8e99-df1c-c20e-b440a5caf6c3.jpeg)
![fish2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518001/df7f248a-ddec-d150-e0f8-18719148bb01.jpeg)




3.特徴点を出力する

```cs:Form1.cs

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

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

//画像２の特徴点をoutput2に出力
Cv2.DrawKeypoints(temp, key_point2, output2);
Cv2.ImShow("output2", output2);
```
ここで実行すると下２つのウィンドウが表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518001/a2a44fca-30f1-4408-fefb-0c0faa15af47.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518001/2a570c38-7f20-6991-2c5f-de6fc132508b.png)


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




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

```cs:Form1.cs
matcher = DescriptorMatcher.Create("BruteForce");
matches = matcher.Match(descriptor1, descriptor2);
```
2.マッチングした特徴量同士を線でつなぐ


```cs:Form1.cs
Cv2.DrawMatches(mat, key_point1, temp, key_point2, matches, output3);
Cv2.ImShow("output3", output3);
```
実行すると下のウィンドウが新たに表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518001/1d5db8df-4ac2-955d-3cf9-6ab5a204a7ff.png)
なにもいじってないのに精度いいですね
流石OpenCV...


##（おまけ）精度を上げる
まずmatchesの中身をコンソールで確認してみると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518001/92e9b340-4c46-0408-4a00-beb56409d4d0.png)
要素の説明はDMatchの[公式リファレンス](https://docs.opencv.org/3.4/d4/de0/classcv_1_1DMatch.html)を参照してください
意外と距離あった・・・

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

百聞は一見に如かず，まずはコードを見てください（注：作者未だリーダブルコード未読）

```cs: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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518001/0255cafc-bd67-663d-54ee-31e0ed6e6895.png)
ちょっと良くなったかも？

最後にコンソールから確認しましょう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518001/aa117ab7-8253-cd67-c7c2-8126f6fc2103.png)
いい感じに除外できてます



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

これをきっかけに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