Pour un petit projet, j'ai besoin de comparer une image avec une autre - pour déterminer si les images sont approximativement les mêmes ou non. Les images sont de petite taille, variant de 25 à 100 pixels de diamètre. Les images sont censées être des mêmes données d'image mais sont très différentes, donc une simple vérification de l'égalité des pixels ne fonctionnera pas. Considérez ces deux scénarios possibles:
J'ai décidé de représenter chaque image à l'aide d'histogrammes, en utilisant trois histogrammes 1D: un pour chaque canal RVB - il est sûr pour moi d'utiliser simplement la couleur et d'ignorer la texture et les histogrammes de bord (une approche alternative utilise un seul histogramme 3D pour chaque image, mais j'évite cela car cela ajoute une complexité supplémentaire). Par conséquent, je devrai comparer les histogrammes pour voir à quel point ils sont similaires, et si la mesure de similitude dépasse une certaine valeur seuil, je peux dire avec confiance que les images respectives sont visuellement les mêmes - je comparerais les histogrammes de canaux correspondants de chaque image (par exemple, l'image L'histogramme rouge de 1 avec l'histogramme rouge de l'image 2, puis l'histogramme bleu de l'image 1 avec l'histogramme bleu de l'image 2, puis les histogrammes verts - donc je ne compare pas l'histogramme rouge de l'image 1 avec l'histogramme bleu de l'image 2, ce serait tout simplement idiot).
Disons que j'ai ces trois histogrammes, qui représentent un résumé du canal RVB rouge pour trois images (en utilisant 5 cases pour des images à 7 pixels pour plus de simplicité):
H1 H2 H3
X X X
X X X X X
X X X X X X X X X X X X X
0 1 2 3 4 0 1 2 3 4 0 1 2 3 4
H1 = [ 1, 3, 0, 2, 1 ]
H2 = [ 3, 1, 0, 1, 2 ]
H3 = [ 1, 1, 1, 1, 3 ]
Image 1 (H1
) est mon image de référence, et je veux voir si l'image 2 (H2
) et/ou Image 3 (H3
) est similaire à l'Image 1. Notez que dans cet exemple, l'Image 2 est similaire à l'Image 1, mais l'Image 3 ne l'est pas.
Lorsque j'ai fait une recherche rapide d'algorithmes de "différence d'histogramme" (du moins ceux que je pouvais comprendre), j'ai trouvé qu'une approche populaire consistait à résumer simplement les différences entre chaque bin, mais cette approche échoue souvent car elle pèse toutes les différences de bin de la même manière.
Pour illustrer le problème avec cette approche, en code C #, comme ceci:
Int32[] image1RedHistogram = new Int32[] { 1, 3, 0, 2, 1 };
Int32[] image2RedHistogram = new Int32[] { 3, 2, 0, 1, 2 };
Int32[] image3RedHistogram = new Int32[] { 1, 1, 1, 1, 3 };
Int32 GetDifference(Int32[] x, Int32[] y) {
Int32 sumOfDifference = 0;
for( int i = 0; i < x.Length; i++ ) {
sumOfDifference += Math.Abs( x[i] - y[i] );
}
return sumOfDifferences;
}
Dont la sortie est:
GetDifference( image1RedHistogram, image2RedHistogram ) == 6
GetDifference( image1RedHistogram, image3RedHistogram ) == 6
Ceci est une erreur.
Existe-t-il un moyen de déterminer la différence entre deux histogrammes en tenant compte de la forme de la distribution?
La comparaison d'histogrammes est un sujet en soi.
Vous disposez de deux grandes classes de fonctions de comparaison: la comparaison bin-to-bin et la comparaison inter-bin.
H1.red[0] = 0.001 and H2.red[0] = 0.011
Est beaucoup plus important que si H1.red[0] = 0.1 and H2.red[0] = 0.11
, même si dans les deux cas |H1.red[0] - H2.red[0]| = 0.01
.M(i,j)
est la similitude entre les bacs i et j. Supposons que bin[i]
Est rouge. Si bin[j]
Est rouge foncé, alors M(i,j)
est grand. Si bin[j]
Est vert, M(i,j)
est petit. Ensuite, la distance entre les histogrammes H1 et H2 serait sqrt((H1-H2)*M*(H1-H2))
. Cette méthode prend en compte ce que vous avez dit sur les bacs "fermés"! La distance de déplacement de la Terre (EMD) est un autre type de distance entre bacs.Pour finir, j'ai trois points:
M = P'*D*P
Où P'
Est la transposition de P
, alors sqrt((H1-H2)'*M*(H1-H2)) = sqrt((H1-H2)'*P'*D*P*(H1-H2)) = sqrt((P(H1-H2))'*D*(P(H1-H2)))
. Selon la simplicité de calcul de P(H1-H2)
, cela peut vous faire gagner du temps de calcul. Intuitivement, si H1
Est votre histogramme d'origine, P*H1
Est une affectation souple et que vous utilisez la matrice de similitude implicite M = P'*Id*P
Je suis surpris que personne n'ait mentionné l'implémentation opencv de la comparaison d'histogramme et puisse facilement gérer des images multicanaux (niveaux de gris, rgb, rgba, etc.) de différents formats (uchar, float, double, etc.)
Comprend la distance Bhattacharyya, le chi carré, les méthodes de corrélation et d'intersection. Vous pouvez trouver le
compareHist(InputArray H1, InputArray H2, int method)
fonction dans le manuel ici .
Earth Mover's Distance (EMD) est souvent utilisé pour ce type de comparaison d'histogramme. EMD utilise une valeur qui définit le coût en "déplacement" des pixels d'une case de l'histogramme à une autre, et fournit le coût total de la transformation d'un histogramme spécifique en un histogramme cible. Plus un bac est éloigné, plus le coût est élevé.
Dans votre exemple, déplacer 5 unités du rouge [0] au rouge 1 coûterait (c*1*5)
tout en déplaçant 5 unités du rouge [0] au rouge [10] coûterait (c*10*5)
.
Il existe plusieurs implémentations. FastEMD a du code en C++, Java et Matlab. Je crois qu'OpenCV a aussi un support.
Il existe de nombreux articles publiés utilisant cette technique pour la recherche de similarité de base de données d'images volumineuses.
Je trouve que le test du chi carré est un bon point de départ pour comparer les histogrammes. Si vous n'avez pas le même nombre d'entrées dans chaque histogramme, vous devez être un peu plus prudent car vous ne pouvez pas utiliser l'expression "normale". De mémoire, si vous supposez que les histogrammes ont des nombres d'entrées inégaux, le test du chi carré se généralise à
1/(MN) SUM_i [((Mni - Nmi) ^ 2)/(mi + ni)].
M et N sont le nombre total d'entrées dans chaque histogramme, mi est le nombre d'entrées dans le casier i de l'histogramme M et ni est le nombre d'entrées dans le casier i de l'histogramme N.
Un autre test est le test de Kolmogorov-Smirnov. Ce test examine la différence maximale entre les distributions de probabilité cumulées des deux histogrammes. C'est plus difficile à implémenter, je pense que les recettes numériques en C ont un extrait de code en C et je suis sûr que c'est dans Matlab. Si vous êtes plus intéressé par la différence, c'est la forme de l'histogramme et non pas tant les valeurs exactes que cela peut être un meilleur test également son non paramétrique.
Vous voulez essentiellement regarder un distances de probabilité . Il y en a beaucoup et vous devez décider lequel convient à votre application. Dernièrement, j'ai eu de la chance avec Chi-squared et Kullback-Leibler.
Normalisez vos histogrammes en divisant la valeur de chaque case d'un histogramme entrant par le nombre total de pixels sur lesquels l'histogramme est basé. Ensuite, utilisez EMD de @ tkerwin .
Je pense qu'EMD est une bonne solution pour résoudre le problème inter-bin par rapport à la méthode bin to bin. Cependant, comme certains le mentionnent, l'EMD est très longue. Pourriez-vous me suggérer une autre approche pour le bac croisé?
Comme d'autres l'ont mentionné, la distance du Earth Mover ou EMD (aka métrique Wasserstein) est probablement la solution optimale. La méthode Shortlist pour un calcul EMD rapide est disponible dans le package R, transport . Il a été introduit dans n article de 2014 en le comparant à d'autres méthodes, montrant des temps de calcul plus rapides. Le seul inconvénient est qu'il est en R, ce qui n'est pas rapide à moins d'être programmé en C++ sous le capot.