64 votes

Convertir une image en niveaux de gris

Existe-t-il un moyen de convertir une image en niveaux de gris au format 16 bits par pixel, plutôt que de régler chacune des composantes r, g et b sur la luminance. J'ai actuellement un fichier bmp.

Bitmap c = new Bitmap("filename");

Je veux un Bitmap d, qui est une version en niveaux de gris de c. Je vois un constructeur qui inclut System.Drawing.Imaging.PixelFormat, mais je ne comprends pas comment l'utiliser. Je suis nouveau dans le domaine du traitement d'images et des bibliothèques C# correspondantes, mais j'ai une expérience modérée du C# lui-même.

Toute aide, référence à une source en ligne, astuce ou suggestion sera appréciée.

EDIT : d est la version en niveaux de gris de c.

84voto

Asad Butt Points 8989

"Je veux un Bitmap d, qui est en niveaux de gris. Je vois un constructeur qui inclut System.Drawing.Imaging.PixelFormat, mais je ne comprends pas comment l'utiliser cela."

Voici comment procéder

Bitmap grayScaleBP = new 
         System.Drawing.Bitmap(2, 2, System.Drawing.Imaging.PixelFormat.Format16bppGrayScale);

EDIT : Pour convertir en niveaux de gris

             Bitmap c = new Bitmap("fromFile");
             Bitmap d;
             int x, y;

             // Loop through the images pixels to reset color.
             for (x = 0; x < c.Width; x++)
             {
                 for (y = 0; y < c.Height; y++)
                 {
                     Color pixelColor = c.GetPixel(x, y);
                     Color newColor = Color.FromArgb(pixelColor.R, 0, 0);
                     c.SetPixel(x, y, newColor); // Now greyscale
                 }
             }
            d = c;   // d is grayscale version of c  

Version plus rapide de commutateur sur le code Suivez le lien pour une analyse complète :

public static Bitmap MakeGrayscale3(Bitmap original)
{
   //create a blank bitmap the same size as original
   Bitmap newBitmap = new Bitmap(original.Width, original.Height);

   //get a graphics object from the new image
   using(Graphics g = Graphics.FromImage(newBitmap)){

       //create the grayscale ColorMatrix
       ColorMatrix colorMatrix = new ColorMatrix(
          new float[][] 
          {
             new float[] {.3f, .3f, .3f, 0, 0},
             new float[] {.59f, .59f, .59f, 0, 0},
             new float[] {.11f, .11f, .11f, 0, 0},
             new float[] {0, 0, 0, 1, 0},
             new float[] {0, 0, 0, 0, 1}
          });

       //create some image attributes
       using(ImageAttributes attributes = new ImageAttributes()){

           //set the color matrix attribute
           attributes.SetColorMatrix(colorMatrix);

           //draw the original image on the new image
           //using the grayscale color matrix
           g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height),
                       0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes);
       }
   }
   return newBitmap;
}

0 votes

Je suis désolé, j'aurais dû préciser dans ma question que je veux la version en niveaux de gris de mon bitmap d'origine ; j'ai modifié mon message pour le refléter.

11 votes

Cette méthode (pixel par pixel est trop lente) consultez cet article ici : switchonthecode.com/tutorials/

1 votes

Comment modifier cette méthode afin de prendre en compte uniquement les valeurs RVB et non la transparence ? Merci

37voto

Vercas Points 3444
Bitmap d = new Bitmap(c.Width, c.Height);

for (int i = 0; i < c.Width; i++)
{
    for (int x = 0; x < c.Height; x++)
    {
        Color oc = c.GetPixel(i, x);
        int grayScale = (int)((oc.R * 0.3) + (oc.G * 0.59) + (oc.B * 0.11));
        Color nc = Color.FromArgb(oc.A, grayScale, grayScale, grayScale);
        d.SetPixel(i, x, nc);
    }
}

De cette façon, il conserve également le canal alpha.
Profitez-en.

3 votes

Je sais qu'il s'agit d'une vieille réponse, mais pourriez-vous préciser les constantes que vous multipliez sur les valeurs R, G, B ? Je vois que la somme est de "1,0", mais y a-t-il une explication à cela ?

0 votes

@lukegravitt, Merci ! :)

0 votes

Maintenant, après l'avoir utilisé moi-même, je dois ajouter que c'est une mauvaise idée de l'utiliser pour les petites icônes handicapées ou dans tous les cas où la différence doit être remarquée. Le résultat en niveaux de gris est terriblement proche de celui en couleur... Difficile à distinguer.

7voto

Brent Matzelle Points 1604

Aucun des exemples ci-dessus ne crée d'images bitmap de 8 bits (8bpp). Certains logiciels, comme le traitement d'images, ne prennent en charge que le 8bpp. Malheureusement, les bibliothèques MS .NET n'ont pas de solution. Le site PixelFormat.Format8bppIndexed semble prometteur mais après de nombreuses tentatives, je n'ai pas réussi à le faire fonctionner.

Pour créer un véritable fichier bitmap 8 bits, vous devez créer le fichier des en-têtes appropriés . Finalement, j'ai trouvé le Bibliothèque en niveaux de gris solution pour la création de fichiers bitmap (BMP) 8 bits. Le code est très simple :

Image image = Image.FromFile("c:/path/to/image.jpg");
GrayBMP_File.CreateGrayBitmapFile(image, "c:/path/to/8bpp/image.bmp");

Le code de ce projet est loin d'être joli mais il fonctionne, avec un petit problème simple à résoudre. L'auteur a codé en dur la résolution de l'image à 10x10. Les programmes de traitement d'images n'aiment pas cela. La solution est d'ouvrir GrayBMP_File.cs (ouais, nom de fichier funky, je sais) et de remplacer les lignes 50 et 51 par le code ci-dessous. L'exemple fixe la résolution à 200x200 mais vous devez la changer pour le nombre approprié.

int resX = 200;
int resY = 200;
// horizontal resolution
Copy_to_Index(DIB_header, BitConverter.GetBytes(resX * 100), 24);
// vertical resolution 
Copy_to_Index(DIB_header, BitConverter.GetBytes(resY * 100), 28);

0 votes

J'aimerais le tester et l'upvoter, mais j'ai peu de temps pour le moment. Merci quand même pour la réponse.

0 votes

L'astuce avec 8bpp est que vous devez éditer le tableau interne brut qui soutient l'image. Vous pouvez l'obtenir en appelant image.LockBits() puis de copier les données à l'aide de la fonction Marshal.Copy . Google pour obtenir le processus complet. Notez que la largeur d'une image (une ligne lue à partir des données) est souvent plus longue que la largeur réelle, car elle est arrondie au multiple le plus proche de 4 octets.

6voto

jeffreypriebe Points 1070

Pour résumer quelques éléments ici : Il existe des options pixel par pixel qui, tout en étant simples, ne sont pas rapides.

Le commentaire de @Luis est lié à : (archivé) https://web.archive.org/web/20110827032809/http://www.switchonthecode.com/tutorials/csharp-tutorial-convert-a-color-image-to-grayscale est superbe.

Il passe en revue trois options différentes et indique les délais pour chacune d'elles.

3 votes

Le troisième exemple dans le lien ci-dessus est super efficace et a directement résolu mon problème

3 votes

@RichardEverett En effet. Les archives web à la rescousse ! Corrigé.

0voto

Simon Linder Points 1832

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X