Vérification de la similitude des images avec OpenCV

OpenCV supporte-t-il la comparaison de deux images, retournant une certaine valeur (peut-être un pourcentage) qui indique à quel point ces images sont similaires? Par exemple: 100% seraient retournés si la même image était passée deux fois, 0% seraient retournés si les images étaient totalement différentes.

j'ai déjà lu beaucoup de sujets similaires ici sur StackOverflow. J'ai fait aussi tout à fait quelques recherches sur Google. Malheureusement je ne pouvais pas venir avec un satisfieng réponse.

112
demandé sur Peter O. 2012-07-18 16:15:50

4 réponses

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

j'exposerai les techniques les plus courantes et leurs résultats.

comparaison des 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 peu importe. Donc, si vous comparez deux photos avec les forêts, vous obtiendrez un peu de similitude entre les histogrammes, parce que vous avez beaucoup de vert dans les deux.

inconvénient: c'est trop simpliste. Une banane et une plage seront identiques, car les deux sont jaunes.

méthode OpenCV: compareHist ()

template matching

Un bon exemple matchTemplate trouver un bon match . Il effectue la convolution des rechercher l'image avec celui qui est recherché. Il est généralement utilisé pour trouver de plus petites parties d'image dans un plus grand.

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

Méthode OpenCV: matchTemplate ()

correspondance des caractéristiques

considéré comme l'un des moyens les plus efficaces pour faire la recherche d'image. Un certain nombre de caractéristiques sont extraites d'un l'image, d'une manière qui garantit les mêmes fonctionnalités seront à nouveau reconnue même qu'il est en rotation/échelle/asymétrique. Les fonctionnalités extraites de cette façon peuvent être comparées à d'autres ensembles de fonctionnalités d'image. Une autre image qui a une forte proportion des traits dans la première est très probablement représentant le même objet/scène. Il peut être utilisé pour trouver la différence relative dans l'angle de tir entre les pics, ou la quantité de chevauchement.

Il ya un certain nombre D'OpenCV tutoriels/samples sur ce, et une belle vidéo ici . Un module OpenCV complet (features2d) lui est dédié.

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

164
répondu Sam 2017-05-23 12:02:42

si pour 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
}

Source

27
répondu Kiran 2014-04-04 08:11:56

la solution de Sam devrait être suffisante. J'ai utilisé la combinaison de la différence d'histogramme et de la correspondance de gabarit parce que pas une méthode ne fonctionnait pour moi 100% des fois. J'ai donné 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
2
répondu Priyanshu Chauhan 2017-08-03 13:44:45

un peu hors sujet mais utile est l'approche pythonique numpy . Son robuste et rapide, mais ne compare pas les pixels et pas les objets ou les données que l'image Contient (et il nécessite des images de même taille et la forme):

une approche très simple et rapide pour faire cela sans openCV et n'importe quelle bibliothèque pour la vision d'ordinateur est de normaliser les tableaux d'image 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 (ou matrices) vous pouvez simplement additionner sur la multiplication des images que vous aimez 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 entre 0 et 1 (un pourcentage si vous multipliez par 100):

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

s'il vous plaît noter que si vous avez des images colorées, vous devez le faire dans les 3 dimensions ou tout simplement comparer une version avec un gris. Je dois souvent comparer des quantités énormes de photos contenu arbitraire et c'est vraiment un moyen rapide de le faire.

0
répondu Franz 2017-06-09 13:44:43