WPF C# - 将16位(8位多通道)RAW高度图加载到BitmapSource中

时间:2017-01-01 21:24:03

标签: heightmap bitmapsource

我正在尝试在我的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);
    }
像这样,但这样做会给我一半的图像并且它比它应该的颜色更暗,因为数组中每个第二个字节有1个字节,值为0.做像素[i / 2]再次给我像之前提到的相同的图像(16位加载样本)。

将16位原始图像加载到Photoshop中会显示导入对话框,其中将通道计数设置为2为8位(将其设置为16位,使用2个通道将不允许我导入它,但是16位,1个通道可以工作)。 / p>

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

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

谢谢新年快乐!

1 个答案:

答案 0 :(得分:0)

通过在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 == width * height

然后我们没有alpha通道。

如果

  

file_size == width * height * 2

然后我们就有了一个alpha通道。

希望这可以在将来帮助某人。有很多RAW图像格式,它可以非常快速地混淆,特别是那些使用Heightmaps / Photoshop RAW图像试图以编程方式操作这些图像的人。这些格式似乎没有很好的记录......或者也许虽然我花了整整一个下午来讨论这个话题,但我根本就没有足够的挖掘力。