2010-04-24 2 views
6

Я использую C# и имею изображение, сохраненное в объекте Bitmap.Уменьшение битового размера бит в C#

Теперь я хотел бы преобразовать это изображение в серию серого в 8 бит, а затем в 4-битное изображение в оттенках серого.

Есть ли у вас какие-либо советы, как это можно сделать?

ответ

6

В форматах .NET Bitmap нет такой вещи, как 8 или 4-битное изображение в оттенках серого. Поддерживаемые форматы перечисляются PixelFormat enumeration. Однако вы можете создать 4 или 8-битное изображение, создав индексированное изображение (8bppIndexed или 4bppIndexed), где каждая запись в палитре представляет собой значение шкалы серого.

Этот код берет Bitmap и создает копию в качестве 8bpp индексируются изображения с полутоновых значений:

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; 
    } 

Для того, чтобы сделать 4Bpp изображение вместо этого, вы должны создать цель с PixelFormat. Format4bppIndexed, а затем установите ColorPalette на 16 дискретных оттенков серого. Наконец, в цикле вы должны нормализовать значения 2 между 0-15 и упаковать каждые 2 пикселя в один байт.

Это модифицированный код, чтобы сделать 4bpp полутонового изображения:

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

Последняя часть 'BitmapToGrayscale4bpp' имеет один недочет:' (байт) (prevValue | ColorIndex << 4) 'должен быть' (байт) (prevValue << 4 | colorIndex) '. Предыдущее полубайт должно появиться до того, как colorIndex придет в выходной байт. – lnmx

Смежные вопросы