保存 16 位灰度图像的结构

Structure for holding a 16bits grayscale image

我需要屏蔽内存缓冲区中的图像(用黑色填充的矩形区域)。所以我天真地为我的 API 重新使用了 Bitmap class with ImageFormat.MemoryBmp。这在我的本地机器上运行良好:

public static void MaskBitmap(Bitmap input, Rectangle maskRegion)
{
    var bytesPerPixel = Image.GetPixelFormatSize(input.PixelFormat) / 8;
    var row = new byte[maskRegion.Width * bytesPerPixel];

    var maskData = input.LockBits(maskRegion, ImageLockMode.WriteOnly, input.PixelFormat);
    for (var i = 0; i < maskData.Height; ++i)
    {
        Marshal.Copy(row, 0, maskData.Scan0 + (i * maskData.Stride), row.Length);
    }
    input.UnlockBits(maskData);
}

然而,当部署到生产环境时,发现以下抛出 NotImplementedException:

var image16 = new Bitmap(512, 512, PixelFormat.Format16bppGrayScale);

我最终追踪到了这里:

所以我的问题是:在 c# 中是否有任何现有的 class 我可以重新使用来保存 pixelformat 类型的图像:

我知道 GDI+ does not support saving/displaying 16 位图像,我只需要一个具有图像样式访问的内存结构。


仅供参考,我尝试了以下技巧:

var image = new Bitmap(512,512,PixelFormat.Format24bppRgb);
image.Flags = ImageFlags.ColorSpaceGray;

但是 Flags 是只读的。

我认为Wpf bitmaps应该支持16位灰度。

但是,我处理过的大多数使用 16 位灰度图像的系统都使用自定义数据类型。类似于:

public class My16BitImage{
    public ushort[] Data {get;}
    public int Width {get;}
    public int Height {get;}
}

请注意,为了显示图像,您很可能需要将其转换为 8 位图像,并且您可能需要缩放值以使 max/min 值映射到 largest/smallest 8 位值。

如您所见,GDI+ Bitmap 在 Linux 上根本不支持 16bpp 灰度像素格式,实际上它在 Windows 上的支持也非常有限。在我收集了两个平台的限制后,请参阅 不同平台上可能的像素格式限制 部分下的 table here

I need to mask image from memory buffers

要在 Linux 和 Windows 上使用完全托管的内存中位图表示,您可以使用 this library (disclaimer: written by me). You can create a 16bpp grayscale bitmap data by the BitmapDataFactory.CreateBitmapData method, which returns an IReadWriteBitmapData that allows a lot of managed operations (see the link that enlists the usable extension methods). You can even convert it to an actual Bitmap by the ToBitmap 扩展,但在 Linux 上这会将结果为具有 24bpp RGB 像素格式的 Bitmap

示例:

var image16 = BitmapDataFactory.CreateBitmapData(new Size(512, 512), PixelFormat.Format16bppGrayScale);
var row = image16.FirstRow;
do
{
    for (int x = 0; x < image16.Width; x++)
    {
        // row[x] uses a Color32 structure (8 bit per color) but raw access
        // enables you to use the full 16-bit color range:
        row.WriteRaw<ushort>(x, 32768); // 50% gray
    }
} while (row.MoveNextRow());


至于 8bpp 索引和 24bpp RGB 格式,原生 Bitmap 也支持 Linux,但请注意,从版本 .NET 6 System.Drawing 开始支持 only on Windows by default. Microsoft recommends using other libraries instead, but you can still enable the Unix support by adding "System.Drawing.EnableUnixSupport": true to runtimeconfig.json. Or, if you decide to use my library I mentioned above, just call DrawingModule.Initialize() before anything else, which enables 无需编辑任何配置文件即可支持 Unix。