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 .
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:
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 .
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
#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
Avantages et inconvénients de chaque algorithme
La performance de img_hash est bonne aussi
Comparaison de la vitesse avec la bibliothèque PHash (100 images de ukbench)
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 ).
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.
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
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 ).
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
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.