2012-07-13 35 views
7

イメージをモノクロ(黒の&白、1ビット深度)として保存しようとしていますが、やり方が分かりません。ビットマップをモノクロに変換する

私はpngで始まり、印刷用のビットマップに変換しています(これはサーマルプリンタであり、とにかく黒のみをサポートしています。また、カラー/グレースケールとして送信しようとすると大きな画像では遅くなります)。

これまでのところ、私のコードはビットマップに変換するのは簡単ではありませんが、元の色深度はそのままです。何をしたい

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

可能重複-Whiteまたはセピアc#](http://stackoverflow.com/questions/4624998/convert-image-to-black-white-orse-sepia-in-c-sharp) – ken2k

+1

実際には、それらの質問は、グレースケールに変換することについて説明していますが、OPでは1 BPPモノクロに変換したいと考えていますが、これにはしきい値/ディザリングが含まれています。 – Ani

答えて

10

フルカラー(24ビット/ピクセル)の画像を取り込んで1ビット/ピクセル出力ビットマップに変換し、標準RGBをグレースケール変換に適用し、Floyd-Steinbergを使用してグレースケールを1ビット/ピクセル出力に変換します。

これは決して「理想的な」実装とは見なされませんが、機能することに注意してください。必要に応じて適用可能ないくつかの改善点があります。たとえば、入力画像全体をdata配列にコピーしますが、実際には、エラーデータを累積するために2行( "現在"と "次"の行)をメモリに保存するだけです。それにもかかわらず、パフォーマンスは受け入れられるようです。

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

Floyd-SteinbergまたはBayer orderedのような良いディザリングアルゴリズムです。あなた自身で二進化を実装するか、AForge.NETのようなライブラリを使ってやることができます(画像処理サンプルをダウンロードしてください)。二進化のドキュメントhereを見つけることができます。

関連する問題