【问题标题】:WPF C# - Loading 16bit (8bit multi-channel) RAW Heightmap into BitmapSourceWPF C# - 将 16 位(8 位多通道)原始高度图加载到 BitmapSource
【发布时间】:2017-01-01 21:24:02
【问题描述】:

我试图在我的 WPF 应用程序中显示 16 位 RAW 图像的预览,但它没有像我希望的那样工作。我已经在 SA 甚至 CodeProject 上查看了无数示例、问题/答案,但这也没有让我走得太远。好吧,实际上它确实如此,因为我可以完全加载 8 位灰度 RAW 图像并将其显示在应用程序上,而不会出现任何奇怪的伪影,但是当涉及 16 位图像时,它就变得一团糟了。

以下是它的外观示例: https://i.stack.imgur.com/kSCX5.jpg

这是我在尝试加载相同原始图像的 16 位版本时得到的结果(直接从第三方程序导出为 16 位): https://i.stack.imgur.com/Melmk.jpg

将 16 位图像加载为 8 位给我一半的正确图像。

这些是我的导入函数:

    BinaryReader br = new BinaryReader(File.Open(filename, FileMode.Open));

    private void LoadRAWData8bit()
    {
        int bits = format.BitsPerPixel;
        int stride = ((width * bits + (bits - 1)) & ~(bits - 1)) / 8;

        byte[] pixels = new byte[stride * height];

        for (int i = 0; i < br.BaseStream.Length; ++i)
            pixels[i] = br.ReadByte();

        br.Close();

        BitmapSource bmp = BitmapSource.Create(width, height, 96, 96, format, null, pixels, stride);

        RawFile = new CRAW(new Size(width, height), format, stride, bmp);
    }

    // 16bit load Test
    private void LoadRAWData16bit()
    {
        WriteableBitmap wBmp = new WriteableBitmap(width, height, 96, 96, format, null);
        int bpp = format.BitsPerPixel / 8;

        byte[] pixels = new byte[wBmp.PixelWidth * wBmp.PixelHeight];

        Int32Rect drawRegionRect = new Int32Rect(0, 0, wBmp.PixelWidth, wBmp.PixelHeight);

        for (int i = 0; i < br.BaseStream.Length; ++i)
            pixels[i] = br.ReadByte();

        br.Close();

        int stride = wBmp.PixelWidth * bpp;
        wBmp.WritePixels(drawRegionRect, pixels, stride, 0);

        RawFile = new CRAW(new Size(width, height), format, stride, wBmp);
    }

(请不要介意传递给 CRAW 类的参数,我现在只是在试验,直到我可以让它正常工作。)

我错过了一步吗?有谁知道如何让它工作?我尝试使用 ushort 数组而不是字节数组来制作相同的 8 位导入函数:

private void LoadRAWData16bit()
    {
        int bits = format.BitsPerPixel;
        int stride = ((width * bits + (bits - 1)) & ~(bits - 1)) / 8;
        int bpp = format.BitsPerPixel / 8;

        ushort[] pixels = new ushort[stride * height * bpp];

        for (int i = 0; i < br.BaseStream.Length; i += sizeof(ushort))
            pixels[i] = br.ReadUInt16();

        br.Close();

        BitmapSource bmp = BitmapSource.Create(width, height, 96, 96, format, null, pixels, stride);

        RawFile = new CRAW(new Size(width, height), format, stride, bmp);
    }

像这样,但是这样做给了我一半的图像,而且它比预期的要暗很多,因为数组中每个第 2 个字节有 1 个字节的值为 0。做像素 [i / 2] 再次给了我与前面提到的相同的图像(16 位加载示例)。

将 16 位原始图像加载到 Photoshop 会显示导入对话框,该对话框建议将通道数 2 作为 8 位(将其设置为 16 位和 2 个通道不会让我导入它,但 16 位和 1 个通道可以工作)。

这可以解释为什么将 16 位图像作为 8 位加载到我的 WPF 应用程序中只导入其中的一半……但这给我留下了一个很大的问号,即为什么它也没有加载第二个通道。

这个主题的文档记录很差,几乎没有在任何地方讨论过。在这件事上找不到任何东西..希望找到能够帮助我的人。

谢谢,新年快乐!

【问题讨论】:

    标签: heightmap bitmapsource


    【解决方案1】:

    通过在 Hex 编辑器中分析 .RAW 图像,我自己找到了解决方案。

    基本上,多通道 8/16 位 RAW 图像的结构如下图所示(8 位示例):http://puu.sh/t97fY/6920f804af.png

    第一个字节属于图像本身(根据 Photoshop 也称为 Alpha 1),第二个字节是第二个通道(称为 Alpha 2)。 每个图像层的字节是交替的,如屏幕截图所示。 在上面显示的屏幕截图中,0x00 字节属于第二个通道,而其他字节(59、57、58、56 等)属于主图像。

    此时拆分 2 层非常简单。由于 BitmapSource.Create 使用原始字节生成位图,我们所要做的就是循环通过 FileStream 并交替目标缓冲区以适应其正确缓冲区中的字节,然后将其馈送到 BitmapSource 类。

    如果 RAW 图像没有 Alpha 通道,而只有普通图像本身,您可以分配一个与普通图像一样大的缓冲区并用 0x00 填充它,这将为您提供一个空白的 Alpha 层。

    如何以编程方式确定 RAW 图像是否具有 Alpha 通道也很简单。给定宽度和高度,多通道 RAW 图像的大小将是基本图像的两倍。

    例子:

    Width: 128
    Height: 128
    RAW Image Size: 32768
    128 * 128 = 16384
    

    如果

    file_size == 宽度 * 高度

    那么我们就没有 alpha 通道了。

    如果

    file_size == 宽度 * 高度 * 2

    那么我们就有了一个 alpha 通道。

    希望这可以帮助将来的人。有这么多 RAW 图像格式,它很快就会变得非常混乱,特别是对于那些使用高度图/Photoshop RAW 图像试图以编程方式处理这些图像的人来说。这些格式似乎没有很好的文档记录。或者我只是简单地尽管我花了一个下午的时间在这个话题上,但还没有深入挖掘。

    【讨论】:

      猜你喜欢
      • 2011-10-13
      • 1970-01-01
      • 2021-11-08
      • 1970-01-01
      • 2019-04-05
      • 2019-08-27
      • 1970-01-01
      • 1970-01-01
      • 2020-05-07
      相关资源
      最近更新 更多