Wie kann ich beurteilen, wie ähnlich zwei Bilder mit OpenCV sind?

140

Unterstützt OpenCV den Vergleich zweier Bilder und gibt einen Wert (möglicherweise einen Prozentsatz) zurück, der angibt, wie ähnlich diese Bilder sind? ZB würden 100% zurückgegeben, wenn dasselbe Bild zweimal übergeben würde, 0% würden zurückgegeben, wenn die Bilder völlig unterschiedlich wären.

Ich habe hier auf StackOverflow bereits viele ähnliche Themen gelesen. Ich habe auch ziemlich viel gegoogelt. Leider konnte ich keine zufriedenstellende Antwort finden.

Boris
quelle
Siehe auch Antworten unter stackoverflow.com/questions/4196453/…
B. Go

Antworten:

208

Dies ist ein riesiges Thema mit Antworten aus 3 Codezeilen auf ganze Forschungsmagazine.

Ich werde die gebräuchlichsten derartigen Techniken und ihre Ergebnisse skizzieren.

Histogramme vergleichen

Eine der einfachsten und schnellsten Methoden. Vor Jahrzehnten vorgeschlagen, um Bildähnlichkeiten zu finden. Die Idee ist, dass ein Wald viel Grün und ein menschliches Gesicht viel Rosa oder was auch immer haben wird. Wenn Sie also zwei Bilder mit Wäldern vergleichen, werden Sie einige Ähnlichkeiten zwischen Histogrammen feststellen, da Sie in beiden viel Grün haben.

Nachteil: Es ist zu simpel. Eine Banane und ein Strand sehen gleich aus, da beide gelb sind.

OpenCV-Methode: compareHist ()

Vorlagenübereinstimmung

Ein gutes Beispiel hier matchTemplate, um eine gute Übereinstimmung zu finden . Es faltet das Suchbild mit dem, in dem gesucht wird. Es wird normalerweise verwendet, um kleinere Bildteile in einem größeren zu finden.

Nachteile: Es werden nur gute Ergebnisse mit identischen Bildern, gleicher Größe und Ausrichtung erzielt.

OpenCV-Methode: matchTemplate ()

Feature Matching

Wird als eine der effizientesten Methoden zur Bildsuche angesehen. Eine Reihe von Merkmalen wird aus einem Bild so extrahiert, dass garantiert wird, dass dieselben Merkmale auch dann wieder erkannt werden, wenn sie gedreht, skaliert oder verzerrt werden. Die auf diese Weise extrahierten Features können mit anderen Bildfeaturesätzen verglichen werden. Bei einem anderen Bild, bei dem ein hoher Anteil der Merkmale mit dem ersten übereinstimmt, wird dieselbe Szene dargestellt.

Wenn Sie die Homografie zwischen den beiden Punktsätzen finden, können Sie auch den relativen Unterschied im Aufnahmewinkel zwischen den Originalbildern oder den Überlappungsgrad ermitteln.

Es gibt eine Reihe von OpenCV-Tutorials / Beispielen dazu und ein schönes Video hier . Ein ganzes OpenCV-Modul (features2d) ist ihm gewidmet.

Nachteile: Es kann langsam sein. Es ist nicht perfekt.


Drüben auf der OpenCV-Q & A- Site spreche ich über den Unterschied zwischen Feature-Deskriptoren, die beim Vergleich ganzer Bilder großartig sind, und Textur-Deskriptoren, mit denen Objekte wie menschliche Gesichter oder Autos in einem Bild identifiziert werden.

Sam
quelle
Ähnliche Bilder zu vergleichen , dass nur wenige unterschiedliche Bilder (zB ein neues Objekt in die ansonsten gleiche Ansicht bewegt) können Sie auch die Arbeit mit absdiff codota.com/code/java/methods/org.opencv.core.Core/absdiff Thresholding das Ergebnis Erstellt eine Maske, mit der Sie die Bereiche hervorheben können, die sich von Szene zu Szene geändert haben.
Max F.
34

Wenn zum Abgleichen identischer Bilder (gleiche Größe / Ausrichtung)

// 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
}

Quelle

Kiran
quelle
12

Sams Lösung sollte ausreichen. Ich habe eine Kombination aus Histogrammdifferenz und Vorlagenabgleich verwendet, da in 100% der Fälle nicht eine Methode für mich funktioniert hat. Ich habe der Histogrammmethode jedoch weniger Bedeutung beigemessen. Hier ist, wie ich in einem einfachen Python-Skript implementiert habe.

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
Priyanshu Chauhan
quelle
Ich verstehe Python nicht gut. Aber was ist der Typ 'commutative_image_diff'? cv.Mat oder double. Wenn es sich um cv.Mat handelt, vergleichen Sie 'commutative_image_diff <self.minimum_commutative_image_diff', wie es funktioniert oder welchen Zweck dieser Vergleich hat. Kannst du es mir erklären?
BulletRain
1

Ein wenig abseits des Themas, aber nützlich ist der pythonische numpyAnsatz. Es ist robust und schnell, vergleicht jedoch nur Pixel und nicht die Objekte oder Daten, die das Bild enthält (und es erfordert Bilder gleicher Größe und Form):

Ein sehr einfacher und schneller Ansatz, um dies ohne openCV und jede Bibliothek für Computer Vision zu tun, besteht darin, die Bildarrays nach zu normieren

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))

Nachdem Sie beide normierten Bilder (oder Matrizen) definiert haben, können Sie einfach die Multiplikation der Bilder summieren, die Sie vergleichen möchten:

1) Wenn Sie ähnliche Bilder vergleichen, ergibt die Summe 1:

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

2) Wenn sie nicht ähnlich sind, erhalten Sie einen Wert zwischen 0 und 1 (ein Prozentsatz, wenn Sie mit 100 multiplizieren):

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

Bitte beachten Sie, dass Sie bei farbigen Bildern dies in allen drei Dimensionen tun oder einfach eine Graustufenversion vergleichen müssen. Ich muss oft große Mengen von Bildern mit beliebigen Inhalten vergleichen, und das ist ein sehr schneller Weg.

Franz
quelle
2
Hallo, ich folge nur deinem Schritt, aber ich habe festgestellt, dass der Normalisierungsteil kein korrektes Ergebnis erzielen kann. Das Endergebnis ist viel größer als 1,0. Irgendeine Idee?
G_cy