web-dev-qa-db-ja.com

JavaでOpenCVを使用して2つの画像を比較する

OpenCVライブラリを使用して、2つの画像を比較(類似しているかどうかを判断)しようとしています。 Javaラッパーを構成し、Javaに書き直そうとしているいくつかのチュートリアル(主にC/C++))を見つけました。機能検出アプローチを使用しています。

問題は、私が現在使用しているアルゴリズムでは妥当な結果が生成されないことです(2つの類似した画像に共通点はなく、完全に異なる他の2つの画像間の一致を見つけると主張しています)。誰かがopenCVマッチャーを使用して妥当な結果を生成する方法を提案できますか?

これは画像比較のための私のコードです

private static void compareImages(String path1, String path2) {
    System.out.println(path1 + "-" + path2);

    FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB);
    DescriptorExtractor descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB);

    DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);

    // first image
    Mat img1 = Imgcodecs.imread(path1, Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);
    Mat descriptors1 = new Mat();
    MatOfKeyPoint keypoints1 = new MatOfKeyPoint();

    detector.detect(img1, keypoints1);
    descriptor.compute(img1, keypoints1, descriptors1);

    // second image
    Mat img2 = Imgcodecs.imread(path2, Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);
    Mat descriptors2 = new Mat();
    MatOfKeyPoint keypoints2 = new MatOfKeyPoint();

    detector.detect(img2, keypoints2);
    descriptor.compute(img2, keypoints2, descriptors2);

    // match these two keypoints sets
    MatOfDMatch matches = new MatOfDMatch();
    matcher.match(descriptors1, descriptors2, matches);

    for (DMatch m : matches.toArray()) {
      // how to use these values to detect the similarity? They seem to be way off
      // all of these values are in range 50-80 which seems wrong to me
      System.out.println(m.distance);
    }
  }

残念ながら、SURFやSIFTなどのアルゴリズムはJavaラッパーでは使用できないため、ORBを使用しています。コンピュータビジョンの経験がほとんどないかまったくないので、この単純な比較アルゴリズムを機能させようとしています。合理的な結果を生み出すために。

編集:私のユースケースは、さまざまな角度から撮影された画像に対してこのアルゴリズムを実行しています。より適切にフォーマットされるようにコードを更新しました。

比較するサンプル画像:

enter image description hereenter image description here

15
Smajl

ちょうど私の2セント:

  1. JavaではSURFとSIFTにアクセスできます: openCV DescriptorExtractor Reference 。 3年前にFREAK実装を試してみたところ、openCVがJavaにバイナリ記述子を渡すと、バイナリ記述子にいくつかの変更が発生していることがわかりました。 ORBにも同じ問題がある可能性があります。 cまたはc ++からの記述子のデータをJava側のものと比較しましたか?

  2. ブルートフォースマッチャーは、クエリイメージ内のすべてのフィーチャについて、トレインイメージから最適なフィーチャを見つけます。見た目がまったく違うとしても。あなたは試合をふるいにかけ、悪いものを落とさなければなりません。いくつかの戦略が存在しますが、簡単なのは一致の最高20%を取得することです(ただし、これによりすべての異常値が削除されることはありません)。 プログレッシブサンプルコンセンサス 私のセットアップでは非常にうまく機能しました。

  3. 機能を使用して画像の類似性を比較することには、落とし穴があります。機能の数と品質は写真のサイズと内容によって異なるため、画像をグローバルに比較することが難しくなります(2つの画像のどちらがもう一方よりも参照に似ているか知りたい場合)。 Calib3d.findHomography(obj, scene, CV_RANSAC);を使用して、1つの画像から別の画像への変換を推定し、重複領域の正規化されたピクセルの差を使用できます。
5
Gilfoyle

this SO Question で説明されているように、最も簡単で簡単な方法は、ヒストグラムを比較することです。アルゴリズムが特定のデータセットでのみ機能する必要がある場合は、別の色を使用してみてくださいチャネルを使用して、セット内の画像が最も類似している場所を確認します。

ヒストグラムのアプローチは実際的ではないように見えるかもしれませんが、画像の色の類似性を考えると、これはいくらか役立つと思います。

Photoshopで2つの画像のヒストグラムを比較した後:

histogram comparison

0
mmarkman