begin process at 2012 02 11 09:54:40
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Graphique

 > TRAITEMENT D'IMAGE EN NOIR ET BLANC

TRAITEMENT D'IMAGE EN NOIR ET BLANC


 Information sur la source

Note :
Aucune note
Catégorie :Graphique Source .NET ( DotNet ) Classé sous :image, noir, blanc, difusion, erreurs Niveau :Initié Date de création :08/11/2006 Date de mise à jour :09/11/2006 14:22:08 Vu :17 093

Auteur : Malkuth

Ecrire un message privé
Commentaire sur cette source (3)
Ajouter un commentaire et/ou une note

 Description

Cliquez pour voir la capture en taille normale
Bonjours à tous

Voilà je doit travaillé sur des image et les convertir en noir & blanc (C'est un projet de génération de fax), il s'agit aussi de mon premier projet C# (le C/C++ est assez loin derriere moi mais je suis content de revenir a ce type de syntax aprés une longue période VB).

cette classe fais partie d'un projet bien plus vaste mais elle pourra aidé des paersonne qui auront a travailler sur des image en noir et blanc (sujet peu traiter sur les sites codes source a ce que j'ai vue), il y'a aussi Frédéric Mélantois qui traite du sujet du traitement d'image sur son blog et dans des articles (dernier : http://www.techheadbrothers.com/Articles.aspx?Id=8 d3eb481-8a98-42a6-8033-e851c797aa60&p=1).
donc ca pourras peut-être soulever des questions/sugestions sur le sujet.

Enfin bref j'ai essayer d'optimiser mais y'a sans doute d'autres optimisation a faire.

C'est la première fois que je traite des image et dans l'ensemble je ne suis pas mécontant du résultat , mon application est fluide toutefois je ne suis pas satisfais de la gestion de la luminositer, j'ai essayer de trouver un moyen de ne pas "bruler" les parties claires mais on as trés vite une perte de constraste, si quelqu'un peut me donnée des méthodes pour réaliser ca de maniére plus propre je suis preneur(j'y mais juste la condition que l'algo s'applique sur le niveau de gris.

La classe supporte trois algo pour la transphormation niveau de gris -> Noir et blanc :
RANDOM (on compare le niveau de gris a une valeur aléatoire),
HALFTONE (on compare le niveau de gris a une valeur fixé),
FLOYD Steinberg (algo par difusion d'erreur) sans doute le plus intéréssant mais aussi le plus gourmand

il est a noté que l'algo Floyd a tendonce a créer des motif répétitif pour les surfaces de couleur uniforme et dégradé on pourat donc l'amélioré en ajoutant une petite dose d'aléatoire...


le traitement noir et blanc est volontairement séparer de la partie qui gére le passage en noir et blanc, en effet cette partie n'est recalculer que lorsque l'on modifie la taille de l'image ce qui est assez rare pour des pages de fax.


Source

  • //Structure de manipulation de tableaux RGB
  • public struct RGBPix
  • {
  • public byte R;
  • public byte G;
  • public byte B;
  • }
  • //Classe de manipulation et conversion d'image en noir et blanc
  • public class FaxImage
  • {
  • //Petite enumération des différent algo gérer par la classe
  • public enum BWAlgorithme
  • {
  • Floyd,
  • Haltone,
  • Random
  • }
  • //Immage d'origine
  • private Bitmap _OriginalImg = null;
  • //Pointer ver un tableau de byte contenant les données en niveaux de gris
  • private IntPtr _GreyDat = IntPtr.Zero;
  • //Image finale
  • private Bitmap _BWImg = null;
  • //variable de configuration internes
  • private BWAlgorithme _DitherAlgo = BWAlgorithme.Floyd;
  • private sbyte _Luminosity = 0;
  • private int _Height = 0;
  • private int _Width = 0;
  • //Constructeur On lui passe l'image d'origine, et la taille finale souhaiter
  • public FaxImage(System.Drawing.Bitmap Img,int Width,int Height)
  • {
  • this.Width = Width;
  • this.Height = Height;
  • this._OriginalImg = Img;
  • }
  • //Métode pour changer d'image d'origine
  • public void SetImage(Bitmap Image)
  • {
  • this._OriginalImg = Image;
  • if (this._GreyDat != IntPtr.Zero)
  • {
  • System.Runtime.InteropServices.Marshal.FreeHGlobal(this._GreyDat);
  • this._GreyDat = IntPtr.Zero;
  • }
  • }
  • //Propriété pour récupérer l'image en noir et blanc
  • public System.Drawing.Bitmap BWImage
  • {
  • get
  • {
  • //On recalcul l'image en niveau de gris si besoin.
  • if (this._GreyDat == IntPtr.Zero)
  • Make_GrayDat();
  • //On recalcul l'image noir et blanc si besoin
  • if (_BWImg==null)
  • switch (this._DitherAlgo)
  • {
  • case BWAlgorithme.Floyd:
  • Make_BWDat_Floyd();
  • break;
  • case BWAlgorithme.Haltone:
  • Make_BWDat_HalfTone();
  • break;
  • case BWAlgorithme.Random:
  • Make_BWDat_Random();
  • break;
  • }
  • //On retourne l'image
  • return this._BWImg;
  • }
  • }
  • Propriéter de modification de la luminositer de l'image final
  • public sbyte Luminosity
  • {
  • get
  • {
  • return this._Luminosity;
  • }
  • set
  • {
  • if (this._Luminosity != value)
  • {
  • this._Luminosity = value;
  • if (this._BWImg != null)
  • {
  • this._BWImg.Dispose();
  • this._BWImg = null;
  • }
  • }
  • }
  • }
  • //Propriéter pour indiquer l'algo a utiliser lors de la conversion
  • public BWAlgorithme DitherAlgo
  • {
  • get
  • {
  • return this._DitherAlgo;
  • }
  • set
  • {
  • if (this._DitherAlgo != value)
  • {
  • this._DitherAlgo = value;
  • if (this._BWImg != null)
  • {
  • this._BWImg.Dispose();
  • this._BWImg = null;
  • }
  • }
  • }
  • }
  • //Propriéter de la hauteur final de l'image
  • public int Height
  • {
  • get
  • {
  • return this._Height;
  • }
  • set
  • {
  • if (value < 1) value = 1;
  • if (this._Height != value)
  • {
  • this._Height = value;
  • if (this._GreyDat != IntPtr.Zero)
  • {
  • System.Runtime.InteropServices.Marshal.FreeHGlobal(this._GreyDat);
  • this._GreyDat = IntPtr.Zero;
  • }
  • }
  • }
  • }
  • //Propriéter de la largeur final de l'image
  • public int Width
  • {
  • get
  • {
  • return this._Width;
  • }
  • set
  • {
  • if (value < 1) value = 1;
  • if (this._Width != value)
  • {
  • this._Width = value;
  • if (this._GreyDat != IntPtr.Zero)
  • {
  • System.Runtime.InteropServices.Marshal.FreeHGlobal(this._GreyDat);
  • this._GreyDat = IntPtr.Zero;
  • }
  • }
  • }
  • }
  • private void Make_BWDat_Floyd()
  • {
  • //Initialisation de l'image
  • if (this._BWImg != null)
  • this._BWImg.Dispose();
  • this._BWImg=new Bitmap(this._Width, this._Height, PixelFormat.Format1bppIndexed);
  • BitmapData BWDat = this._BWImg.LockBits(new Rectangle(0, 0, this._Width, this._Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);
  • //Allocation de la mémoire pour les erreurs
  • IntPtr Erreurs = System.Runtime.InteropServices.Marshal.AllocHGlobal(((this._Height + 1) * this._Width + 1) * sizeof(int));
  • //Calcule des donnée noir et blanc
  • unsafe
  • {
  • byte CurBitMsk;
  • int PointVal;
  • int ErrToDispatch;
  • byte* CurGrey = (byte*)this._GreyDat.ToPointer();
  • int* CurErreur = (int*)Erreurs.ToPointer();
  • int* CurErreur7 = &(CurErreur[1]);
  • int* CurErreur1 = &(CurErreur[this._Width - 1]);
  • int* CurErreur5 = &(CurErreur[this._Width]);
  • int* CurErreur3 = &(CurErreur[this._Width + 1]);
  • //initialisation des premiéres erreurs (les autres seront initialiser à la volée).
  • for (int* LastErreur = &(((int*)Erreurs.ToPointer())[this._Width]); CurErreur <= LastErreur; CurErreur++)
  • *CurErreur = 0;
  • CurErreur = (int*)Erreurs.ToPointer();
  • Random Rnd = new Random();
  • float LuminosityRatio = (float)((float)255/(float)(255 - Math.Abs(this._Luminosity)));
  • byte LuminosityOffset = (this._Luminosity < 0) ? (byte)0 : (byte)this._Luminosity;
  • //Table de précacule de la luminosité
  • byte* LuminosityTab = stackalloc byte [255];
  • for (int grayValue = 0; grayValue < 255; grayValue++)
  • LuminosityTab[grayValue] = (byte)(grayValue / LuminosityRatio + LuminosityOffset);
  • for (int y = 0; y < this._Height; y++)
  • {
  • CurBitMsk = 128;// 1 << 7;
  • for (
  • byte* CurBWs = &(((byte*)BWDat.Scan0.ToPointer())[BWDat.Stride * y]), //On ointe vers le premier octe de la ligne en cours.
  • afterLastGrey = &(((byte*)this._GreyDat.ToPointer())[(y+1)*this.Width]); //Borne de la ligne des niveaux de gris
  • //On parcourt la ligne courante
  • CurGrey < afterLastGrey;
  • //incrémentation des pointeurs
  • CurGrey++,
  • CurErreur++,
  • CurErreur7++,
  • CurErreur1++,
  • CurErreur5++,
  • CurErreur3++
  • )
  • {
  • //Calcul de la valeur du point
  • PointVal = LuminosityTab[*CurGrey] + *CurErreur + Rnd.Next(-25, 25);
  • if(PointVal > 128)
  • {
  • //Enregistrement du point
  • *CurBWs |= CurBitMsk;
  • //Calcul de l'erreur
  • ErrToDispatch = PointVal - 255;
  • }
  • else
  • {
  • //Enregistrement du point
  • *CurBWs &= (byte)(255 ^ CurBitMsk);
  • //Calcul de l'erreur
  • ErrToDispatch = PointVal;
  • }
  • //Diffusion de l'erreur
  • *CurErreur7 += ((ErrToDispatch * 7) >> 4);
  • *CurErreur1 += (ErrToDispatch >> 4);
  • *CurErreur5 += ((ErrToDispatch * 5) >> 4);
  • *CurErreur3 = ((ErrToDispatch * 3) >> 4); // = et pas += pour initialisé à la volée
  • //Initialisation des pointeurs et du masque de bit courant pour le point suivant
  • CurBitMsk >>= 1;
  • if (CurBitMsk == 0)
  • {
  • CurBitMsk = 128;//1 << 7;
  • CurBWs++;
  • }
  • }
  • }
  • }
  • //Libération du tableau des erreurs
  • System.Runtime.InteropServices.Marshal.FreeHGlobal(Erreurs);
  • //Sauveguarde de l'image.
  • this._BWImg.UnlockBits(BWDat);
  • }
  • private void Make_BWDat_Random()
  • {
  • //Initialisation de l'image
  • if (this._BWImg != null)
  • this._BWImg.Dispose();
  • this._BWImg = new Bitmap(this._Width, this._Height, PixelFormat.Format1bppIndexed);
  • BitmapData BWDat = this._BWImg.LockBits(new Rectangle(0, 0, this._Width, this._Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);
  • //initialisation d'un Tableau de byte aléatoire.
  • Byte[] rnds = new Byte[this._Width * this._Height];
  • new Random().NextBytes(rnds);
  • //Calcule des donnée noir et blanc
  • unsafe
  • {
  • byte* CurBWs = (byte*)BWDat.Scan0.ToPointer();
  • byte* CurGrey = (byte*)this._GreyDat.ToPointer();
  • byte CurBitMsk;
  • double LuminosityRatio = (255 - Math.Abs(this._Luminosity)) / 255.0;
  • for (int y = 0; y < this._Height; y++)
  • {
  • CurBitMsk = 128;// 1 << 7;
  • CurBWs = &(((byte*)BWDat.Scan0.ToPointer())[BWDat.Stride * y]);
  • for (int x = 0; x < this._Width; x++)
  • {
  • //Enregistrement du point
  • *CurBWs = (byte)((((*CurGrey * LuminosityRatio) + ((this._Luminosity < 0) ? (sbyte)0 : this._Luminosity)) > rnds[x + y * this._Width]) ? (*CurBWs | CurBitMsk) : (*CurBWs & (255 ^ CurBitMsk)));
  • //Initialisation des pointeurs et du masque de bit courant pour le point suivant
  • CurBitMsk >>= 1;
  • if (CurBitMsk == 0)
  • {
  • CurBitMsk = 128; // 1 << 7;
  • CurBWs++;
  • }
  • CurGrey++;
  • }
  • }
  • }
  • //Sauveguarde de l'image.
  • this._BWImg.UnlockBits(BWDat);
  • }
  • private void Make_BWDat_HalfTone()
  • {
  • //Initialisation de l'image
  • if (this._BWImg != null)
  • this._BWImg.Dispose();
  • this._BWImg = new Bitmap(this._Width, this._Height, PixelFormat.Format1bppIndexed);
  • BitmapData BWDat = this._BWImg.LockBits(new Rectangle(0, 0, this._Width, this._Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);
  • //Calcul des donnée noir et blanc
  • unsafe
  • {
  • byte* CurBWs = (byte*)BWDat.Scan0.ToPointer();
  • byte* CurGrey = (byte*)this._GreyDat.ToPointer();
  • byte CurBitMsk;
  • double LuminosityRatio = (255 - Math.Abs(this._Luminosity)) / 255.0;
  • for (int y = 0; y < this._Height; y++)
  • {
  • CurBitMsk = 1 << 7;
  • CurBWs = &(((byte*)BWDat.Scan0.ToPointer())[BWDat.Stride * y]);
  • for (int x = 0; x < this._Width; x++)
  • {
  • //Enregistrement du point
  • *CurBWs = (byte)((((*CurGrey * LuminosityRatio) + ((this._Luminosity < 0) ? (sbyte)0 : this._Luminosity)) > 128) ? (*CurBWs | CurBitMsk) : (*CurBWs & (255 ^ CurBitMsk)));
  • //Initialisation des pointeurs et du masque de bit courant pour le point suivant
  • CurBitMsk >>= 1;
  • if (CurBitMsk == 0)
  • {
  • CurBitMsk = 1 << 7;
  • CurBWs++;
  • }
  • CurGrey++;
  • }
  • }
  • }
  • //Enregistrement des modification.
  • this._BWImg.UnlockBits(BWDat);
  • }
  • public void Make_GrayDat()
  • {
  • //On redimensionne l'image d'origine.
  • Bitmap SizedImg = new Bitmap (this._OriginalImg ,this._Width,this._Height);
  • //OnRécupére les données de l'image.
  • BitmapData RGBDat = SizedImg.LockBits(new Rectangle(0, 0, this._Width, this._Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
  • //On initialise le tableau de donnée.
  • if (this._GreyDat != IntPtr.Zero)
  • {
  • System.Runtime.InteropServices.Marshal.ReAllocHGlobal(this._GreyDat,new IntPtr(this._Width * this._Height));
  • }
  • else
  • {
  • this._GreyDat = System.Runtime.InteropServices.Marshal.AllocHGlobal(this._Width * this._Height);
  • }
  • //On Recalcule les données de niveau de gris.
  • unsafe
  • {
  • //tables de precalculs des multiplications pour le calcul du niveau de gris
  • //Les tableaus sont créer dans le tas (+ rapide por les petits tableau)
  • //ils sont libéré à la fin de la fonction.
  • int* multiBleu = stackalloc int[256];
  • int* multiVert = stackalloc int[256];
  • int* multiRouge = stackalloc int[256];
  • for (int i = 0; i < 256; i++)
  • {
  • multiBleu[i] = 76 * i;
  • multiVert[i] = 151 * i;
  • multiRouge[i] = 28 * i;
  • }
  • byte* CurGrey = (byte*)this._GreyDat.ToPointer();
  • for (int y = 0; y < this._Height; y++)
  • {
  • //On pointe vers le début de la ligne
  • RGBPix* CurRGBDat = (RGBPix*)&(((byte*)RGBDat.Scan0.ToPointer())[y * RGBDat.Stride]);
  • //Balayage de la ligne
  • for (
  • // Calcul de la borne supérieur de la ligne
  • byte* afterLastGrey = &(((byte*)this._GreyDat.ToPointer())[(y+1)*this.Width]); //Borne de la ligne des niveaux de gris
  • //On Balaye toute la ligne
  • CurGrey < afterLastGrey;
  • //On pointe vers les données suivantes
  • CurRGBDat++,
  • CurGrey++
  • )
  • *CurGrey = (byte)((multiBleu[CurRGBDat->B] + multiVert[CurRGBDat->G] + multiRouge[CurRGBDat->R]) >> 8);
  • }
  • }
  • //On supprime les donnée en noir et blans pour forcer leur recalcule
  • if (_BWImg != null)
  • {
  • this._BWImg.Dispose();
  • this._BWImg=null;
  • }
  • //On libére les ressoure
  • SizedImg.UnlockBits(RGBDat);
  • SizedImg.Dispose();
  • }
  • }
        //Structure de manipulation de tableaux RGB
    public struct RGBPix
    {
        public byte R;
        public byte G;
        public byte B;
    }

    //Classe de manipulation et conversion d'image en noir et blanc
    public class FaxImage
    {

        //Petite enumération des différent algo gérer par la classe
        public enum BWAlgorithme
        {
            Floyd,
            Haltone,
            Random
        }
        //Immage d'origine
        private Bitmap _OriginalImg = null;
        //Pointer ver un tableau de byte contenant les données en niveaux de gris
        private IntPtr _GreyDat = IntPtr.Zero;
        //Image finale
        private Bitmap _BWImg = null;

        //variable de configuration internes
        private BWAlgorithme _DitherAlgo = BWAlgorithme.Floyd;
        private sbyte _Luminosity = 0;
        private int _Height = 0;
        private int _Width = 0;

        //Constructeur On lui passe l'image d'origine, et la taille finale souhaiter
        public FaxImage(System.Drawing.Bitmap Img,int Width,int Height)
        {
            this.Width = Width;
            this.Height = Height;
            this._OriginalImg = Img;
        }

        //Métode pour changer d'image d'origine
        public void SetImage(Bitmap Image)
        {
            this._OriginalImg = Image;
            if (this._GreyDat != IntPtr.Zero)
            {
                System.Runtime.InteropServices.Marshal.FreeHGlobal(this._GreyDat);
                this._GreyDat = IntPtr.Zero;
            }
        }

        //Propriété pour récupérer l'image en noir et blanc
        public System.Drawing.Bitmap BWImage
        {
            get
            {
                //On recalcul l'image en niveau de gris si besoin.
                if (this._GreyDat == IntPtr.Zero)
                    Make_GrayDat();
                //On recalcul l'image noir et blanc si besoin
                if (_BWImg==null)
                    switch (this._DitherAlgo)
                    {
                        case BWAlgorithme.Floyd:
                            Make_BWDat_Floyd();
                            break;
                        case BWAlgorithme.Haltone:
                            Make_BWDat_HalfTone();
                            break;
                        case BWAlgorithme.Random:
                            Make_BWDat_Random();
                            break;
                    }
                //On retourne l'image
                return this._BWImg;
            }            
        }

        Propriéter de modification de la luminositer de l'image final
        public sbyte Luminosity
        {
            get
            {
                return this._Luminosity;
            }
            set
            {
                if (this._Luminosity != value)
                {
                    this._Luminosity = value;
                    if (this._BWImg != null)
                    {
                        this._BWImg.Dispose();
                        this._BWImg = null;
                    }
                }
            }
        }

        //Propriéter pour indiquer l'algo a utiliser lors de la conversion
        public BWAlgorithme DitherAlgo
        {
            get
            {
                return this._DitherAlgo;
            }
            set
            {
                if (this._DitherAlgo != value)
                {
                    this._DitherAlgo = value;
                    if (this._BWImg != null)
                    {
                        this._BWImg.Dispose();
                        this._BWImg = null;
                    }
                }
            }
        }

        //Propriéter de la hauteur final de l'image
        public int Height
        {
            get
            {
                return this._Height;
            }
            set
            {
                if (value < 1) value = 1;
                if (this._Height != value)
                {
                    this._Height = value;
                    if (this._GreyDat != IntPtr.Zero)
                    {
                        System.Runtime.InteropServices.Marshal.FreeHGlobal(this._GreyDat);
                        this._GreyDat = IntPtr.Zero;
                    }

                }
            }
        }

        //Propriéter de la largeur final de l'image
        public int Width
        {
            get
            {
                return this._Width;
            }
            set
            {   
                if (value < 1) value = 1;
                if (this._Width != value)
                {
                    this._Width = value;
                    if (this._GreyDat != IntPtr.Zero)
                    {
                        System.Runtime.InteropServices.Marshal.FreeHGlobal(this._GreyDat);
                        this._GreyDat = IntPtr.Zero;
                    }

                }
            }
        }

        private void Make_BWDat_Floyd()
        {
            //Initialisation de l'image
            if (this._BWImg != null)
                this._BWImg.Dispose();
            this._BWImg=new Bitmap(this._Width, this._Height, PixelFormat.Format1bppIndexed);
            BitmapData BWDat = this._BWImg.LockBits(new Rectangle(0, 0, this._Width, this._Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);

            //Allocation de la mémoire pour les erreurs
            IntPtr Erreurs = System.Runtime.InteropServices.Marshal.AllocHGlobal(((this._Height + 1) * this._Width + 1) * sizeof(int));

            //Calcule des donnée noir et blanc
            unsafe
            {
                byte CurBitMsk;
                int PointVal;
                int ErrToDispatch;
                byte* CurGrey = (byte*)this._GreyDat.ToPointer();
                int* CurErreur = (int*)Erreurs.ToPointer();
                int* CurErreur7 = &(CurErreur[1]);
                int* CurErreur1 = &(CurErreur[this._Width - 1]);
                int* CurErreur5 = &(CurErreur[this._Width]);
                int* CurErreur3 = &(CurErreur[this._Width + 1]);

                //initialisation des premiéres erreurs (les autres seront initialiser à la volée).
                for (int* LastErreur = &(((int*)Erreurs.ToPointer())[this._Width]); CurErreur <= LastErreur; CurErreur++)
                    *CurErreur = 0;
                CurErreur = (int*)Erreurs.ToPointer();

                Random Rnd = new Random();

                float LuminosityRatio = (float)((float)255/(float)(255 - Math.Abs(this._Luminosity)));
                byte LuminosityOffset = (this._Luminosity < 0) ? (byte)0 : (byte)this._Luminosity;

                //Table de précacule de la luminosité
                byte* LuminosityTab = stackalloc byte [255];
                for (int grayValue = 0; grayValue < 255; grayValue++)
                    LuminosityTab[grayValue] = (byte)(grayValue / LuminosityRatio + LuminosityOffset);

                for (int y = 0; y < this._Height; y++)
                {   
                    CurBitMsk = 128;// 1 << 7;
                    for (
                        byte* CurBWs = &(((byte*)BWDat.Scan0.ToPointer())[BWDat.Stride * y]),  //On ointe vers le premier octe de la ligne en cours.
                        afterLastGrey = &(((byte*)this._GreyDat.ToPointer())[(y+1)*this.Width]); //Borne de la ligne des niveaux de gris
                        //On parcourt la ligne courante
                        CurGrey < afterLastGrey;
                        //incrémentation des pointeurs
                        CurGrey++,
                        CurErreur++,
                        CurErreur7++,
                        CurErreur1++,
                        CurErreur5++,
                        CurErreur3++
                    )
                    {
                        //Calcul de la valeur du point
                        PointVal = LuminosityTab[*CurGrey] + *CurErreur + Rnd.Next(-25, 25);
                        
                        if(PointVal > 128)
                        {
                            //Enregistrement du point
                            *CurBWs |= CurBitMsk;
                            //Calcul de l'erreur
                            ErrToDispatch = PointVal - 255;
                        }
                        else
                        {
                            //Enregistrement du point
                            *CurBWs &=  (byte)(255 ^ CurBitMsk);
                            //Calcul de l'erreur
                            ErrToDispatch = PointVal;
                        }

                        //Diffusion de l'erreur
                        *CurErreur7 += ((ErrToDispatch * 7) >> 4);
                        *CurErreur1 += (ErrToDispatch >> 4);
                        *CurErreur5 += ((ErrToDispatch * 5) >> 4);
                        *CurErreur3 = ((ErrToDispatch * 3) >> 4); // = et pas += pour initialisé à la volée

                        //Initialisation des pointeurs et du masque de bit courant pour le point suivant
                        CurBitMsk >>= 1;
                        if (CurBitMsk == 0)
                        {
                            CurBitMsk = 128;//1 << 7;
                            CurBWs++;
                        }
                    }
                }
            }

            //Libération du tableau des erreurs
            System.Runtime.InteropServices.Marshal.FreeHGlobal(Erreurs);
            
            //Sauveguarde de l'image.
            this._BWImg.UnlockBits(BWDat);
        }

        private void Make_BWDat_Random()
        {
            //Initialisation de l'image
            if (this._BWImg != null)
                this._BWImg.Dispose();
            this._BWImg = new Bitmap(this._Width, this._Height, PixelFormat.Format1bppIndexed);
            BitmapData BWDat = this._BWImg.LockBits(new Rectangle(0, 0, this._Width, this._Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);

            //initialisation d'un Tableau de byte aléatoire.
            Byte[] rnds = new Byte[this._Width * this._Height];
            new Random().NextBytes(rnds);

            //Calcule des donnée noir et blanc
            unsafe
            {
                byte* CurBWs = (byte*)BWDat.Scan0.ToPointer();
                byte* CurGrey = (byte*)this._GreyDat.ToPointer();
                byte CurBitMsk;
                double LuminosityRatio = (255 - Math.Abs(this._Luminosity)) / 255.0;
                for (int y = 0; y < this._Height; y++)
                {
                    CurBitMsk = 128;// 1 << 7;
                    CurBWs = &(((byte*)BWDat.Scan0.ToPointer())[BWDat.Stride * y]);
                    for (int x = 0; x < this._Width; x++)
                    {                        
                        //Enregistrement du point
                        *CurBWs = (byte)((((*CurGrey * LuminosityRatio) + ((this._Luminosity < 0) ? (sbyte)0 : this._Luminosity)) > rnds[x + y * this._Width]) ? (*CurBWs | CurBitMsk) : (*CurBWs & (255 ^ CurBitMsk)));
                        
                        //Initialisation des pointeurs et du masque de bit courant pour le point suivant
                        CurBitMsk >>= 1;
                        if (CurBitMsk == 0)
                        {
                            CurBitMsk = 128; // 1 << 7;
                            CurBWs++;
                        }
                        CurGrey++;
                    }
                }
            }

            //Sauveguarde de l'image.
            this._BWImg.UnlockBits(BWDat);
        }

        private void Make_BWDat_HalfTone()
        {
            //Initialisation de l'image
            if (this._BWImg != null)
                this._BWImg.Dispose();
            this._BWImg = new Bitmap(this._Width, this._Height, PixelFormat.Format1bppIndexed);
            BitmapData BWDat = this._BWImg.LockBits(new Rectangle(0, 0, this._Width, this._Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);

            //Calcul des donnée noir et blanc
            unsafe
            {
                byte* CurBWs = (byte*)BWDat.Scan0.ToPointer();
                byte* CurGrey = (byte*)this._GreyDat.ToPointer();
                byte CurBitMsk;
                double LuminosityRatio = (255 - Math.Abs(this._Luminosity)) / 255.0;
                for (int y = 0; y < this._Height; y++)
                {
                    CurBitMsk = 1 << 7;
                    CurBWs = &(((byte*)BWDat.Scan0.ToPointer())[BWDat.Stride * y]);
                    for (int x = 0; x < this._Width; x++)
                    {
                        //Enregistrement du point
                        *CurBWs = (byte)((((*CurGrey * LuminosityRatio) + ((this._Luminosity < 0) ? (sbyte)0 : this._Luminosity)) > 128) ? (*CurBWs | CurBitMsk) : (*CurBWs & (255 ^ CurBitMsk)));

                        //Initialisation des pointeurs et du masque de bit courant pour le point suivant
                        CurBitMsk >>= 1;
                        if (CurBitMsk == 0)
                        {
                            CurBitMsk = 1 << 7;
                            CurBWs++;
                        }
                        CurGrey++;
                    }
                }
            }

            //Enregistrement des modification.
            this._BWImg.UnlockBits(BWDat);
        }


public void Make_GrayDat()
        {
            //On redimensionne l'image d'origine.
            Bitmap SizedImg = new Bitmap (this._OriginalImg ,this._Width,this._Height);

            //OnRécupére les données de l'image.
            BitmapData RGBDat = SizedImg.LockBits(new Rectangle(0, 0, this._Width, this._Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

            //On initialise le tableau de donnée.
            if (this._GreyDat != IntPtr.Zero)
            {
                System.Runtime.InteropServices.Marshal.ReAllocHGlobal(this._GreyDat,new IntPtr(this._Width * this._Height));
            }
            else
            {
                this._GreyDat = System.Runtime.InteropServices.Marshal.AllocHGlobal(this._Width * this._Height);
            }

            //On Recalcule les données de niveau de gris.
            unsafe
            {
                //tables de precalculs des multiplications pour le calcul du niveau de gris
                //Les tableaus sont créer dans le tas (+ rapide por les petits tableau)
                //ils sont libéré à la fin de la fonction.
                int* multiBleu = stackalloc int[256];
                int* multiVert = stackalloc int[256];
                int* multiRouge = stackalloc int[256];
                for (int i = 0; i < 256; i++)
                {
                    multiBleu[i] = 76 * i;
                    multiVert[i] = 151 * i;
                    multiRouge[i] = 28 * i;
                }

                byte* CurGrey = (byte*)this._GreyDat.ToPointer();
                for (int y = 0; y < this._Height; y++)
                {
                    //On pointe vers le début de la ligne
                    RGBPix* CurRGBDat = (RGBPix*)&(((byte*)RGBDat.Scan0.ToPointer())[y * RGBDat.Stride]);
                    //Balayage de la ligne
                    for (
                        // Calcul de la borne supérieur de la ligne
                        byte* afterLastGrey = &(((byte*)this._GreyDat.ToPointer())[(y+1)*this.Width]); //Borne de la ligne des niveaux de gris
                        //On Balaye toute la ligne
                        CurGrey < afterLastGrey; 
                        //On pointe vers les données suivantes
                        CurRGBDat++,
                        CurGrey++
                    )
                        *CurGrey = (byte)((multiBleu[CurRGBDat->B] + multiVert[CurRGBDat->G] + multiRouge[CurRGBDat->R]) >> 8);
                }
            }

            //On supprime les donnée en noir et blans pour forcer leur recalcule
            if (_BWImg != null)
            {
                this._BWImg.Dispose();
                this._BWImg=null;
            }

            //On libére les ressoure
            SizedImg.UnlockBits(RGBDat);
            SizedImg.Dispose();
        }
    }

 Conclusion

=============================================
Quel ques explications
===================================== ========

les compteurs:
---------------------

On remarque que les for correspondant au balayage des lignes n'utilise pas de compteur classique.
mais travaile directement sur les pointeurs.

En effet lorsque je balaye une ligne j'utilise un pointeur pour acceder au pixel courrant,
et j'incremente directement le pointeur pour acceder au pixel suivant, en effet
*PointVar est plus rapide que PointVar[x]
donc x n'a plus d'autre utilité que de compter le nombre de fois ou je vais répéter les opératon,

la démarche est de se demander comment supprimer x tous bonnement.

et le principe est simple :

Avant d'entrer dans la boucle ou au début de celle ci j'initialize PointVar
pour pointer sur le premier pixel de la ligne,
Dans le même temps je créer un second pointer BornePointVar qui pointe lui sur le dernier pixel de la ligne + 1 (ce n'est pas grave si il est hors de l'image ou même de la mémoire aloué car il ne serat jamais fais accé a la donnée sous jacente).

ca donne ca :
for(
    type* PointVar = AddressePremierPixelLigne,
    type* BornePointVar = AddresseDernierPixelLigne + 1;

    PointVar < BornePointVar;

    PointVar++
)
{
............
}


les masques de pixel :
---------------------

lors de laccés aux donnée d'une image noir et blanc les pixels sont sur chaque bit, il faut donc utilisé un masque de bit pour travailler au niveau de chaqu'un des pixel

la méthode la plus rapide que j'ai trouver est :

a la fin de la boucle for sur chaque pixels de la ligne :

avec CurBWs pointeur byte* sur les octets de la ligne,
et CurBitMsk byte


CurBitMsk >>= 1;
if (CurBitMsk == 0)
{
    CurBitMsk = 128;//1 << 7;
    CurBWs++;
}

bien entendu il faut avant de lire le premier pixel de la ligne initialiser le masque avec :
CurBitMsk = 128;//1 << 7;

ATTENTION la méthode de lecture de la ligne avec des bornes pointeur
n'est pas directement utilisable avec les images en noire et blanc pusique les donnée de pixel ne sont pas caller sur des octets.

mais dans le cas présent ce n'est pas un problème puisque les donnée sont lu depuis un tableau de byte des couleurs en niveaux de gris

============================================ ==========


Je mettrait a jour avec les conseil que j'aurrais retenue ainsi qu'avec d'autre partie du programme qui traite des images.

A bientôt...


 Historique

08 novembre 2006 17:02:39 :
Ajout d'une Photo, de commentaires et modifications mineur du code...
09 novembre 2006 14:22:08 :
Optimisation de l'algo Floyd et de l'algo de niveau de gris

 Sources du même auteur

Source avec Zip Source avec une capture Source .NET (Dotnet) "SURFACE LIKE" EN SILVERLIGHT
Source avec Zip Source .NET (Dotnet) BULKINSERT EN C#
Source avec Zip Source .NET (Dotnet) CONVERTIR EN NOIR ET BLANC AVEC IL

 Sources de la même categorie

Source avec Zip Source avec une capture Source .NET (Dotnet) WINDOWSGADGET LIKE par Frelon
Source avec Zip Source avec une capture Source .NET (Dotnet) USERCONTROL PLANNING / SEMAINE / JOURNÉE par yohan49
Source avec Zip Source avec une capture Source .NET (Dotnet) TEMPLATE MATCHING ET RECONNAISSANCE D'OBJETS AVEC OPENCV (EM... par boutemine
Source .NET (Dotnet) CALCULE D'UNE EXPRESSION MATHEMATIQUE PAR COMPILATION par yohan49
Source avec Zip Source avec une capture Source .NET (Dotnet) CALENDRIER TACTILE, SOUS FORME DE ROUES par Robert33

 Sources en rapport avec celle ci

Source avec Zip Source .NET (Dotnet) BALLON, CAREE ET IMAGE QUI TOURNENT, SE GONFLENT ET SE DGONF... par zertyx
Source avec Zip Source .NET (Dotnet) PUZZLE 4X4 par jrscofield
Source avec Zip SILVERLIGHT 4: BOUTON À 3 IMAGES par BumpMANN
Source avec Zip Source .NET (Dotnet) CONVERTIR EN NOIR ET BLANC AVEC IL par Malkuth
Source avec Zip Source avec une capture Source .NET (Dotnet) EFFET DE FLOU ET NOIR ET BLANC SUR UNE IMAGE. par yoannd

Commentaires et avis

Commentaire de Malkuth le 08/11/2006 02:43:41

Sorry
En fait le traitement en noir et blanc a été traiter dans cette source : par une autre méthode que je mettrais sans doute en plus des autres déjà présente.

http://www.csharpfr.com/codes/IMAGES-DITHERING-MOTIF_30132.aspx

toutefois l'algo de cette source transphorme l'image en conservant le format de couleur 32bit, dans le code présenter ci dessus on obtient une image  de 1 bit par pixel (nécessaire pour souver sous forme d'un tiff multipage CCIT4 pour la compatibilité avec les carte Fax de Eicon (et sans doute d'autre mais je les connait pas!!!).

Commentaire de Malkuth le 08/11/2006 17:13:41

Les gros carrés sur l'image de présentation c'est du a la compression Jpeg de l'image...

Commentaire de Patrice99 le 09/11/2006 10:10:48

En JPeg2000, les copies d'écran ne sont pas dégradées : il suffit d'enregistrer au format .png puis de renommer en .jpg

 Ajouter un commentaire


Discussions en rapport avec ce code source dans le forum

extraction d'une zone d'une image [ par wenna ] salut je cherche un code c# qui permet d'extraire une zone à partir d'une image.l'image est constutiée des zones où le couleur des pixels sont noir et SetPixel transparent [ par amlb ] Bonjour,mon probl&#232;me est le suivant: je traite une image Bitmap et je veux pouvoir transformer tous les pixels blanc de cette image en pixel tran comment enlever le fond blanc d'une image avec visual c# [ par ami7 ] Salut à tous, voilà j'ai ajouter à mon application un bouton , j'ai changé la propriété Image de ce dernier mais le bouton parait une image a un fon Comment attribué un entier(variable) dans le nom d'un Button? [ par darkdog85 ] Bonjour, Je ne sais pas si mon titre est très clair alors je vais directement passé a mon exemple : [code=cs] int i; for (i=1;i < 11;i++) { button Afficher image BMP d'uni fichier XML [ par thib89 ] Bonsoir, Excuser moi de vous déranger, si quelqu'un pouvais m'aider se serait vraiment bienvenu. Je programme sous VS 2010 en C#. J'ai un fichier XM comment dessiner des objets graphiques sur une image [ par ami7 ] bonsoir, j'utilise un code c# qui permet de dessiner des objets ghraphiques (rectangle , ellipse, ligne...) le question c'est que je veut tout d'abord Trouver tous les pixels noire dans une image binaire trés grande [ par issam414 ] Bonjour à tous, je débute dans la programmation en c# et je suis déjà perdu, pourtant ça me parait simple comme question [^^peur] . alors, j'ai une i Application du modèle de Markov en utlisant logistic Map [ par chattachat ] Salut à tous .Mon problème est comment crypter une image à l'aide de modèle de markov premier ordre en utilisant une fonction logistique Chaos . Ce te Definir le chemin d'une pictureBox dans le code [ par ahorel ] Bonjour, Je remercie les personnes qui m'ont aidé pour insérer les images dans mon windows form. J'utilise ce chemin pour les insérer: string imgPat Extraction d'images et de pages - PDF [ par mbeditions ] Bonjour à tous, Je développe actuellement un logiciel dont l'une des fonctionnalités est l'extraction des photos contenues dans un fichier PDF. Parti


Nos sponsors


Sondage...

CalendriCode

Février 2012
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
272829    

Consulter la suite du CalendriCode

Photothèque

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 5,195 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales