Méthode simple et rapide pour comparer des images pour la similitude

195

J'ai besoin d'un moyen simple et rapide de comparer deux images pour la similitude. Ie Je veux obtenir une valeur élevée s'ils contiennent exactement la même chose mais peuvent avoir un arrière-plan légèrement différent et peuvent être déplacés / redimensionnés de quelques pixels.

(Plus concret, si cela compte: une image est une icône et l'autre image est une sous-zone d'une capture d'écran et je veux savoir si cette sous-zone est exactement l'icône ou non.)

J'ai OpenCV sous la main mais je ne suis toujours pas habitué.

Une possibilité à laquelle j'ai pensé jusqu'à présent: divisez les deux images en 10x10 cellules et pour chacune de ces 100 cellules, comparez l'histogramme des couleurs. Ensuite, je peux définir une valeur de seuil inventée et si la valeur que j'obtiens est supérieure à ce seuil, je suppose qu'elles sont similaires.

Je ne l'ai pas encore essayé à quel point cela fonctionne mais je suppose que ce serait assez bon. Les images sont déjà assez similaires (dans mon cas d'utilisation), je peux donc utiliser une valeur de seuil assez élevée.

Je suppose qu'il existe des dizaines d'autres solutions possibles pour cela qui fonctionneraient plus ou moins (car la tâche elle-même est assez simple car je ne veux détecter les similitudes que si elles sont vraiment très similaires). Que suggérerais-tu?


Il y a quelques questions très liées / similaires sur l'obtention d'une signature / empreinte digitale / hachage à partir d'une image:

Aussi, je suis tombé sur ces implémentations qui ont de telles fonctions pour obtenir une empreinte digitale:

Quelques discussions sur les hachages d'images perceptives: ici


Un peu hors sujet: il existe de nombreuses méthodes pour créer des empreintes digitales audio. MusicBrainz , un service Web qui fournit une recherche basée sur les empreintes digitales pour les chansons, a un bon aperçu dans leur wiki . Ils utilisent maintenant AcoustID . C'est pour trouver des correspondances exactes (ou presque exactes). Pour trouver des correspondances similaires (ou si vous n'avez que des extraits de code ou un bruit élevé), jetez un œil à Echoprint . Une question SO connexe est ici . Il semble donc que cela soit résolu pour l'audio. Toutes ces solutions fonctionnent assez bien.

Une question un peu plus générique sur la recherche floue en général est ici . Par exemple, il existe un hachage sensible à la localité et une recherche du plus proche voisin .

Albert
la source
1
Peut-être que la prise d'empreintes d'images pourrait vous aider? stackoverflow.com/questions/596262/…
GWW
1
La métrique de Wasserstein, également connue sous le nom de distance de déplacement de la terre (EMD), est quelque chose que les gens semblent ne pas savoir, mais donnerait à peu près ce que vous voulez ici.
mmgp
3
duplication possible de la comparaison d'images - algorithme rapide
sashoalm
Salut, j'ai trouvé un dHash amélioré - je l'ai appelé IDHash: github.com/Nakilon/dhash-vips
Nakilon

Réponses:

110

La capture d'écran ou l'icône peut-elle être transformée (mise à l'échelle, rotation, biais ...)? Il y a pas mal de méthodes sur ma tête qui pourraient éventuellement vous aider:

  • Distance euclidienne simple comme mentionné par @carlosdc (ne fonctionne pas avec les images transformées et vous avez besoin d'un seuil).
  • Corrélation croisée (normalisée) - une mesure simple que vous pouvez utiliser pour comparer les zones de l'image. C'est plus robuste que la simple distance euclidienne mais ne fonctionne pas sur les images transformées et vous aurez à nouveau besoin d'un seuil.
  • Comparaison d'histogrammes - si vous utilisez des histogrammes normalisés, cette méthode fonctionne bien et n'est pas affectée par les transformations affines. Le problème est de déterminer le seuil correct. Il est également très sensible aux changements de couleur (luminosité, contraste, etc.). Vous pouvez le combiner avec les deux précédents.
  • Détecteurs de points / zones saillants - tels que MSER (Maximally Stable Extremal Regions) , SURF ou SIFT . Ce sont des algorithmes très robustes et ils pourraient être trop compliqués pour votre tâche simple. La bonne chose est que vous n'avez pas besoin d'avoir une zone exacte avec une seule icône, ces détecteurs sont suffisamment puissants pour trouver la bonne correspondance. Une bonne évaluation de ces méthodes se trouve dans cet article: Détecteurs de caractéristiques invariantes locales: une enquête .

La plupart d'entre eux sont déjà implémentés dans OpenCV - voir par exemple la méthode cvMatchTemplate (utilise la correspondance d'histogramme): http://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html . Les détecteurs de points / zones saillants sont également disponibles - voir Détection des fonctionnalités OpenCV .

Karel Petranek
la source
1
Il peut être mis à l'échelle ou légèrement déplacé. L'arrière-plan de l'icône sera également différent. J'ai essayé la comparaison d'histogrammes mais j'ai eu beaucoup de faux positifs. J'ai également essayé la distance euclidienne, mais cela donne aussi trop de faux positifs (mais je peux peut-être améliorer un peu la gestion de la valeur alpha dans l'icône). Je vais essayer un peu plus loin, sinon je vérifierai MSER, SURF ou SIFT.
Albert
1
Une autre idée - cela ne fonctionnerait-il pas si vous utilisiez une comparaison d'histogramme des images après avoir appliqué un opérateur Sobel? Cela ne ferait que comparer la similitude des bords. Cela peut ou non fonctionner, selon le degré de «nervosité» de l'arrière-plan.
Karel Petranek
46

Je suis confronté aux mêmes problèmes récemment, pour résoudre ce problème (algorithme simple et rapide pour comparer deux images) une fois pour toutes, je contribue un module img_hash à opencv_contrib, vous pouvez trouver les détails sur ce lien .

Le module img_hash fournit six algorithmes de hachage d'image, assez faciles à utiliser.

Exemple de codes

origine lenaorigine lena

flou lenaflou lena

redimensionner lenaredimensionner lena

shift lenashift lena

#include <opencv2/core.hpp>
#include <opencv2/core/ocl.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/img_hash.hpp>
#include <opencv2/imgproc.hpp>

#include <iostream>

void compute(cv::Ptr<cv::img_hash::ImgHashBase> algo)
{
    auto input = cv::imread("lena.png");
    cv::Mat similar_img;

    //detect similiar image after blur attack
    cv::GaussianBlur(input, similar_img, {7,7}, 2, 2);
    cv::imwrite("lena_blur.png", similar_img);
    cv::Mat hash_input, hash_similar;
    algo->compute(input, hash_input);
    algo->compute(similar_img, hash_similar);
    std::cout<<"gaussian blur attack : "<<
               algo->compare(hash_input, hash_similar)<<std::endl;

    //detect similar image after shift attack
    similar_img.setTo(0);
    input(cv::Rect(0,10, input.cols,input.rows-10)).
            copyTo(similar_img(cv::Rect(0,0,input.cols,input.rows-10)));
    cv::imwrite("lena_shift.png", similar_img);
    algo->compute(similar_img, hash_similar);
    std::cout<<"shift attack : "<<
               algo->compare(hash_input, hash_similar)<<std::endl;

    //detect similar image after resize
    cv::resize(input, similar_img, {120, 40});
    cv::imwrite("lena_resize.png", similar_img);
    algo->compute(similar_img, hash_similar);
    std::cout<<"resize attack : "<<
               algo->compare(hash_input, hash_similar)<<std::endl;
}

int main()
{
    using namespace cv::img_hash;

    //disable opencl acceleration may(or may not) boost up speed of img_hash
    cv::ocl::setUseOpenCL(false);

    //if the value after compare <= 8, that means the images
    //very similar to each other
    compute(ColorMomentHash::create());

    //there are other algorithms you can try out
    //every algorithms have their pros and cons
    compute(AverageHash::create());
    compute(PHash::create());
    compute(MarrHildrethHash::create());
    compute(RadialVarianceHash::create());
    //BlockMeanHash support mode 0 and mode 1, they associate to
    //mode 1 and mode 2 of PHash library
    compute(BlockMeanHash::create(0));
    compute(BlockMeanHash::create(1));
}

Dans ce cas, ColorMomentHash nous donne le meilleur résultat

  • attaque de flou gaussien: 0,567521
  • attaque par décalage: 0,229728
  • attaque de redimensionnement: 0,229358

Avantages et inconvénients de chaque algorithme

Performances sous différentes attaques

Les performances de img_hash sont bonnes aussi

Comparaison de vitesse avec la bibliothèque PHash (100 images d'ukbench) calculer les performances performances de comparaison

Si vous souhaitez connaître les seuils recommandés pour ces algorithmes, veuillez consulter cet article ( http://qtandopencv.blogspot.my/2016/06/introduction-to-image-hash-module-of.html ). Si vous souhaitez savoir comment mesurer les performances des modules img_hash (y compris la vitesse et les différentes attaques), veuillez consulter ce lien ( http://qtandopencv.blogspot.my/2016/06/speed-up-image-hashing-of -opencvimghash.html ).

StereoMatching
la source
11

La capture d'écran contient-elle uniquement l'icône? Si tel est le cas, la distance L2 des deux images peut suffire. Si la distance L2 ne fonctionne pas, la prochaine étape est d'essayer quelque chose de simple et bien établi, comme: Lucas-Kanade . Ce qui, j'en suis sûr, est disponible dans OpenCV.

carlosdc
la source
La sous-zone contient exactement uniquement l'icône (avec un arrière-plan aléatoire) ou quelque chose de différent. Je veux voir de quel cas il s'agit. Cependant, il peut être très légèrement décalé ou redimensionné, c'est pourquoi je n'étais pas sûr de pouvoir simplement regarder la distance (quelle que soit la norme). Mais je vais essayer avec une version réduite.
Albert
6

Si vous souhaitez obtenir un index sur la similitude des deux images, je vous suggère à partir des métriques l'index SSIM. C'est plus cohérent avec l'œil humain. Voici un article à ce sujet: Indice de similarité structurelle

Il est également implémenté dans OpenCV et peut être accéléré avec GPU: OpenCV SSIM avec GPU

Milan Tenk
la source
5

Si vous pouvez être sûr d'avoir un alignement précis de votre modèle (l'icône) sur la région de test, alors toute ancienne somme de différences de pixels fonctionnera.

Si l'alignement ne sera qu'un tout petit peu décalé, vous pouvez passer les deux images par le bas avec cv :: GaussianBlur avant de trouver la somme des différences de pixels.

Si la qualité de l'alignement est potentiellement mauvaise, je recommanderais soit un histogramme des dégradés orientés, soit l'un des algorithmes pratiques de détection / descripteur de points clés d'OpenCV (tels que SIFT ou SURF ).

rcv
la source
4

Si pour faire correspondre des images identiques - code pour la distance L2

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

Vite. Mais pas robuste aux changements d'éclairage / de point de vue, etc. Source

Kiran
la source
2

Si vous souhaitez comparer l'image pour la similitude, je vous suggère d'utiliser OpenCV. Dans OpenCV, il y a peu de correspondance de fonctionnalités et de correspondance de modèles. Pour la correspondance des fonctionnalités, il existe des détecteurs SURF, SIFT, FAST, etc. Vous pouvez l'utiliser pour détecter, décrire et faire correspondre l'image. Après cela, vous pouvez utiliser l'index spécifique pour trouver le nombre de correspondance entre les deux images.

Hua Er Lim
la source
1
vous avez dit "Après cela, vous pouvez utiliser l'index spécifique pour trouver le nombre de correspondance entre les deux images." quel peut être le nombre minimum de correspondances entre les deux images pour dire qu'elles "contiennent" le même objet?
Inês Martins