2010-02-15 29 views
46

¿Existe alguna manera de convertir una imagen a escala de grises en 16 píxeles por formato de bit, en lugar de configurar cada uno de los componentes r, gyb como luminiscencia? Actualmente tengo un bmp del archivo.Convierta una imagen a escala de grises

Bitmap c = new Bitmap("filename"); 

Quiero un mapa de bits d, que es una versión en escala de grises de c. Veo un constructor que incluye System.Drawing.Imaging.PixelFormat, pero no entiendo cómo usarlo. Soy nuevo en el procesamiento de imágenes y en las bibliotecas relevantes de C#, pero tengo una experiencia moderada con C#.

Se agradecerá cualquier ayuda, referencia a una fuente en línea, pista o sugerencia.

Gracias.

EDITAR: d es la versión en escala de grises de c.

Respuesta

56

"Quiero un mapa de bits D, que es en escala de grises. veo una consructor que incluye System.Drawing.Imaging.PixelFormat, pero no entiendo cómo utilizar eso."

Aquí es cómo hacer esto

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

EDIT: Para convertir a escala de grises

   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 

versión más rápida de switchonthecode enlace de seguimiento para el análisis completo:

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 
    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 
    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); 

    //dispose the Graphics object 
    g.Dispose(); 
    return newBitmap; 
} 
+0

Lo siento, debería haber declarado que en mi pregunta que quiero la versión en escala de grises de mi mapa de bits original, he editado la publicación para reflejar esto. – 0fnt

+11

Este método (píxel por píxel es demasiado lento) consulte este artículo aquí: http: //www.switchonthecode.com/tutorials/csharp-tutorial-convert-a-color-image-to-grayscale – Luis

+6

También, el píxel por el método de píxeles solo usaba el valor Rojo .... – mpen

27
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 esta manera también mantiene el canal alfa.
Disfruta.

+4

¿Por qué obtuve un voto a favor? Esta respuesta está perfectamente bien y sobre el tema. – Vercas

+1

Sé que es una respuesta antigua, pero ¿podría explicar las constantes que multiplica en los valores R, G, B? Veo que resume a "1.0", pero ¿hay alguna explicación de por qué? –

+3

@LarsKristensen Vea esto: https://en.wikipedia.org/wiki/Grayscale – lukegravitt

6

Ninguno de los ejemplos anteriores crea imágenes de mapa de bits de 8 bits (8bpp). Algunos software, como el procesamiento de imágenes, solo son compatibles con 8bpp. Desafortunadamente, las bibliotecas MS .NET no tienen una solución. El formato PixelFormat.Format8bppIndexed parece prometedor, pero después de muchos intentos no pude hacerlo funcionar.

Para crear un verdadero archivo de mapa de bits de 8 bits, debe crear el proper headers. Finalmente encontré la solución Grayscale library para crear archivos de mapa de bits de 8 bits (BMP). El código es muy simple:

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

el código para este proyecto está lejos de ser bonita, pero funciona, con un pequeño problema sencillo de solución. El autor codificó la resolución de la imagen a 10x10. A los programas de procesamiento de imágenes no les gusta esto. La solución está abierta GrayBMP_File.cs (sí, nombres de archivos funky, lo sé) y reemplaza las líneas 50 y 51 con el código siguiente. El ejemplo establece la resolución en 200x200 pero debe cambiarla al número correcto.

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

Me gustaría probarlo y subirlo de categoría, pero tengo poco tiempo en este momento. Gracias por la respuesta sin embargo. – 0fnt

+0

el truco con 8bpp es que necesita editar la matriz interna sin formato que respalda la imagen. Puedes obtenerlo llamando 'image.LockBits()' y luego copiando adentro/afuera usando 'Marshal.Copy'. Google para obtener el proceso completo. Observe que el paso de una imagen (una línea leída a partir de los datos) a menudo es más largo que el ancho real, ya que se redondea al múltiplo más cercano de 4 bytes. – Nyerguds

6

Para resumir algunos artículos aquí: Hay algunas opciones de píxel a píxel que, siendo sencillo simplemente no son rápidos.

@Luis 'comentario que une a: (archivado) https://web.archive.org/web/20110827032809/http://www.switchonthecode.com/tutorials/csharp-tutorial-convert-a-color-image-to-grayscale es excelente.

Se ejecuta a través de tres opciones diferentes e incluye los tiempos para cada uno.

+3

El tercer ejemplo en el enlace de arriba es super eficiente y resolvió directamente mi problema – ford

+0

Tristemente ese enlace ahora está muerto ... –

+3

@RichardEverett Indeed. ¡Archivo web al rescate! Fijo. – jeffreypriebe

3

El código siguiente es la solución más simple:

Bitmap bt = new Bitmap("imageFilePath"); 

for (int y = 0; y < bt.Height; y++) 
{ 
    for (int x = 0; x < bt.Width; x++) 
    { 
     Color c = bt.GetPixel(x, y); 

     int r = c.R; 
     int g = c.G; 
     int b = c.B; 
     int avg = (r + g + b)/3; 
     bt.SetPixel(x, y, Color.FromArgb(avg,avg,avg)); 
    } 
} 

bt.Save("d:\\out.bmp"); 
9

Hay un método estático en ToolStripRenderer clase, llamada CreateDisabledImage. Su uso es tan simple como:

Bitmap c = new Bitmap("filename"); 
Image d = ToolStripRenderer.CreateDisabledImage(c); 

Utiliza una matriz diferente poco que el de la respuesta aceptada y, además, lo multiplica por una transparencia de valor de 0,7, por lo que el efecto es ligeramente diferente que sólo en escala de grises, pero si solo quiere que su imagen se vea gris, es la mejor y más simple solución.

+2

Oh hombre, gracias por esto. Esto concuerda con el aspecto de las imágenes dentro de los controles desactivados en WinForms, lo que mantiene todo en constante coherencia. – Jimmy

Cuestiones relacionadas