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)
}
  1. 抱歉,如果我在没有IDE
  2. 的情况下从计算机上的内存中编写的代码中有错字
  3. 将 System.Windows.media.Imaging 添加到您的使用中
  4. 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);

这似乎有效!