OpenCVで2つの画像がどの程度類似しているかをどのように評価できますか?


140

OpenCVは2つの画像の比較をサポートし、これらの画像がどの程度類似しているかを示す値(おそらくパーセンテージ)を返しますか?たとえば、同じ画像が2回渡された場合は100%が返され、画像がまったく異なる場合は0%が返されます。

StackOverflowについては、すでに多くの同様のトピックを読みました。かなりググリングもしました。残念ながら、満足のいく答えを見つけることができませんでした。


回答:


208

これは非常に大きなトピックであり、3行のコードから研究雑誌全体に回答しています。

そのような最も一般的な手法とその結果について概説します。

ヒストグラムの比較

最も単純で最速の方法の1つ。画像の類似性を見つける手段として数十年前に提案されました。アイデアは、森にはたくさんの緑があり、人間の顔にはたくさんのピンクなどがあるということです。したがって、2つの画像を森林と比較すると、ヒストグラムに類似性が得られます。両方に緑がたくさんあるからです。

欠点:単純すぎる。どちらも黄色なので、バナナとビーチは同じに見えます。

OpenCVメソッド:compareHist()

テンプレートマッチング

ここでの良い例は、matchTemplateが適切な一致を見つけることです。検索対象の画像と検索画像をたたみ込みます。これは通常、大きい画像部分から小さい画像部分を見つけるために使用されます。

欠点:同じ画像、同じサイズと向きでのみ良い結果が返されます。

OpenCVメソッド:matchTemplate()

特徴照合

画像検索を行う最も効率的な方法の1つと考えられています。画像から多数の特徴が抽出され、回転、拡大縮小、または傾斜した場合でも同じ特徴が再び認識されることが保証されます。この方法で抽出された特徴は、他の画像特徴セットと照合できます。最初の画像と一致する特徴の割合が高い別の画像は、同じシーンを描いていると見なされます。

2組の点の間のホモグラフィを見つけると、元の画像間の撮影角度の相対的な違いや重なりの量も見つけることができます。

これには多くのOpenCVチュートリアル/サンプルがあり、ここに素晴らしいビデオがあります。OpenCVモジュール全体(features2d)が専用です。

欠点:遅いかもしれません。完璧ではありません。


上の上OpenCVのQ&AサイトIは、画像における人間の顔や車などのオブジェクトを識別するために使用され、全体像と質感記述子を比較する際に最適です特徴記述子、との違いについて話しています。


いくつかの異なる画像しかない類似の画像(たとえば、新しいオブジェクトが他の同じビューに移動された)を比較するには、absdiff codota.com / code / java / methods / org.opencv.core.Core / absdiffを使用し て結果をしきい値処理することもできますシーンごとに変化した領域を強調表示できるマスクを作成します。
マックスF.

34

同じ画像を一致させる場合(同じサイズ/向き)

// Compare two images by getting the L2 error (square-root of sum of squared error).
double getSimilarity( const Mat A, const Mat B ) {
if ( A.rows > 0 && A.rows == B.rows && A.cols > 0 && A.cols == B.cols ) {
    // Calculate the L2 relative error between images.
    double errorL2 = norm( A, B, CV_L2 );
    // Convert to a reasonable scale, since L2 error is summed across all pixels of the image.
    double similarity = errorL2 / (double)( A.rows * A.cols );
    return similarity;
}
else {
    //Images have a different size
    return 100000000.0;  // Return a bad value
}

ソース


12

サムのソリューションで十分です。ヒストグラムの違いとテンプレートマッチングの両方を組み合わせて使用​​しました。これは、100%の時間で1つの方法が機能しなかったためです。ただし、ヒストグラム法はそれほど重要ではありません。これが私が単純なpythonスクリプトで実装した方法です。

import cv2

class CompareImage(object):

    def __init__(self, image_1_path, image_2_path):
        self.minimum_commutative_image_diff = 1
        self.image_1_path = image_1_path
        self.image_2_path = image_2_path

    def compare_image(self):
        image_1 = cv2.imread(self.image_1_path, 0)
        image_2 = cv2.imread(self.image_2_path, 0)
        commutative_image_diff = self.get_image_difference(image_1, image_2)

        if commutative_image_diff < self.minimum_commutative_image_diff:
            print "Matched"
            return commutative_image_diff
        return 10000 //random failure value

    @staticmethod
    def get_image_difference(image_1, image_2):
        first_image_hist = cv2.calcHist([image_1], [0], None, [256], [0, 256])
        second_image_hist = cv2.calcHist([image_2], [0], None, [256], [0, 256])

        img_hist_diff = cv2.compareHist(first_image_hist, second_image_hist, cv2.HISTCMP_BHATTACHARYYA)
        img_template_probability_match = cv2.matchTemplate(first_image_hist, second_image_hist, cv2.TM_CCOEFF_NORMED)[0][0]
        img_template_diff = 1 - img_template_probability_match

        # taking only 10% of histogram diff, since it's less accurate than template method
        commutative_image_diff = (img_hist_diff / 10) + img_template_diff
        return commutative_image_diff


    if __name__ == '__main__':
        compare_image = CompareImage('image1/path', 'image2/path')
        image_difference = compare_image.compare_image()
        print image_difference

私はpythonをよく理解していません。しかし、「commutative_image_diff」タイプとは何ですか?cv.Matまたはdouble。cv.Matの場合は、「commutative_image_diff <self.minimum_commutative_image_diff」と比較して、どのように機能するか、またはこの比較の目的を比較してください。説明してくれませんか?
BulletRain

1

少し外れたトピックですが、Pythonic numpyアプローチが役立ちます。その堅牢で高速ですが、ピクセルを比較するだけで、画像に含まれるオブジェクトやデータは比較しません(同じサイズと形状の画像が必要です)。

openCVやコンピュータービジョン用のライブラリなしでこれを行うための非常にシンプルで高速なアプローチは、

import numpy as np
picture1 = np.random.rand(100,100)
picture2 = np.random.rand(100,100)
picture1_norm = picture1/np.sqrt(np.sum(picture1**2))
picture2_norm = picture2/np.sqrt(np.sum(picture2**2))

両方の標準化された画像(または行列)を定義した後、比較する画像の乗算を合計できます。

1)同様の画像を比較すると、合計は1を返します。

In[1]: np.sum(picture1_norm**2)
Out[1]: 1.0

2)それらが類似していない場合、0と1の間の値(100を掛けるとパーセンテージ)が得られます。

In[2]: np.sum(picture2_norm*picture1_norm)
Out[2]: 0.75389941124629822

あなたがカラー写真を持っているなら、あなたは3次元すべてでこれをしなければならないか、単にグレースケール版を比較しなければならないことに注意してください。膨大な量の写真と任意のコンテンツを比較しなければならないことがよくありますが、これは非常に高速な方法です。


2
こんにちは、私はあなたの手順に従っていますが、正規化部分が適切な結果を得ることができないことがわかりました。最終結果は1.0よりはるかに大きくなります。何か案が?
G_cy
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.