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

j'ai besoin d'un moyen simple et rapide pour comparer deux images pour la similitude. C'est-à-dire: Je veux obtenir une valeur élevée si elles contiennent exactement la même chose mais peuvent avoir un arrière-plan légèrement différent et peuvent être déplacées / redimensionnées par quelques pixels.

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

j'ai OpenCV à portée de main mais je ne suis pas encore habitué.

une possibilité à laquelle j'ai pensé jusqu'à présent: diviser les deux images en cellules 10x10 et pour chacune de ces 100 cellules, comparer l'histogramme de couleur. Ensuite, je peux définir une valeur de seuil reconstituée et si la valeur que j'obtiens est au-dessus de ce seuil, je suppose qu'ils sont similaires.

Je n'ai pas encore essayé à quel point cela fonctionne mais je pense que ce serait suffisant. Les images sont déjà assez similaire (dans mon cas d'utilisation), donc je peux utiliser un seuil assez élevé.

je suppose qu'il y a des douzaines d'autres solutions possibles pour cela qui fonctionneraient plus ou moins (comme la tâche elle-même est très simple car je ne veux détecter la similitude que si elles sont vraiment très similaires). Que suggérez-vous?


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

  • OpenCV / SURF Comment générer un hash de l'image / empreinte / signature de l'descripteurs?
  • de l'Image d'empreinte digitale afin de comparer la similarité de nombreuses images
  • Quasi-Copie De L'Image De "Détection De 1519210920"
  • OpenCV: Image des Empreintes digitales et de les Comparer à l'Encontre de la Base de données .
  • plus , plus , plus , plus , plus , plus , plus

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

  • pHash
  • imgSeek ( dépôt GitHub ) (GPL) sur la base du document Fast Multirésolution de l'Image de l'Interrogation
  • image-match . Très similaire à ce que je cherchais. Similaire à pHash, basé sur une signature d'image pour tout type d'image, Goldberg et al . Utilise Python et Elasticsearch.
  • iqdb
  • ImageHash . supporte la pHash.

Certaines discussions au sujet de perception de l'image de hachages: ici


un peu offtopique: il existe de nombreuses méthodes pour créer des empreintes 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 sont à l'aide de AcoustID now. Il s'agit de trouver des Correspondances exactes (ou plutôt exactes). Pour trouver des correspondances similaires (ou si vous n'avez que quelques bribes ou un bruit élevé), jetez un oeil à Echoprint . Une question connexe est ici . On dirait que c'est résolu pour l'audio. Toutes ces solutions fonctionnent très bien.

une question un peu plus générale au sujet de la recherche floue en général est ici . E. g. il y a " localité-sensible hachage et "recherche du plus proche voisin .

165
demandé sur Albert 2010-11-16 19:31:37

7 réponses

peut-on transformer la capture d'écran ou l'icône (échelle, rotation, asymétrie)...)? Il y a plusieurs méthodes au sommet de ma tête qui pourraient vous aider:

  • simple distance euclidienne comme mentionné par @carlosdc (ne fonctionne pas avec des images transformées et vous avez besoin d'un seuil).
  • ( - une métrique simple que vous pouvez utiliser pour comparaison des zones d'image. Il est plus robuste que la simple distance euclidienne mais ne fonctionne pas sur les images transformées et vous aurez encore 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 affine. Le problème est de déterminer le bon seuil. Il est également très sensible aux changements de couleur (luminosité, contraste, etc.). Vous pouvez les 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 simple tâche. Une bonne chose est que vous ne devez pas avoir une zone exacte avec une seule icône, ces détecteurs sont assez puissants pour trouver la bonne correspondance. Une belle évaluation de ces méthodes est dans cet article: détecteurs de caractéristiques locales invariantes: une enquête .

la plupart de ceux - ci sont déjà mis en œuvre dans OpenCV-voir par exemple la méthode cvMatchTemplate (utilise l'appariement des histogrammes): http://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html . Les détecteurs de point de saillance / zone sont également disponibles - voir OpenCV Feature Detection .

93
répondu Karel Petranek 2010-11-17 09:59:36

je fais face 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 de ce lien .

Le module

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

Codes exemple

origin lena origine lena

blur lena flou lena

resize lena redimensionner lena

shift lena poste 151960920"

#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 donner le meilleur résultat

  • flou gaussien attaque : 0.567521
  • shift attaque : 0.229728
  • redimensionner l'attaque: 0.229358

pour et contre de chaque algorithme

Performance under different attacks

la performance de img_hash est bonne aussi

comparaison de la vitesse avec la bibliothèque PHash (100 images de ukbench) compute performance comparison performance

si vous voulez connaître les seuils recommandés pour ces algorithmes, s'il vous plaît vérifier ce post ( http://qtandopencv.blogspot.my/2016/06/introduction-to-image-hash-module-of.html ). Si vous êtes intéressant sur la façon dont je mesure la performance des modules img_hash (inclure la vitesse et les différentes attaques), s'il vous plaît vérifier ce lien ( http://qtandopencv.blogspot.my/2016/06/speed-up-image-hashing-of-opencvimghash.html ).

33
répondu StereoMatching 2017-06-27 14:25:25

la capture d'écran ne contient-elle que l'icône? Si c'est le cas, la distance L2 des deux images pourrait suffire. Si la distance L2 ne fonctionne pas, l'étape suivante est d'essayer quelque chose de simple et bien établi, comme: Lucas-Kanade . Qui je suis sûr est disponible en OpenCV.

8
répondu carlosdc 2010-11-16 23:19:06

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 va être qu'un tout petit peu désactivé, alors vous pouvez passer bas les deux images avec cv::GaussianBlur avant de trouver la somme des différences de pixels.

Si la qualité de l'alignement est potentiellement mauvaise alors je vous recommande soit un Histogramme de Gradients orientés ou de l'un des algorithmes de détection/descripteur de point de saisie d'OpenCV (tels que SIFT ou SURF ).

4
répondu rcv 2010-11-17 23:28:02

si vous voulez obtenir un indice sur la similarité des deux images, je vous suggère de la métrique l'indice SSIM. Il est plus cohérent avec l'œil humain. Voici un article à ce sujet: indice de similarité structurelle

il est mis en œuvre dans OpenCV aussi, et il peut être accéléré avec GPU: OpenCV SSIM avec GPU

4
répondu ramez 2013-09-12 16:49:00

Si pour l'appariement des images identiques - code pour les L2 de distance

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

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

3
répondu Kiran 2014-04-04 08:28:09

si vous voulez comparer l'image pour la similitude,je vous suggère D'utiliser OpenCV. Dans OpenCV, il y a peu d'appariement des fonctionnalités et des modèles. Pour l'appariement des caractéristiques, il y a SURF, SIFT, FAST et ainsi de suite. Vous pouvez l'utiliser pour détecter, décrire et ensuite en fonction de l'image. Après cela, vous pouvez utiliser l'index spécifique pour trouver le nombre de correspondance entre les deux images.

2
répondu Hua Er Lim 2013-01-19 05:17:24