2010-04-24 110 views
6

我正在使用C#,并在对象位图中存储了图像。减少C#中的位图位大小#

现在我想将此图像转换为8位灰度,然后转换为4位灰度图像。

你有任何提示如何做到这一点?

回答

6

在.NET位图格式中,不存在8位或4位灰度图像。支持的格式由PixelFormat enumeration列举。但是,您可以通过创建索引图像(8bppIndexed或4bppIndexed)来创建4或8位图像,其中调色板中的每个条目都是灰度值。

这段代码使用位图,并创建一个副本,与灰度值的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)'。 prevValue半字节应该在输出字节中的colorIndex半字节之前。 – lnmx 2011-11-28 16:18:02