【问题标题】:Reducing Bitmap bit-size in C#在 C# 中减少位图位大小
【发布时间】:2010-04-24 09:33:34
【问题描述】:

我正在使用 C#,并将图像存储在对象位图中。

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

你有什么技巧可以做到这一点吗?

【问题讨论】:

    标签: c# bitmap


    【解决方案1】:

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

    【讨论】:

    • BitmapToGrayscale4bpp 的最后一部分有一个小错误:(byte)(prevValue | colorIndex &lt;&lt; 4) 应该是(byte)(prevValue &lt;&lt; 4 | colorIndex )。 prevValue 半字节应位于输出字节中的 colorIndex 半字节之前。
    猜你喜欢
    • 2013-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-01
    • 1970-01-01
    相关资源
    最近更新 更多