2012-07-13 27 views
7

Sto tentando di salvare un'immagine come monocromatica (nero & bianco, profondità di 1 bit) ma sto arrivando perduto come farlo.Conversione di una bitmap in monocromatica

Sto iniziando con un png e la conversione in un bitmap per la stampa (è una stampante termica e supporta solo il nero in ogni caso - più lento per le immagini grandi se provo a inviarli come colore/scala di grigi).

Il mio codice fino ad ora è semplicemente semplice convertirlo in una bitmap, ma mantiene la profondità del colore originale.

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

possibile duplicato [convertire immagini in nero -White o Seppia in C#] (http://stackoverflow.com/questions/4624998/convert-image-to-black-white-or-sepia-in-c-sharp) – ken2k

+1

In realtà, mi sembra che quelle domande siano riguardo alla conversione in scala di grigi - mentre l'OP vuole convertirlo in 1 monocromio BPP, che implica la soglia/dithering. – Ani

risposta

10

Ecco un codice che ho messo insieme che prende un'immagine a colori (24 bit/pixel) e la converte in una bitmap di uscita a 1 bit/pixel, applicando una conversione da RGB a scala di grigi standard e quindi utilizzando Floyd-Steinberg per convertire la scala di grigi nell'output a 1 bit/pixel.

Si noti che questo non deve essere considerato un'implementazione "ideale", ma funziona. Ci sono una serie di miglioramenti che potrebbero essere applicati se lo si desidera. Ad esempio, copia l'intera immagine di input nell'array data, mentre abbiamo solo bisogno di tenere due righe in memoria (le righe "corrente" e "successiva") per accumulare i dati di errore. Nonostante questo, le prestazioni sembrano accettabili.

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

Ciò che si vuole è un buon algoritmo di dithering come Floyd-Steinberg o Bayer ordered. Puoi implementare tu stesso la binarizzazione o utilizzare una libreria come AForge.NET per farlo per te (scarica gli esempi di elaborazione delle immagini). È possibile trovare la documentazione di binarizzazione here.

Problemi correlati