はじめに
今回は、OpenCvSharpを使用して、画像の特徴点と類似度を取得してみます。
全く同じ画像かどうかの比較ではなく、似ているかどうかを判定してみます。
画像に対して特徴量を取得し、比較するやり方です。
OpenCvSharpのインストールや、サンプルアプリの作成は以下の記事を参考にしてください。
Visual Studio 2022のインストールにつきましては、以下の記事にまとめましたので参考ください。
他にも私のブログで、OpenCVについて解説している記事がありますのでご覧ください。
画像の特徴点の検出
まずは画像を用意します。
以下のフリー素材を使用しました。
私は以下の場所に画像を保存しました。
D:\project\img\cat1.jpg
画像の特徴点をAKAZEを使用して、検出してみます。
特徴点を検出するアルゴリズムは、SURFやSIFTなどがあります。
フォームにボタンを配置し、クリックイベントに以下のように実装しました。
private void button9_Click(object sender, EventArgs e)
{
using (var mat = new Mat(@"D:\project\img\cat1.jpg"))
using (var descriptors = new Mat())
using (var drowKeyPoint = new Mat())
{
var akaze = AKAZE.Create();
// キーポイントを検出
akaze.DetectAndCompute(mat, null, out KeyPoint[] keyPoints, descriptors);
// 画像に描画
Cv2.DrawKeypoints(mat, keyPoints, drowKeyPoint);
Cv2.ImShow("image", drowKeyPoint);
}
}
keyPointsについては、outパラメーター修飾子で参照渡しにし、検出結果を受け取っています。
実行してみると、以下のように画像の特徴点を取得することができました。
画像の類似度の取得
比較1
次に、画像の類似度を取得してみます。
先程抽出した、画像の特徴点同士のマッチングを行い、類似度を取得します。
比較対象として、先程の画像と似ている、以下のフリー素材を使用しました。
私は以下の場所に画像を保存しました。
D:\project\img\cat2.jpg
今回は特徴量のマッチングとして、BFMatcher(Brute Force)を使用しました。
その名の通り、総当たりです。
他にもFlannBasedMatcherなどがあります。
実用的に使用できるように関数を作成しました。
引数に、比較したい画像を2つ指定します。
また、比較結果の画像を表示するかどうかのフラグを設けました。
/// <summary>
/// 2つの画像の類似度をチェックする
/// </summary>
/// <param name="mat1"></param>
/// <param name="mat2"></param>
/// <param name="show">画像を表示するかのフラグ</param>
/// <returns></returns>
private float ImageMatch(Mat mat1, Mat mat2, bool show)
{
using (var descriptors1 = new Mat())
using (var descriptors2 = new Mat())
{
// 特徴点を検出
var akaze = AKAZE.Create();
// キーポイントを検出
akaze.DetectAndCompute(mat1, null, out KeyPoint[] keyPoints1, descriptors1);
akaze.DetectAndCompute(mat2, null, out KeyPoint[] keyPoints2, descriptors2);
// それぞれの特徴量をマッチング
var matcher = new BFMatcher(NormTypes.Hamming, false);
var matches = matcher.Match(descriptors1, descriptors2);
// 2つの画像のマッチング結果を表示
if (show)
{
using (var drowMatch = new Mat())
{
Cv2.DrawMatches(mat1, keyPoints1, mat2, keyPoints2, matches, drowMatch);
Cv2.ImShow("image match", drowMatch);
}
}
// 平均距離を返却(小さい方が類似度が高い)
var sum = matches.Sum(x => x.Distance);
return sum / matches.Length;
}
}
類似度として、特徴量マッチングの距離の平均を取得しました。
全く同じであれば0であり、値が小さいほど、画像は似ていることになります。
呼び出し方は以下です。
private void button8_Click(object sender, EventArgs e)
{
using (var mat1 = new Mat(@"D:\project\img\cat1.jpg"))
using (var mat2 = new Mat(@"D:\project\img\cat2.jpg"))
{
// 2つの画像を比較(平均距離をスコアとした)
float score = ImageMatch(mat1, mat2, true);
Console.WriteLine("score:" + score);
}
}
実行してみた結果は以下です。
左右に二枚の画像が配置しており、それぞれの特徴量を線で引いています。
スコアは以下になりました。(コンソールに出力されています)
score:100.8207
比較2
折角なので、もう一枚比較してみましょう。
比較結果は以下です。
スコアは先程よりは少し上がりました。
先程の猫同士のほうが似ていることになりますね。
score:121.8167
さいごに
今回は画像の類似度を求めてみました。
OpenCvSharpで簡単にできるので、ぜひ試してみてくださいね😊
他にも私のブログで、OpenCVについて解説している記事がありますのでご覧ください。
コメント