SoftwareBitmap 16 灰色像素到 ushort[]
SoftwareBitmap 16 Gray pixels to ushort[]
我正在使用 mediaframes (Kinect) 实时获取颜色,Depth/Infrared UWP 上的帧。这是为了将帧数据存储在磁盘上,稍后进行处理。
对于颜色,我使用 Memorystream 获取以字节为单位的像素。
// Get the Individual color Frame
var vidFrame = clrFrame?.VideoMediaFrame;
{
if (vidFrame == null) return;
// create a UWP SoftwareBitmap and copy Color Frame into Bitmap
SoftwareBitmap sbt = new SoftwareBitmap(vidFrame.SoftwareBitmap.BitmapPixelFormat, vidFrame.SoftwareBitmap.PixelWidth, vidFrame.SoftwareBitmap.PixelHeight);
vidFrame.SoftwareBitmap.CopyTo(sbt);
// PixelFormat needs to be in 8bit for Colour only
if (sbt.BitmapPixelFormat != BitmapPixelFormat.Bgra8)
sbt = SoftwareBitmap.Convert(vidFrame.SoftwareBitmap, BitmapPixelFormat.Bgra8);
if (source != null)
{
var ignore = Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
extBitmap = new WriteableBitmap(sbt.PixelWidth, sbt.PixelHeight);
sbt.CopyToBuffer(extBitmap.PixelBuffer);
byte[] pixels = PixelBufferToWriteableBitmap(extBitmap);
extBitmap.Invalidate();
await SavePixelsToFile(pixels);
});
}
}
public async Task<byte[]> PixelBufferToWriteableBitmap(WriteableBitmap wb)
{
using (Stream stream = wb.PixelBuffer.AsStream())
{
using (MemoryStream memoryStream = new MemoryStream())
{
await stream.CopyToAsync(memoryStream);
byte[] pixels = memoryStream.ToArray();
return pixels;
}
}
}
红外像素格式为Gray16(在SoftwareBitmap中);我想保留原始像素数据(因此帧中没有数据丢失)并将其写入 ushort[] 数组中的本地文件夹。
以下是链接,我偶然发现了如何从软件位图中获取设置像素。但是,它是bgra转字节,我想把软件位图转成ushort。
https://docs.microsoft.com/en-us/windows/uwp/audio-video-camera/imaging
我是新手,不知道如何进行。
有人可以帮忙吗?
编辑
我认为可以通过执行以下操作将缓冲区媒体帧转换为字节数组:
public 异步任务 BufferStreamTobyte(BufferMediaFrame buffFrame)
{
using (Stream stream = buffFrame.Buffer.AsStream())
{
using (MemoryStream memoryStream = new MemoryStream())
{
await stream.CopyToAsync(memoryStream);
byte[] pixels = memoryStream.ToArray();
return pixels;
}
}
}
但我不确定这样做是否丢失了红外帧的信息。由于红外线和深度是每像素 16 位,因此当前的字节转换保持 8 bpp。为此 ushort[] 将能够容纳 16bpp。
我对此很陌生,不确定所以我希望我做对了吗?
编辑 2:
我在byte[]中得到了像素数据。
我知道 byte 是 8 位而 short 是 16 位所以我改变了数组的长度:
int width = softwareBitmap.PixelWidth;
int height = softwareBitmap.PixelHeight;
int length = width * height * 2;
byte[] irbyteData = new byte[length]; // *2 to get 16 bit
var irshortData = new ushort[width * height]; // 16 bit ushort
IntPtr ptr = (IntPtr)pixelBytesAddress;
Marshal.Copy(ptr, irbyteData, 0, length); //seems to successfully get pixels from memory but not sure if this is lossless
我会尝试使用 PNG
例如:
using(var fs=new FileStream("sample.png"))
{
BitmapSource bmpSource=BitmapSource(Width,Height,96,96,PixelFormats.Gray16,
BitmapPalettes.Gray16,buffer,ImageWidth*sizeof(ushort));
PngBitmapEncoder enc = new PngBitmapEncoder();
end.Frames.Add(BitmapFrame.Create(bmpSource));
enc.Save(fs)
}
- 抱歉,如果我在没有IDE
的情况下从计算机上的内存中编写的代码中有错字
- 将 System.Windows.media.Imaging 添加到您的使用中
- buffer 是一个包含像素值的 ushort 数组(总长度应为:宽*高*2)
我通过以下link找到了将 IntPtr 数据复制到 ushort 数组的解决方案:
我通过
得到地址IntPtr
using (var input = softwareBitmap.LockBuffer(BitmapBufferAccessMode.ReadWrite))
using (var inputReference = input.CreateReference())
((IMemoryBufferByteAccess)inputReference).GetBuffer(out inputBytes, out inputCapacity);
IntPtr ptr = (IntPtr)inputBytes;
Marshal.Copy(ptr, infraredbyteData, 0, length);
我得到长度为(宽度*高度*2)的字节来保存16位数据。
后来我通过
将它转换为ushort
var size = infraredbyteData.Length / 2;
ushort[] output = new ushort[size]; // every ushort is 2 bytes
Buffer.BlockCopy(infraredbyteData, 0, output, 0, infraredbyteData.Length);
这似乎有效!
我正在使用 mediaframes (Kinect) 实时获取颜色,Depth/Infrared UWP 上的帧。这是为了将帧数据存储在磁盘上,稍后进行处理。
对于颜色,我使用 Memorystream 获取以字节为单位的像素。
// Get the Individual color Frame
var vidFrame = clrFrame?.VideoMediaFrame;
{
if (vidFrame == null) return;
// create a UWP SoftwareBitmap and copy Color Frame into Bitmap
SoftwareBitmap sbt = new SoftwareBitmap(vidFrame.SoftwareBitmap.BitmapPixelFormat, vidFrame.SoftwareBitmap.PixelWidth, vidFrame.SoftwareBitmap.PixelHeight);
vidFrame.SoftwareBitmap.CopyTo(sbt);
// PixelFormat needs to be in 8bit for Colour only
if (sbt.BitmapPixelFormat != BitmapPixelFormat.Bgra8)
sbt = SoftwareBitmap.Convert(vidFrame.SoftwareBitmap, BitmapPixelFormat.Bgra8);
if (source != null)
{
var ignore = Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
extBitmap = new WriteableBitmap(sbt.PixelWidth, sbt.PixelHeight);
sbt.CopyToBuffer(extBitmap.PixelBuffer);
byte[] pixels = PixelBufferToWriteableBitmap(extBitmap);
extBitmap.Invalidate();
await SavePixelsToFile(pixels);
});
}
}
public async Task<byte[]> PixelBufferToWriteableBitmap(WriteableBitmap wb)
{
using (Stream stream = wb.PixelBuffer.AsStream())
{
using (MemoryStream memoryStream = new MemoryStream())
{
await stream.CopyToAsync(memoryStream);
byte[] pixels = memoryStream.ToArray();
return pixels;
}
}
}
红外像素格式为Gray16(在SoftwareBitmap中);我想保留原始像素数据(因此帧中没有数据丢失)并将其写入 ushort[] 数组中的本地文件夹。
以下是链接,我偶然发现了如何从软件位图中获取设置像素。但是,它是bgra转字节,我想把软件位图转成ushort。
https://docs.microsoft.com/en-us/windows/uwp/audio-video-camera/imaging
我是新手,不知道如何进行。
有人可以帮忙吗?
编辑
我认为可以通过执行以下操作将缓冲区媒体帧转换为字节数组:
public 异步任务
using (Stream stream = buffFrame.Buffer.AsStream())
{
using (MemoryStream memoryStream = new MemoryStream())
{
await stream.CopyToAsync(memoryStream);
byte[] pixels = memoryStream.ToArray();
return pixels;
}
}
}
但我不确定这样做是否丢失了红外帧的信息。由于红外线和深度是每像素 16 位,因此当前的字节转换保持 8 bpp。为此 ushort[] 将能够容纳 16bpp。 我对此很陌生,不确定所以我希望我做对了吗?
编辑 2:
我在byte[]中得到了像素数据。 我知道 byte 是 8 位而 short 是 16 位所以我改变了数组的长度:
int width = softwareBitmap.PixelWidth;
int height = softwareBitmap.PixelHeight;
int length = width * height * 2;
byte[] irbyteData = new byte[length]; // *2 to get 16 bit
var irshortData = new ushort[width * height]; // 16 bit ushort
IntPtr ptr = (IntPtr)pixelBytesAddress;
Marshal.Copy(ptr, irbyteData, 0, length); //seems to successfully get pixels from memory but not sure if this is lossless
我会尝试使用 PNG
例如:
using(var fs=new FileStream("sample.png"))
{
BitmapSource bmpSource=BitmapSource(Width,Height,96,96,PixelFormats.Gray16,
BitmapPalettes.Gray16,buffer,ImageWidth*sizeof(ushort));
PngBitmapEncoder enc = new PngBitmapEncoder();
end.Frames.Add(BitmapFrame.Create(bmpSource));
enc.Save(fs)
}
- 抱歉,如果我在没有IDE 的情况下从计算机上的内存中编写的代码中有错字
- 将 System.Windows.media.Imaging 添加到您的使用中
- buffer 是一个包含像素值的 ushort 数组(总长度应为:宽*高*2)
我通过以下link找到了将 IntPtr 数据复制到 ushort 数组的解决方案:
我通过
得到地址IntPtrusing (var input = softwareBitmap.LockBuffer(BitmapBufferAccessMode.ReadWrite))
using (var inputReference = input.CreateReference())
((IMemoryBufferByteAccess)inputReference).GetBuffer(out inputBytes, out inputCapacity);
IntPtr ptr = (IntPtr)inputBytes;
Marshal.Copy(ptr, infraredbyteData, 0, length);
我得到长度为(宽度*高度*2)的字节来保存16位数据。
后来我通过
将它转换为ushortvar size = infraredbyteData.Length / 2;
ushort[] output = new ushort[size]; // every ushort is 2 bytes
Buffer.BlockCopy(infraredbyteData, 0, output, 0, infraredbyteData.Length);
这似乎有效!