2010-04-24 4 views
6

C#을 사용하고 이미지를 Bitmap 객체에 저장하는 중입니다.C#에서 비트 맵 비트 크기 줄이기

이제이 이미지를 8 비트 그레이 스케일로 변환 한 다음 4 비트 그레이 스케일 이미지로 변환하고 싶습니다.

어떻게 만들 수 있는지 알려주시겠습니까?

답변

6

.NET 비트 맵 형식에서는 8 비트 또는 4 비트 회색 명암 이미지가 없습니다. 지원되는 형식은 PixelFormat enumeration에 의해 열거됩니다. 그러나 팔레트의 각 항목은 그레이 스케일 값인 인덱싱 된 이미지 (8bppIndexed 또는 4bppIndexed)를 만들어 4 비트 또는 8 비트 이미지를 만들 수 있습니다.

이 코드는 비트 맵을 받아 그레이 스케일 값으로 8bpp를 인덱스 이미지로 복사본을 생성합니다 : 대신 4Bpp 이미지를 만들기 위해

public static Bitmap BitmapToGrayscale(Bitmap source) 
    { 
     // Create target image. 
     int width = source.Width; 
     int height = source.Height; 
     Bitmap target = new Bitmap(width,height,PixelFormat.Format8bppIndexed); 
     // Set the palette to discrete shades of gray 
     ColorPalette palette = target.Palette;    
     for(int i = 0 ; i < palette.Entries.Length ; i++) 
     {     
      palette.Entries[i] = Color.FromArgb(0,i,i,i); 
     } 
     target.Palette = palette; 

     // Lock bits so we have direct access to bitmap data 
     BitmapData targetData = target.LockBits(new Rectangle(0, 0, width,height), 
               ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed); 
     BitmapData sourceData = source.LockBits(new Rectangle(0, 0, width,height), 
               ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); 

     unsafe 
     { 
      for(int r = 0 ; r < height ; r++) 
      { 
       byte* pTarget = (byte*) (targetData.Scan0 + r*targetData.Stride); 
       byte* pSource = (byte*) (sourceData.Scan0 + r*sourceData.Stride); 
       for(int c = 0 ; c < width ; c++) 
       { 
        byte colorIndex = (byte) (((*pSource)*0.3 + *(pSource + 1)*0.59 + *(pSource + 2)*0.11)); 
        *pTarget = colorIndex; 
        pTarget++; 
        pSource += 3; 
       } 
      } 
     } 

     target.UnlockBits(targetData); 
     source.UnlockBits(sourceData); 
     return target; 
    } 

, 당신은 PixelFormat과 함께 대상을 만들어야합니다. Format4bppIndexed로 설정 한 다음 ColorPalette를 16 개의 개별 음영으로 설정합니다. 마지막으로, 루프에서 0-15 사이의 값 2를 정규화하고 각 2 픽셀 값을 단일 바이트로 묶어야합니다.

가 4bpp 그레이 스케일 이미지를 만들기 위해 변형 된 코드이다 :

BitmapToGrayscale4bpp` '의 마지막 부분은 하나의 작은 버그가
public static Bitmap BitmapToGrayscale4bpp(Bitmap source) 
    { 
     // Create target image. 
     int width = source.Width; 
     int height = source.Height; 
     Bitmap target = new Bitmap(width,height,PixelFormat.Format4bppIndexed); 
     // Set the palette to discrete shades of gray 
     ColorPalette palette = target.Palette;    
     for(int i = 0 ; i < palette.Entries.Length ; i++) 
     { 
      int cval = 17*i; 
      palette.Entries[i] = Color.FromArgb(0,cval,cval,cval); 
     } 
     target.Palette = palette; 

     // Lock bits so we have direct access to bitmap data 
     BitmapData targetData = target.LockBits(new Rectangle(0, 0, width,height), 
               ImageLockMode.ReadWrite, PixelFormat.Format4bppIndexed); 
     BitmapData sourceData = source.LockBits(new Rectangle(0, 0, width,height), 
               ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); 

     unsafe 
     { 
      for(int r = 0 ; r < height ; r++) 
      { 
       byte* pTarget = (byte*) (targetData.Scan0 + r*targetData.Stride); 
       byte* pSource = (byte*) (sourceData.Scan0 + r*sourceData.Stride); 
       byte prevValue = 0; 
       for(int c = 0 ; c < width ; c++) 
       { 
        byte colorIndex = (byte) ((((*pSource)*0.3 + *(pSource + 1)*0.59 + *(pSource + 2)*0.11))/16); 
        if (c % 2 == 0) 
         prevValue = colorIndex; 
        else 
         *(pTarget++) = (byte)(prevValue | colorIndex << 4); 

        pSource += 3; 
       } 
      } 
     } 

     target.UnlockBits(targetData); 
     source.UnlockBits(sourceData); 
     return target; 
    } 
+0

'(바이트) (에 prevValue는 | colorIndex는 << 4)'되어야 (바이트) (prevValue << 4 | colorIndex)'. prevValue 니블은 출력 바이트의 colorIndex 니블 앞에 와야합니다. – lnmx