2012-07-13 22 views
7

Estoy tratando de guardar una imagen como monocromática (negro & blanco, 1 bit de profundidad) pero estoy perdiendo la manera de hacerlo.Convirtiendo un mapa de bits a monocromo

Estoy empezando con un png y convirtiéndolo en un mapa de bits para imprimir (es una impresora térmica y solo admite negro de todos modos, además de lento para las imágenes grandes si intento enviarlas como color/escala de grises).

Mi código hasta ahora es muy fácil de convertir a un mapa de bits, pero conserva la profundidad de color original.

Image image = Image.FromFile("C:\\test.png"); 

byte[] bitmapFileData = null; 
int bitsPerPixel = 1; 
int bitmapDataLength; 

using (MemoryStream str = new MemoryStream()) 
{ 
    image.Save(str, ImageFormat.Bmp); 
    bitmapFileData = str.ToArray(); 
} 
+0

http://stackoverflow.com/questions/4669317/how-to-convert-a-bitmap-image-to-black-and-white-in-c – Dmitriy

+0

posible duplicado de [convertir una imagen a Negro -Blanco o Sepia en C#] (http://stackoverflow.com/questions/4624998/convert-image-to-black-white-or-sepia-inc-c-sharp) – ken2k

+1

En realidad, me parece que esas preguntas son sobre la conversión a escala de grises, mientras que el OP quiere convertirlo a 1 monocromo BPP, que implica el umbral/dithering. – Ani

Respuesta

10

Aquí hay un código que reúno para obtener una imagen a todo color (24 bits/píxel), convertirlo en un mapa de bits de salida de 1 bit/píxel, aplicar una conversión RGB estándar a escala de grises y luego usar Floyd-Steinberg para convierte la escala de grises en la salida de 1 bit/píxel.

Tenga en cuenta que esto de ninguna manera debe considerarse una implementación "ideal", pero funciona. Hay una serie de mejoras que podrían aplicarse si quisiera. Por ejemplo, copia toda la imagen de entrada en la matriz data, mientras que realmente solo necesitamos mantener dos líneas en la memoria (las líneas "actual" y "siguiente") para acumular los datos de error. A pesar de esto, el rendimiento parece aceptable.

public static Bitmap ConvertTo1Bit(Bitmap input) 
{ 
    var masks = new byte[] { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; 
    var output = new Bitmap(input.Width, input.Height, PixelFormat.Format1bppIndexed); 
    var data = new sbyte[input.Width, input.Height]; 
    var inputData = input.LockBits(new Rectangle(0, 0, input.Width, input.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); 
    try 
    { 
     var scanLine = inputData.Scan0; 
     var line = new byte[inputData.Stride]; 
     for (var y = 0; y < inputData.Height; y++, scanLine += inputData.Stride) 
     { 
      Marshal.Copy(scanLine, line, 0, line.Length); 
      for (var x = 0; x < input.Width; x++) 
      { 
       data[x, y] = (sbyte)(64 * (GetGreyLevel(line[x * 3 + 2], line[x * 3 + 1], line[x * 3 + 0]) - 0.5)); 
      } 
     } 
    } 
    finally 
    { 
     input.UnlockBits(inputData); 
    } 
    var outputData = output.LockBits(new Rectangle(0, 0, output.Width, output.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed); 
    try 
    { 
     var scanLine = outputData.Scan0; 
     for (var y = 0; y < outputData.Height; y++, scanLine += outputData.Stride) 
     { 
      var line = new byte[outputData.Stride]; 
      for (var x = 0; x < input.Width; x++) 
      { 
       var j = data[x, y] > 0; 
       if (j) line[x/8] |= masks[x % 8]; 
       var error = (sbyte)(data[x, y] - (j ? 32 : -32)); 
       if (x < input.Width - 1) data[x + 1, y] += (sbyte)(7 * error/16); 
       if (y < input.Height - 1) 
       { 
        if (x > 0) data[x - 1, y + 1] += (sbyte)(3 * error/16); 
        data[x, y + 1] += (sbyte)(5 * error/16); 
        if (x < input.Width - 1) data[x + 1, y + 1] += (sbyte)(1 * error/16); 
       } 
      } 
      Marshal.Copy(line, 0, scanLine, outputData.Stride); 
     } 
    } 
    finally 
    { 
     output.UnlockBits(outputData); 
    } 
    return output; 
} 

public static double GetGreyLevel(byte r, byte g, byte b) 
{ 
    return (r * 0.299 + g * 0.587 + b * 0.114)/255; 
} 
4

Lo que queremos es un buen algoritmo de interpolación como Floyd-Steinberg o Bayer ordered. Puede implementar la binarización usted mismo o utilizar una biblioteca como AForge.NET para hacerlo por usted (descargue las muestras de procesamiento de imágenes). Puede encontrar la documentación de binarización here.

Cuestiones relacionadas