WPF C# - 将 16 位(8 位多通道)RAW 高度图加载到 BitmapSource
WPF C# - Loading 16bit (8bit multi-channel) RAW Heightmap into BitmapSource
我试图在我的 WPF 应用程序中显示 16 位 RAW 图像的预览,但它没有像我希望的那样工作。我看过无数的例子,questions/answers 在 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 的参数 class,我现在只是在试验,直到我可以让它正常工作。)
我是不是漏掉了一步?有谁知道如何让它工作?我尝试使用 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。做 pixels[i / 2] 给了我再次使用之前提到的相同图像(16 位加载示例)。
将 16 位原始图像加载到 Photoshop 会显示导入对话框,该对话框建议通道数为 2 作为 8 位(将其设置为 16 位和 2 个通道不会让我导入它,但 16 位和 1 个通道可以) .
这可以解释为什么将 16 位图像作为 8 位图像加载到我的 WPF 应用程序中只导入了它的一半.. 但是这给我留下了一个很大的疑问,为什么它不加载第二个通道。
这个主题的文档很少,几乎没有在任何地方讨论过。在任何地方都找不到关于这件事的任何信息。希望能找到能够帮助我的人。
谢谢,新年快乐!
通过在十六进制编辑器中分析 .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 class .
如果 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 图像并试图以编程方式处理这些图像的人来说。这些格式似乎没有很好的记录......或者也许我只是没有挖掘足够,尽管我花了整个下午在这个话题上。
我试图在我的 WPF 应用程序中显示 16 位 RAW 图像的预览,但它没有像我希望的那样工作。我看过无数的例子,questions/answers 在 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 的参数 class,我现在只是在试验,直到我可以让它正常工作。)
我是不是漏掉了一步?有谁知道如何让它工作?我尝试使用 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。做 pixels[i / 2] 给了我再次使用之前提到的相同图像(16 位加载示例)。
将 16 位原始图像加载到 Photoshop 会显示导入对话框,该对话框建议通道数为 2 作为 8 位(将其设置为 16 位和 2 个通道不会让我导入它,但 16 位和 1 个通道可以) .
这可以解释为什么将 16 位图像作为 8 位图像加载到我的 WPF 应用程序中只导入了它的一半.. 但是这给我留下了一个很大的疑问,为什么它不加载第二个通道。
这个主题的文档很少,几乎没有在任何地方讨论过。在任何地方都找不到关于这件事的任何信息。希望能找到能够帮助我的人。
谢谢,新年快乐!
通过在十六进制编辑器中分析 .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 class .
如果 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 图像并试图以编程方式处理这些图像的人来说。这些格式似乎没有很好的记录......或者也许我只是没有挖掘足够,尽管我花了整个下午在这个话题上。