two Algorithme pour comparer deux images en C#




compare two images (4)

Voici une approche simple avec une image-hachage de 256 bits (MD5 a 128 bits)

  1. redimensionner l'image en 16x16 pixels

  1. réduire les couleurs au noir / blanc (ce qui équivaut à vrai / faux dans cette sortie de la console)

  1. lire les valeurs booléennes dans List<bool> - ceci est le hachage

Code :

public static List<bool> GetHash(Bitmap bmpSource)
{
    List<bool> lResult = new List<bool>();         
    //create new image with 16x16 pixel
    Bitmap bmpMin = new Bitmap(bmpSource, new Size(16, 16));
    for (int j = 0; j < bmpMin.Height; j++)
    {
        for (int i = 0; i < bmpMin.Width; i++)
        {
            //reduce colors to true / false                
            lResult.Add(bmpMin.GetPixel(i, j).GetBrightness() < 0.5f);
        }             
    }
    return lResult;
}

Je sais, GetPixel n'est pas si rapide mais sur une image de 16x16 pixels, ça ne devrait pas être le goulot d'étranglement.

  1. comparez ce hachage avec les valeurs de hachage d'autres images et ajoutez une tolérance (nombre de pixels pouvant différer de l'autre hachage)

Code:

List<bool> iHash1 = GetHash(new Bitmap(@"C:\mykoala1.jpg"));
List<bool> iHash2 = GetHash(new Bitmap(@"C:\mykoala2.jpg"));

//determine the number of equal pixel (x of 256)
int equalElements = iHash1.Zip(iHash2, (i, j) => i == j).Count(eq => eq);

Donc, ce code est capable de trouver des images égales avec:

  • formats de fichiers différents (par exemple jpg, png, bmp)
  • rotation (90, 180, 270), basculement horizontal / vertical - en changeant l'ordre d'itération de i et j
  • différentes dimensions (le même aspect est requis)
  • compression différente (la tolérance est requise en cas de perte de qualité comme les artefacts jpeg) - vous pouvez accepter une égalité de 99% pour être la même image et 50% pour être une image différente.
  • la couleur a changé pour geyscaled et l'inverse (parce que la luminosité est indépendante de la couleur)

Mise à jour / Améliorations:

après avoir utilisé cette méthode pendant un moment, j'ai remarqué quelques améliorations qui peuvent être faites

  • replacing GetPixel pour plus de performance
  • utiliser l' exeif-thumbnail au lieu de lire toute l'image pour une amélioration des performances
  • au lieu de définir 0.5f pour différer entre la lumière et l'obscurité - utilisez la luminosité médiane distincte de tous les 256 pixels. Sinon, les images sombres / claires sont supposées identiques et permettent de détecter les images dont la luminosité est modifiée.
  • Si vous avez besoin fast calculs fast , utilisez bool[] ou List<bool> si vous avez besoin de stocker beaucoup de hachages avec la nécessité d'économiser de la mémoire, utilisez un Bitarray car un booléen n'est pas stocké dans un bit, il prend un byte !

J'écris un outil en C # pour trouver des images en double. Actuellement, je crée une somme de contrôle MD5 des fichiers et les compare.

Malheureusement mes images peuvent être

  • tourné de 90 degrés
  • avoir des dimensions différentes (image plus petite avec le même contenu)
  • avoir des compressions ou des types de fichiers différents (par exemple, des artefacts jpeg, voir ci-dessous)

quelle serait la meilleure approche pour résoudre ce problème?


Après avoir rééchantillonné les images à une résolution commune, vous pouvez utiliser une décomposition en ondelettes et comparer les coefficients de cette décomposition au lieu des images elles-mêmes. La comparaison des seuls N coefficients rendra cette méthode plus robuste au bruit et autres artefacts.

Il existe plusieurs implémentations C # pour les ondelettes disponibles. Un exemple est https://waveletstudio.codeplex.com/


Question intéressante, la comparaison d'images n'est pas si difficile étant donné que,

  1. Ces images sont les mêmes (le premier n'est pas une section du second ou vice versa)
  2. Les images ne sont tournées que par des multiples de 90 degrés

Une façon de faire serait de comparer,

  1. Redimensionner les deux images à la taille la plus petite
  2. Appliquer la détection des contours sur chaque image résultante en noir et blanc (ou tableau de 0 et 1)
  3. Comparez les bitmaps qui en résultent (gardez le premier encore et tournez le second de 90 degrés 3 fois) et calculez% pixcels correspondant et obtenez la valeur la plus élevée

Maintenant, si la valeur se situe dans une valeur raisonnable disons 90% (probablement à déterminer en faisant quelques expériences), alors vous pouvez sans risque supposer les deux sont les mêmes, mais cela ne va pas fonctionner si,

  1. Même si quelques pixels sont différents dans le coin, par exemple la deuxième image est coupée du premier
  2. Les images sont alternées à des multiples de 90 degrés (bien que ce ne soit pas très probable)

Vous pouvez vérifier l' algorithme pour comparer deux images afin de voir les méthodes disponibles pour la comparaison d'images.

À moins de vouloir recréer vous-même l'intégralité des algorithmes, vous devriez essayer d'utiliser des bibliothèques déjà existantes ou une partie au moins de leur code (à condition que leur licence vous convienne).

Pour une implémentation C # open source de la détection Edge et des algorithmes de vision par ordinateur associés, vous pouvez essayer EmguCV qui est un wrapper d'OpenCV.





hash