Comment puis-je évaluer la similitude de deux images avec OpenCV?

141

OpenCV prend-il en charge la comparaison de deux images, renvoyant une valeur (peut-être un pourcentage) qui indique à quel point ces images sont similaires? Par exemple, 100% serait retourné si la même image était transmise deux fois, 0% serait retourné si les images étaient totalement différentes.

J'ai déjà lu beaucoup de sujets similaires ici sur StackOverflow. J'ai aussi fait pas mal de googles. Malheureusement, je n'ai pas pu trouver de réponse satisfaisante.

Boris
la source
Voir également les réponses sur stackoverflow.com/questions/4196453/…
B. Go

Réponses:

208

C'est un sujet énorme, avec des réponses de 3 lignes de code à des magazines de recherche entiers.

Je décrirai les techniques les plus courantes et leurs résultats.

Comparaison d'histogrammes

Une des méthodes les plus simples et les plus rapides. Proposé il y a des décennies comme un moyen de trouver des similitudes d'image. L'idée est qu'une forêt aura beaucoup de vert et un visage humain beaucoup de rose, ou autre. Donc, si vous comparez deux images avec des forêts, vous obtiendrez une certaine similitude entre les histogrammes, car vous avez beaucoup de vert dans les deux.

Inconvénient: c'est trop simpliste. Une banane et une plage se ressembleront, car les deux sont jaunes.

Méthode OpenCV: compareHist ()

Correspondance de modèle

Un bon exemple ici matchTemplate trouvant une bonne correspondance . Il convolve l'image de recherche avec celle dans laquelle la recherche est effectuée. Il est généralement utilisé pour trouver des parties d'image plus petites dans une plus grande.

Inconvénients: il ne renvoie que de bons résultats avec des images identiques, même taille et même orientation.

Méthode OpenCV: matchTemplate ()

Correspondance des fonctionnalités

Considéré comme l'un des moyens les plus efficaces de rechercher des images. Un certain nombre de caractéristiques sont extraites d'une image, de manière à garantir que les mêmes caractéristiques seront reconnues à nouveau même lorsqu'elles sont tournées, mises à l'échelle ou inclinées. Les caractéristiques extraites de cette manière peuvent être comparées à d'autres ensembles de caractéristiques d'image. Une autre image qui présente une proportion élevée d'éléments correspondant à la première est considérée comme représentant la même scène.

Trouver l'homographie entre les deux ensembles de points vous permettra également de trouver la différence relative d'angle de prise de vue entre les images originales ou la quantité de chevauchement.

Il existe un certain nombre de tutoriels / exemples OpenCV à ce sujet, et une belle vidéo ici . Tout un module OpenCV (features2d) lui est dédié.

Inconvénients: cela peut être lent. Ce n'est pas parfait.


Sur le site OpenCV Q&A , je parle de la différence entre les descripteurs de caractéristiques, qui sont excellents pour comparer des images entières et des descripteurs de texture, qui sont utilisés pour identifier des objets comme des visages humains ou des voitures dans une image.

Sam
la source
pour comparer des images similaires qui n'ont que quelques images distinctes (par exemple, un nouvel objet déplacé dans la même vue), vous pouvez également travailler avec absdiff codota.com/code/java/methods/org.opencv.core.Core/absdiff Seuil du résultat produit un masque qui vous permet de mettre en évidence les régions qui ont changé d'une scène à l'autre.
Max F.
34

Si pour faire correspondre des images identiques (même taille / orientation)

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

La source

Kiran
la source
12

La solution de Sam devrait être suffisante. J'ai utilisé une combinaison de différence d'histogramme et de correspondance de modèles, car aucune méthode ne fonctionnait pour moi à 100%. J'ai cependant accordé moins d'importance à la méthode de l'histogramme. Voici comment j'ai implémenté dans un simple script 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
Priyanshu Chauhan
la source
Je ne comprends pas bien python. Mais quel est le type «commutative_image_diff»? cv.Mat ou double. Si c'est cv.Mat, comparez 'commutative_image_diff <self.minimum_commutative_image_diff' comment ça marche ou quel est le but de cette comparaison. Pouvez-vous m'expliquer?
BulletRain
1

L' numpyapproche pythonique est un peu hors sujet mais utile . C'est robuste et rapide, mais il ne fait que comparer les pixels et non les objets ou les données que l'image contient (et il nécessite des images de même taille et forme):

Une approche très simple et rapide pour ce faire sans openCV et sans aucune bibliothèque pour la vision par ordinateur consiste à normaliser les tableaux d'images par

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

Après avoir défini les deux images normées (ou matrices), vous pouvez simplement additionner la multiplication des images que vous souhaitez comparer:

1) Si vous comparez des images similaires, la somme retournera 1:

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

2) S'ils ne sont pas similaires, vous obtiendrez une valeur comprise entre 0 et 1 (un pourcentage si vous multipliez par 100):

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

Veuillez noter que si vous avez des images colorées, vous devez le faire dans les 3 dimensions ou simplement comparer une version en échelle de gris. Je dois souvent comparer d'énormes quantités d'images avec un contenu arbitraire et c'est un moyen très rapide de le faire.

Franz
la source
2
salut, je viens de suivre votre étape mais j'ai trouvé que la partie normalisation ne pouvait pas obtenir un résultat correct. Le résultat final est bien supérieur à 1,0. Une idée?
G_cy