IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Image identique ou différente


Sujet :

C#

  1. #1
    Membre régulier
    Profil pro
    Débutant
    Inscrit en
    Février 2007
    Messages
    126
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Débutant
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Février 2007
    Messages : 126
    Points : 87
    Points
    87
    Par défaut Image identique ou différente
    Bonjour à tous,

    Je me crée une petite bibliothèque de comparaison d'image dans le cadre d'un projet. Une des class est censée vérifier que deux image sont identiques en taille, format, résolution, ...

    Pour la comparer pixels par pixels, j'utilise la fonction suivante qui trouve les pixels différent

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    		protected static IList<Point> GetDiffPixels(Image img1, Image img2)
    		{
    			Bitmap bmp1 = (Bitmap)img1;
    			Bitmap bmp2 = (Bitmap)img2;
     
    			IEnumerable<int> widthRange = Enumerable.Range(0, img1.Width);
    			IEnumerable<int> heightRange = Enumerable.Range(0, img1.Height);
     
    			List<Point> result = widthRange
    				.SelectMany(x => heightRange, (x, y) => new Point(x, y))
    				.Select(point => new
    				        {
    				        	Point = point,
    				        	Pixel1 = bmp1.GetPixel(point.X, point.Y),
    				        	Pixel2 = bmp2.GetPixel(point.X, point.Y)
    				        })
    				.Where(pair => pair.Pixel1 != pair.Pixel2)
    				.Select(pair => pair.Point)
    				.ToList();
     
    			return result;
    		}
    En principe si le résultat est à 0 j'ai une image identique au pixels près.

    J'ai également fait un autre test sur base de deux images identiques au pixels près et au même format sur leur stream par le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    		public static Stream ImageToStream(Image image)
    		{
    			ImageFormat imgFormat = ImgUtils.GetFormat(image);
     
    			MemoryStream ms = new MemoryStream();
    			image.Save(ms, imgFormat);
    			return  ms;
    		}
     
    		public static bool CompareStreamImage(Image img1, Image img2)
    		{
    			using( Stream stream1 = ImageToStream( img1 ) ) {
    				using(Stream stream2 = ImageToStream( img2 ) ) {
     
    					return CompareStream(stream1, stream2);
     
    				}}
     
    		}
     
    public static bool CompareStream(Stream a, Stream b)
    		{
    			if (a == null || b == null)
    				throw new ArgumentNullException(a == null ? "a" : "b");
     
    			if (a == b)
    				return true;
     
    			if (a.Length != b.Length) //TODO: comment faire la différence si longueur différente ou si pas la même comparaison après
    				return false;
     
    			for (int i = 0; i < a.Length; i++)
    			{
    				int aByte = a.ReadByte();
    				int bByte = b.ReadByte();
     
    				if (aByte.CompareTo(bByte) != 0)
    					return false;
    			}
     
    			return true;
    		}
    Et la le résultat est étonnant.

    En effet, la comparaison au pixels près est identique mais l'analyse du stream est différent au niveaux de la longeur des streams.

    Les questions sont donc

    l'image est-elle différente ou non?
    Qu'est ce qui peut faire que deux images identiques au pixels près peuvent avoir des streams différent?
    Sur quoi puis-je me baser pour m'assurer que deux images sont identiques si les méthodes ci-avant donnent des résultat différent?

    Merci de votre aide et en espérant avoir été clair sur le problème rencontré.

  2. #2
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    bonjour

    Il est preferable de comparer les images Byte à Byte (octet par octer).

    ton code revu :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     
        public static bool CompareByteImage(Image img1, Image img2)
            {
               byte[] byteImg1 = ImageToByteArray(img1);
               byte[] byteImg2 = ImageToByteArray(img2);
     
                return CompareBytesImage(byteImg1, byteImg2);
            }
            public static byte[] ImageToByteArray(Image image)
            {
                ImageFormat imgFormat = ImgUtils.GetFormat(image);
     
                MemoryStream ms = new MemoryStream();
                image.Save(ms, imgFormat);
                return ms.ToArray();
            }
            public static bool CompareBytesImage(byte[] a, byte[] b)
            {
                if (a == null || b == null)
                    throw new ArgumentNullException(a == null ? "a" : "b");
     
                if (a == b)
                    return true;
     
                if (a.Length != b.Length) //TODO: comment faire la différence si longueur différente ou si pas la même comparaison après
                    return false;
     
                for (int i = 0; i < a.Length; i++)
                {
                    byte aByte = a[i];
                    byte bByte = b[i];
     
                    if (aByte.CompareTo(bByte) != 0)
                        return false;
                }
     
                return true;
            }
    bon code...

  3. #3
    Expert éminent sénior

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 757
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 757
    Points : 10 697
    Points
    10 697
    Billets dans le blog
    21
    Par défaut
    Citation Envoyé par MABROUKI Voir le message
    bonjour

    Il est preferable de comparer les images Byte à Byte (octet par octer).
    Cela ne changera pas le problème. Les méthodes byte à byte ou stream à stream retourneront le même résultat.

    Citation Envoyé par agparchitecture
    Qu'est ce qui peut faire que deux images identiques au pixels près peuvent avoir des streams différent?
    Tout simplement les métadonnées.

    Lorsque tu compares pixel par pixel, tu prends les données de l'image uniquement.

    Lorsque tu compares stream par stream, le stream contient l'image sous un format (PNG, JPEG, etc...). Ces formats contiennent les données de l'image (les pixels), mais aussi des métadonnées (par exemple date et heure). Tu peux donc avoir 2 images identiques au niveau des pixels, mais avec des métadonnées différentes. Ce qui explique que la comparaison pixel par pixel puisse te renvoyer un résultat différent de la comparaison stream par stream.

    Si tu veux comparer les images (le contenu), la bonne méthode est bien d'utiliser les pixels.
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  4. #4
    Membre régulier
    Profil pro
    Débutant
    Inscrit en
    Février 2007
    Messages
    126
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Débutant
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Février 2007
    Messages : 126
    Points : 87
    Points
    87
    Par défaut
    Ok merci pour les explications:

    Donc si je veux savoir si les images sont identiques au vu de ce qu'elles affichent (contenus) je regarde les différences des pixels.

    Par contre si je veux savoir si elles sont parfaitement identiques (contenus + métadonnées) je regarde le flux.

    Merci

    @MABROUKI : Ton code me propose de passer par un tableau de bytes à la place d'un ReadBytes sur chaque boucle. Quelle en est la raison par rapport à mon code initial?

  5. #5
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    Citation Envoyé par agparchitecture Voir le message
    Ok merci pour les explications:

    Donc si je veux savoir si les images sont identiques au vu de ce qu'elles affichent (contenus) je regarde les différences des pixels.

    Par contre si je veux savoir si elles sont parfaitement identiques (contenus + métadonnées) je regarde le flux.

    Merci

    @MABROUKI : Ton code me propose de passer par un tableau de bytes à la place d'un ReadBytes sur chaque boucle. Quelle en est la raison par rapport à mon code initial?
    La raison en est la clarté .

    1/ Au regard de ce qu'elles affichent c'est allez vite en besogne. Tu veux dire pixel par pixel pour être plus précis .
    Même dans ce cas il faut en plus que les images aient mêmes Hauteur et Largeur sinon false.
    Ensuite pour comparer rapidement des tableaux de pixels le class BitmapData qui utilise l'interop est le moyen le plus rapide pour le faire.
    2/ si elles sont parfaitement identiques (contenus + métadonnées) ,la même condition Hauteur et Largeur s'impose.
    Comme tu n'as pas fourni le contexte ou but précis de cette comparaison ,la question posée reste vaste.

  6. #6
    Membre régulier
    Profil pro
    Débutant
    Inscrit en
    Février 2007
    Messages
    126
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Débutant
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Février 2007
    Messages : 126
    Points : 87
    Points
    87
    Par défaut
    En fait j'ai plusieurs images qui ont été ramenée depuis différent disque durs et je voulais supprimer les doublons. Fdupes sur linux fait ca très bien mais il en laissait beaucoup qui sont toujours identiques.

    J'ai donc regardé comment fdupes fonctionnait et il fait une comparaison sur le stream. j'ai donc regardé pour faire une comparaison sur les pixels et me suis rendu compte que les images était quand même identique.

    Ne me tracassant pas des métadata, je dois donc bien faire une comparaison pixels par pixels pour m'assurer que les images sont identiques et n'en conserver plus qu'une pour ne plus avoir de doublons.

  7. #7
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    bonjour
    Pour une comparaison par pixel exacte et pour complément les conditions à réunir sont:
    - les images doivent avoir mêmes Size(Hauteur et Largeur en pixel).
    - les images doivent avoir même Résolution
    - les images doivent avoir même PixelFormat(Format32bppRgb,Format32bppArgb,Indexed,etc...)
    - les images doivent avoir même RawFormat(bmp,jpg,png,etc...)

    bon code...

  8. #8
    Membre régulier
    Profil pro
    Débutant
    Inscrit en
    Février 2007
    Messages
    126
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Débutant
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Février 2007
    Messages : 126
    Points : 87
    Points
    87
    Par défaut
    Je viens de rouvrir le post car je me pose encore une question qui reste dans la logique de cette discutions. Si nécessaire je peux ouvrir une nouvelle question

    @MABROUKI : Effectivement, je n'ai pas mis tout le code mais je vérifie bien avant de comparer les pixels que les images sont bien du même type et peuvent être comparées
    Si nécessaire je peux ajouter la class que je suis en train de faire.

    Par contre en continuant le développement je me pose une question car le getpixels(x, y) ou l'utilisation de linq dans ma fonction est très lent sur les images un peut grosse.

    mais on a vu que la différence du stream venait des métadata.

    La question est donc si je clone mes deux images en supprimant les métadat des images est-ce que j'aurai le même Stream?

    En fait j'envisage de faire comme suit:

    1. je copie les images en supprimant les métadata
    2. je convertit les images sans métadat en stream
    3. je compare les streams en comptabilisant les différences. (mais est-ce que les stream seront bien identique???)
    4. Si ceux-ci sont identiques
    alors les images sont identiques
    sinon l’addition des différence me permet de caluler le pourcentage de similarité

    Est-ce que cet algorithme peut marcher correctement ou le fait de simplement supprimer les métadata d'image identique ne me garantira pas des stream identique?

    PS: j'ai vu qu'il existait également lockbit mais je ne veux pas forcément "travailler sur les images" mais juste les comparer sans préoccupation de métadata.

    Merci

Discussions similaires

  1. Images identiques de différentes tailles
    Par rockley dans le forum Traitement d'images
    Réponses: 5
    Dernier message: 09/01/2013, 10h14
  2. [CSS] background-image et classes différentes
    Par Istrella dans le forum Mise en page CSS
    Réponses: 6
    Dernier message: 15/09/2006, 18h44
  3. [css] afficher image sur div différent
    Par mussara dans le forum Mise en page CSS
    Réponses: 20
    Dernier message: 25/07/2006, 12h47
  4. [ XSL : FO] probleme images identique!!!
    Par chouchou93 dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 08/02/2006, 15h38

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo