web-dev-qa-db-fra.com

Comparaison de deux histogrammes

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:

  1. Une caméra de sécurité (CCTV) dans un musée regardant une exposition: nous voulons voir rapidement si deux images vidéo différentes montrent la même scène, mais de légères différences d'éclairage et de mise au point de la caméra signifient qu'elles ne seront pas identiques.
  2. Une image d'une icône GUI d'ordinateur vectoriel rendue à 64x64 par rapport à la même icône rendue à 48x48 (mais les deux images seraient réduites à 32x32 afin que les histogrammes aient le même nombre total de pixels).

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?

49
Dai

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.

  • Comparaison de bin à bin: Comme vous l'avez dit, la somme standard des différences est assez mauvaise. Il y a une amélioration, la distance Chi-carré , qui dit que si 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.
  • Comparaison inter-bin: Un exemple standard appelé matrice de similitude de bin nécessite une matrice de similitude M où dans 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:

  • Vous devriez lire cet article sur la distance de l'histogramme . C'est assez simple et vous présente les distances d'histogramme. Toutes les distances dont j'ai parlé se résument bien au chapitre 1. Honnêtement, la dernière chose décrite dans l'article n'est pas si complexe, mais c'est probablement exagéré pour votre cas.
  • La distance entre les bacs est très bonne, mais peut être coûteuse (c'est-à-dire: longue à calculer, car elle implique une matrice, donc O (n ^ 2)). Le moyen le plus simple de contourner le coûteux calcul inter-bacs (et cela est largement fait) est de faire une affectation douce: si un pixel est rouge, vous devez remplir TOUS les bacs qui ressemblent à distance au rouge (bien sûr, en donnant plus poids aux couleurs les plus proches). Ensuite, vous pouvez utiliser un algorithme bin-to-bin.
  • Un peu plus centré sur les mathématiques: le point précédent portait sur la réduction d'une comparaison inter-bacs à une comparaison bin-à-bin. En fait, il consiste à diagonaliser implicitement la matrice de similarité M. Si vous pouvez diagonaliser M = P'*D*PP' 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
75
Fezvez

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 .

23
nkint

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.

14
tkerwin

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.

6
Bowler

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.

4
Chris A.

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 .

2
jilles de wit

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é?

0
John

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.

0
Adam Erickson