2011-07-26 7 views
3

8 비트 또는 16 비트 회색 음영 픽셀 데이터를 .NET Framework에서 지원할 수있는 파일 형식으로 변환 할 수 있어야합니다.C# - 8 비트 또는 16 비트 회색조 원시 픽셀 데이터 변환

사용할 수있는 데이터는 너비, 높이, 방향 (왼쪽 하단) 및 픽셀 당 2 바이트로 채워진 4096 회색 음영 (12 비트 해상도)의 픽셀 형식입니다.

예를 들어 각 픽셀의 범위는 0에서 4096까지이며 각 픽셀은 2 바이트입니다.

Bitmap 생성자와 함께 이미 PixelFormat.Format16bppGrayScale을 사용해 보았는데 GDI + 예외가 발생합니다. 내가 읽은 모든 것은이 형식이 지원되지 않으며 MSDN이 잘못되었다고 말합니다.

가능한 한 적은 화질 손실로이 픽셀 버퍼를 .NET Bitmap 형식 (예 : Format32bppArgb)으로 변환하려고합니다.

누구나 알고 계십니까?

+0

왜 비트 맵을 만들고 재현하면 PNG로 저장할 수 있습니까? 그것이 어려울 것 같은 소리하지 않습니다, 아마도 일하는 시간, 아마도. –

+0

무엇으로 그것을 재현? 당신은 정교 할 수 있습니까? –

+0

이미지를 재현하는 데 필요한 각 픽셀을 그립니다. –

답변

6

룩업 테이블 (LUT)을 사전 계산하고 각 픽셀을 변환하는 데 사용하는 아래 예제를 참조하십시오. 이 버전은 12 비트 케이스를 다루고 있습니다. 8 비트의 경우 코드는 매우 유사하지만 픽셀 형식을 통해 일반화하기는 어렵습니다.

12 비트 GS에서 효과적으로 8 비트 GS로 변환하면 데이터가 손실됩니다. 그러나 더 나은 대비 (예 : DICOM Window Center/Window Width)로 입력 범위의 작은 범위에 초점을 맞추기 위해 LUT 표를 조정할 수 있습니다.

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

두 가지 방법 : 임의의 버퍼를 가리키는

  • 사용 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.pixelformat.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를 통해 전달합니다.

누구나이 도구를 사용해보고 싶다면 매핑 알고리즘을 게시 할 것입니다.

관련 문제