web-dev-qa-db-fra.com

Algorithme pour comparer deux images en C #

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)
  • ont des compressions ou des types de fichiers différents (par exemple, des artefacts jpeg, voir ci-dessous)

enter image description hereenter image description here

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

49
Byyo

Voici une approche simple avec un hachage d'image de 256 bits (MD5 a 128 bits)

  1. redimensionner l'image à 16x16 pixel

16x16 resized

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

enter image description here

  1. lit les valeurs booléennes dans List<bool> - c'est le hash

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 que GetPixel n'est pas si rapide, mais sur une image de 16 x 16 pixels, il ne devrait pas s'agir d'un goulot d'étranglement.

  1. compare ce hachage aux valeurs de hachage des autres images et ajoute 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:

  • différents formats de fichiers (jpg, png, bmp, par exemple)
  • rotation (90, 180, 270), retournement horizontal/vertical - en modifiant l'ordre d'itération de i et j
  • dimensions différentes (même aspect requis)
  • compression différente (une tolérance est requise en cas de perte de qualité, comme les artefacts jpeg) - vous pouvez accepter une égalité de 99% comme étant la même image et 50% comme étant différente.
  • couleur changée en geyscaled et inversement (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 apportées

  • remplaceGetPixel pour plus de performance
  • en utilisant exeif-thumbnail au lieu de lire toute l'image pour améliorer les performances
  • au lieu de mettre 0.5f pour faire la différence entre clair et foncé - utilisez la luminosité médiane distincte de l’ensemble des 256 pixels. Sinon, les images sombres/claires sont supposées être identiques et permettent de détecter les images dont la luminosité a changé.
  • si vous avez besoin de rapide calculs, utilisez bool[] ou List<bool> _ Si vous devez stocker beaucoup de hachages tout en économisant de la mémoire, utilisez un Bitarray car un booléen n’est pas stocké dans un bit, il faut un octet !
71
fubo

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

Sauf si vous souhaitez 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 (tant que leur licence vous convient).

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.

7
Fab

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 à la place des images elles-mêmes. La comparaison des seuls N premiers coefficients rendra cette méthode plus robuste au bruit et aux autres artefacts.

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

4
Yurrit Avonds

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

  1. Ces images sont les mêmes (la première n’est pas une section de la seconde ou vice versa)
  2. Les images ne pivotent que par multiples de 90 degrés

Une façon de faire la comparaison serait de:

  1. Redimensionner les images à la plus petite taille
  2. Appliquer la détection de contour sur chaque image résultante en image noir et blanc (ou un tableau de 0 et 1)
  3. Comparez les bitmaps obtenus (gardez le premier immobile et faites pivoter le second de 90 degrés 3 fois) et calculez le pourcentage de pixels correspondant et obtenez la valeur la plus élevée.

Maintenant, si la valeur se situe dans une valeur raisonnable, disons 90% (vous devrez probablement déterminer en effectuant peu d'expériences), alors vous pouvez sans risque supposer que les deux sont identiques, mais cela ne fonctionnera pas si,

  1. Même si quelques pixels diffèrent dans le coin, par exemple, la deuxième image est recadrée de la première
  2. La rotation des images n’est pas un multiple de 90 degrés (bien que ce ne soit pas très probable)
2
Low Flying Pelican