web-dev-qa-db-fra.com

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

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

(Plus concret, si cela compte: l'une des images est une icône et l'autre 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é à cela.

Une possibilité à laquelle je pensais jusqu'à présent: divisez les deux images en cellules 10x10 et comparez l'histogramme de couleur pour chacune de ces 100 cellules. Ensuite, je peux définir une valeur de seuil composée et si la valeur obtenue est supérieure à ce seuil, je suppose qu’elles sont similaires.

Je ne l’ai pas encore essayé, mais j’imagine que ce serait suffisant. Les images sont déjà très similaires (dans mon cas d'utilisation), je peux donc utiliser une valeur de seuil assez élevée.

J'imagine qu'il existe des dizaines d'autres solutions possibles pour résoudre ce problème qui fonctionneraient plus ou moins bien (car la tâche en elle-même est assez simple, car je souhaite uniquement détecter une similitude si elles le sont vraiment). 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 perceptuelles: ici


Un peu offtopic: Il existe de nombreuses méthodes pour créer des empreintes audio. MusicBrainz , un service web fournissant une recherche par empreinte digitale des chansons, possède un bonne vue d'ensemble dans son wiki . Ils utilisent AcoustID maintenant. C'est pour trouver des correspondances exactes (ou la plupart du temps exactes). Pour trouver des correspondances similaires (ou si vous ne disposez que de quelques extraits ou d'un bruit élevé), consultez Echoprint . Une question connexe SO 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 y a hachage sensible à la localité et recherche du plus proche voisin .

181
Albert

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

  • Simple distance euclidienne comme mentionné par @carlosdc (ne fonctionne pas avec des images transformées et vous avez besoin d'un seuil).
  • Corrélation croisée (normalisée) - une métrique simple que vous pouvez utiliser pour comparer 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 à 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 consiste à 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 (régions extrêmes stables maximales) , SURF ou TAMIS . Ce sont des algorithmes très robustes et ils pourraient être trop compliqués pour votre tâche simple. La bonne chose à faire est qu’il n’est pas nécessaire d’avoir une zone exacte avec une seule icône, ces détecteurs sont assez puissants pour trouver la bonne correspondance. Cet article présente une bonne évaluation de ces méthodes: Détecteurs à 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 de caractéristiques OpenCV .

101
Karel Petranek

Je fais face aux mêmes problèmes récemment, pour résoudre ce problème (algorithme simple et rapide permettant de 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, très faciles à utiliser.

Exemple de codes

Origin lena Origine lena

blur lena flou lena

resize lena redimensionner lena

shift lena shift 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 par flou gaussien: 0.567521
  • attaque de décalage: 0.229728
  • attaque de redimensionnement: 0.229358

Avantages et inconvénients 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 performancecomparison performance

Si vous souhaitez connaître les seuils recommandés pour ces algorithmes, veuillez vérifier ce post ( 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 (notamment la vitesse et les différentes attaques), veuillez consulter ce lien ( http://qtandopencv.blogspot.my/2016/06/speed-up-image -hachage-de-opencvimghash.html ).

37
StereoMatching

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, l'étape suivante consiste à essayer quelque chose de simple et bien établi, tel que: Lucas-Kanade . Ce qui, je suis sûr, est disponible dans OpenCV.

10
carlosdc

Si vous souhaitez obtenir un index sur la similarité des deux images, je vous suggère d'utiliser les mesures de l'index SSIM. C'est plus compatible avec l'oeil 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 GP

5
ramez

Si vous êtes sûr d’avoir un alignement précis de votre modèle (l’icône) sur la région d’essai, toute somme d’anciennes différences de pixels fonctionnera.

Si l'alignement doit être légèrement réduit, vous pouvez ignorer les deux images avec cv :: GaussianBlur avant de trouver la somme des différences de pixels.

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

4
rcv

Pour des images identiques identiques - code pour 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/point de vue, etc. Source

3
Kiran

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

2
Hua Er Lim