如何从像素字节数组创建BitmapImage(实时video显示)

我需要在WPF控件上显示实时图像。 我正在寻找使用WPF执行此操作的最快方法。

我正在使用其DLL API( AVT )从相机捕获图像。

图像由dll写入,摄像机使用IntPtr将回调上升到名为tFrame的Image结构(如下所述)。 像素数据存储在ImageBuffer属性中,其中InPtr为字节数组。

我知道如何从像素字节数组创建一个位图,但不是BitmapImage。 因此可以创建一个Bitmap,然后从中创建一个BitmapImagem。 这里有一种从内存上的位图创建BitmapImage的方法 。 但我想直接从数据源(tFrame)创建BitmapImage 。 我怎样才能做到这一点?

我知道BitmapImage有一个CopyPixels方法,但它有一个SetPixels。

public struct tFrame { public IntPtr AncillaryBuffer; public uint AncillaryBufferSize; public uint AncillarySize; public tBayerPattern BayerPattern; public uint BitDepth; public tFrameCtx Context; public tImageFormat Format; public uint FrameCount; public uint Height; public IntPtr ImageBuffer; public uint ImageBufferSize; public uint ImageSize; public uint RegionX; public uint RegionY; public tErr Status; public uint TimestampHi; public uint TimestampLo; public uint Width; } 

这是我如何从像素字节数组创建一个位图。 这是在WinForm版本的软件中使用的。

 private void CreateBitmap(tFrame frame) { //This sample is for a 8bpp captured image PixelFormat pxFormat = PixelFormat.Format8bppIndexed; //STRIDE //[https://stackoverflow.com/questions/1983781/why-does-bitmapsource-create-throw-an-argumentexception/1983886#1983886][3] //float bitsPerPixel = System.Drawing.Image.GetPixelFormatSize(format); int bitsPerPixel = ((int)pxFormat >> 8) & 0xFF; //Number of bits used to store the image data per line (only the valid data) int validBitsPerLine = ((int)frame.Width) * bitsPerPixel; //4 bytes for every int32 (32 bits) int stride = ((validBitsPerLine + 31) / 32) * 4; Bitmap bmp = new Bitmap((int)frame.Width, (int)frame.Height, stride, pxFormat, frame.ImageBuffer); } 

编辑1:

感谢dr.mo,现在我能够显示60张FPS 1024×1024图像,CPU使用率约为3%! 我在做的是:

 //@ UI Thread public WriteableBitmap wbm = new WriteableBitmap(1024, 1024, (double)96, (double)96, System.Windows.Media.PixelFormats.Gray8, null); this.wbBackBuffer = this.wbm.BackBuffer; //This can be called by a timer in the UI thread or at the grab Thread for every image, the CPU usage is almost the same. void UpdateDisplayImage() { wbm.Lock(); wbm.AddDirtyRect(new Int32Rect(0, 0, wbm.PixelWidth, wbm.PixelHeight)); wbm.Unlock(); } //@ Grab Thread //Update the backbuffer with new camera image data. UpdateBackBuffer(...); ///  /// [http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.writeablebitmap.aspx] ///  public void UpdateBackBuffer(IntPtr pData, int w, int h, int ch) { //Can not acess wbm from outside UI thread //CopyMemory(wbm.BackBuffer, pData, (uint)(w * h * ch)); //I dont know if it is safe to write to it buffer like this: CopyMemory(this.wbBackBuffer, pData, (uint)(w * h * ch)); } 

这应该可以解决问题。 它超级快。

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Drawing; using System.Runtime.InteropServices; using System.IO; using System.ComponentModel; public class MakeBitmapSource { [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")] public static extern void CopyMemory(IntPtr Destination, IntPtr Source, uint Length); public static BitmapSource FromNativePointer(IntPtr pData, int w, int h, int ch) { PixelFormat format = PixelFormats.Default; if (ch == 1) format = PixelFormats.Gray8; //grey scale image 0-255 if (ch == 3) format = PixelFormats.Bgr24; //RGB if (ch == 4) format = PixelFormats.Bgr32; //RGB + alpha WriteableBitmap wbm = new WriteableBitmap(w, h, 96, 96, format, null); CopyMemory(wbm.BackBuffer, pData, (uint)(w * h * ch)); wbm.Lock(); wbm.AddDirtyRect(new Int32Rect(0, 0, wbm.PixelWidth, wbm.PixelHeight)); wbm.Unlock(); return wbm; } public static BitmapSource FromArray(byte[] data, int w, int h, int ch) { PixelFormat format = PixelFormats.Default; if (ch == 1) format = PixelFormats.Gray8; //grey scale image 0-255 if (ch == 3) format = PixelFormats.Bgr24; //RGB if (ch == 4) format = PixelFormats.Bgr32; //RGB + alpha WriteableBitmap wbm = new WriteableBitmap(w, h, 96, 96, format, null); wbm.WritePixels(new Int32Rect(0, 0, w, h), data, ch * w, 0); return wbm; } }