2011-07-26 11 views
3

8ビットまたは16ビットのグレースケールピクセルデータを、.NETフレームワークがサポートできるファイル形式に変換できる必要があります。C# - 8ビットまたは16ビットのグレースケール生のピクセルデータを変換する

利用可能なデータは、幅、高さ、向き(左下)、ピクセルあたり2バイトでパックされた4096階調のグレー(12ビット解像度)です。

たとえば、各ピクセルの範囲は0〜4096で、各ピクセルは2バイトです。

BitmapコンストラクタでPixelFormat.Format16bppGrayScaleを使用しようとしましたが、GDI +例外がスローされています。私が読んだことはすべて、この形式はサポートされておらず、MSDNが間違っていると言います。

できるだけイメージの品質を損なうことなく、このピクセルバッファを.NETビットマップ形式(Format32bppArgbなど)に変換します。

誰でも知っていますか?

+0

ビットマップを作成して再現するだけで、PNG形式で保存できるのはなぜですか?おそらくそれは難しいようには聞こえません。仕事の時間はおそらく、おそらく。 –

+0

何と一緒にそれを再現しますか?あなたは精緻化できますか? –

+0

イメージを再現する必要がある場所で各ピクセルを描画します。 –

答えて

6

ルックアップテーブル(LUT)を事前計算し、それを使用して各ピクセルを変換する以下の例を参照してください。このバージョンは12ビットのケースをカバーしています。 8ビットの場合、コードは非常に似ていますが、ピクセル形式を超えて一般化することは困難です。

12ビットGSから効果的な8ビットGSに変換するとデータが失われます。しかし、LUTテーブルを調整して、コントラストをより細かくした入力値に焦点を当てることができます(例:DICOM Window Center/Window Width)。

class Program 
{ 
    static void Main(string[] args) 
    { 
     // Test driver - create a Wedge, convert to Bitmap, save to file 
     // 
     int width = 4095; 
     int height = 1200; 
     int bits = 12; 

     byte[] wedge = Wedge(width, height, bits); 

     Bitmap bmp = Convert(wedge, width, height, bits); 

     string file = "wedge.png"; 

     bmp.Save(file); 

     Process.Start(file); 
    } 

    static Bitmap Convert(byte[] input, int width, int height, int bits) 
    { 
     // Convert byte buffer (2 bytes per pixel) to 32-bit ARGB bitmap 

     var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); 

     var rect = new Rectangle(0, 0, width, height); 

     var lut = CreateLut(bits); 

     var bitmap_data = bitmap.LockBits(rect, ImageLockMode.WriteOnly, bitmap.PixelFormat); 

     ConvertCore(width, height, bits, input, bitmap_data, lut); 

     bitmap.UnlockBits(bitmap_data); 

     return bitmap; 
    } 

    static unsafe void ConvertCore(int width, int height, int bits, byte[] input, BitmapData output, uint[] lut) 
    { 
     // Copy pixels from input to output, applying LUT 

     ushort mask = (ushort)((1 << bits) - 1); 

     int in_stride = output.Stride; 
     int out_stride = width * 2; 

     byte* out_data = (byte*)output.Scan0; 

     fixed (byte* in_data = input) 
     { 
      for (int y = 0; y < height; y++) 
      { 
       uint* out_row = (uint*)(out_data + (y * in_stride)); 

       ushort* in_row = (ushort*)(in_data + (y * out_stride)); 

       for (int x = 0; x < width; x++) 
       { 
        ushort in_pixel = (ushort)(in_row[ x ] & mask); 

        out_row[ x ] = lut[ in_pixel ]; 
       } 
      } 
     } 
    } 

    static uint[] CreateLut(int bits) 
    { 
     // Create a linear LUT to convert from grayscale to ARGB 

     int max_input = 1 << bits; 

     uint[] lut = new uint[ max_input ]; 

     for (int i = 0; i < max_input; i++) 
     { 
      // map input value to 8-bit range 
      // 
      byte intensity = (byte)((i * 0xFF)/max_input); 

      // create ARGB output value A=255, R=G=B=intensity 
      // 
      lut[ i ] = (uint)(0xFF000000L | (intensity * 0x00010101L)); 
     } 

     return lut; 
    } 

    static byte[] Wedge(int width, int height, int bits) 
    { 
     // horizontal wedge 

     int max = 1 << bits; 

     byte[] pixels = new byte[ width * height * 2 ]; 

     for (int y = 0; y < height; y++) 
     { 
      for (int x = 0; x < width; x++) 
      { 
       int pixel = x % max; 

       int addr = ((y * width) + x) * 2; 

       pixels[ addr + 1 ] = (byte)((pixel & 0xFF00) >> 8); 
       pixels[ addr + 0 ] = (byte)((pixel & 0x00FF)); 
      } 
     } 

     return pixels; 
    } 
} 
0

2つの方法:

  • 使用Bitmap constructor任意のバッファを指しています。これには、ビットマップが配置されるまでバッファを保持する必要がありますが、メモリ内のビットマップデータを不必要にコピーしないようにします。
  • LockBits methodを使用して、ビットマップのデータへのポインタを取得できます。この場合、希望の寸法とフォーマットで通常どおりBitmapを構築します。その後、LockBitsを呼び出してビットマップデータをバッファにコピーします。これは遅くなりますが、データがBitmapコンストラクタが直接受け入れることができる形式でないため、何らかのカスタム変換が必要な場合には必要です。
+0

ピクセルデータをそのままコピーすることはできません。Bitmapコンストラクタでは、PixelFormatを指定する必要があり、ソースピクセル形式はサポートされていません。実際のピクセルの色情報を12ビットグレースケールから24ビットまたは32ビットRGBに変換する必要があります。理想的には品質の低下なし。 –

+0

次に、LockBitsを使用します。それはあなたが必要とするものを正確に行うのに役立ちます。ただし、品質は低下します:変換する両方のピクセル形式は、チャネルごとに8ビットしかありません。ピクセルあたり12ビットのうち4ビットを失うことになります。完全な品質を維持するのに多くの困難があるかもしれません:http://msdn.microsoft.com/en-us/library/system.drawing.imaging.pagingelformat.aspxは "PixelFormat48bppRGB、[...]は16ビットを使用します。 ..チャンネルGDI +バージョン1.0と1.1では、チャンネルごとに16ビットの画像を読み取ることができますが、そのような画像は処理、表示、および保存のためにチャンネルごとの8ビット形式に変換されます。 –

+0

私は既にLockBitsを使用しようとしています。 LockBitsは変換を行いません。私は8ビットのグレースケールバイトを24ビットRGBバイトに変換するアルゴリズムを書く必要があります。 –

1

偽装16bのフォーマット&使用ColorMatrixを正しく表示する前にそれをマップします。

私はこのアプローチのパフォーマンステストをWindowsではなく、効率的なメモリストレージと、12bまたは16bデータのさまざまな範囲の迅速な再マッピングが必要な他のプラットフォーム(Androidなど)で使用しましたこの技術の

私の12/16bグレースケールデータは実際にはRGB565なので、それは幸せなシリアル化であり、&のその他の操作をデシリアライズすることができます。私が表示する必要があるときは、適切なウィンドウをARGB8888の8bグレースケールにマップするColorMatrixに渡します。

誰かがこれを試したいと思えば、私はマッピングアルゴリズムを投稿します。

関連する問題