首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >WPF C# -将16位(8位多通道)原始Heightmap加载到BitmapSource中

WPF C# -将16位(8位多通道)原始Heightmap加载到BitmapSource中
EN

Stack Overflow用户
提问于 2017-01-01 21:24:02
回答 1查看 784关注 0票数 0

我试图在我的WPF应用程序中显示一个16位原始图像的预览,但它并不像我所希望的那样工作。我在SA上,甚至在CodeProject上看过无数的例子、问题和答案,但这也没有让我走多远。嗯,实际上是这样的,因为我可以完全加载一个8位灰度的原始图像,并在应用程序上显示它,而不需要任何奇怪的工件,但是当涉及到16位图像时,它就会变得一团糟。

下面是一个应该是什么样子的示例:https://i.stack.imgur.com/kSCX5.jpg

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

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

这些是我的重要功能:

代码语言:javascript
复制
    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位导入函数:

代码语言:javascript
复制
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。做像素/2再次给我相同的图像,如前面提到的(16位加载样本)。

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

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

这个问题没有得到充分的记载,而且几乎没有讨论过任何地方。在这件事上什么也找不到。希望能找到一个能帮我的人。

谢谢,新年快乐!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-01-02 23:21:07

通过在十六进制编辑器中分析.RAW映像,自己找到了解决方案。

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

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

在这一点上,分裂这2层是非常简单的。由于BitmapSource.Create从原始字节生成位图,我们所要做的就是循环遍历FileStream并交替目标缓冲区,以适应它们正确的缓冲区中的字节,这些缓冲区随后将被输入到BitmapSource类中。

如果原始图像没有alpha通道,但只有普通图像本身,您可以分配一个与普通图像一样大的缓冲区,并使用0x00填充它,这将给您一个空白alpha层。

如何以编程方式确定原始图像是否有alpha通道也很容易。给定宽度和高度,多通道原始图像将是基本图像的两倍大小。

示例:

代码语言:javascript
复制
Width: 128
Height: 128
RAW Image Size: 32768
128 * 128 = 16384

如果

file_size ==宽度*高度

那我们就没有阿尔法通道了。

如果

file_size ==宽度*高度*2

那我们就有了一个阿尔法通道。

希望这能对将来的人有所帮助。有这么多原始图像格式,它会很快变得非常混乱,特别是对于那些试图以编程方式处理这些图像的高高图/Photoshop原始图像的人。这些格式似乎没有很好的记录..。或者我只是挖的不够多,尽管我花了一个下午在这个话题上。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41419160

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档