我需要在一个WPF控件上显示实时图像。 我正在寻找使用WPF最快的方法来实现这一点。
我正在使用摄像头的dll API(AVT)捕获图像。
图像由dll编写,相机通过指向名为tFrame的Image结构的IntPtr引发回调(如下所述)。 像素数据存储在ImageBuffer属性中,该属性是指向字节数组的InPtr。
我知道如何从像素字节数组创建位图,但不知道如何创建BitmapImage。 所以可以创建位图,然后从中创建BitmapImage。 这里有一种从内存中的位图创建BitmapImage的方法。 但我想直接从数据源(tFrame)创建BitmapImage。 我该怎么做?
我知道BitmapImage具有CopyPixels方法,但缺少SetPixels。
这里是我从像素字节数组创建位图的方法。这个方法用于软件的WinForm版本。
我正在使用摄像头的dll API(AVT)捕获图像。
图像由dll编写,相机通过指向名为tFrame的Image结构的IntPtr引发回调(如下所述)。 像素数据存储在ImageBuffer属性中,该属性是指向字节数组的InPtr。
我知道如何从像素字节数组创建位图,但不知道如何创建BitmapImage。 所以可以创建位图,然后从中创建BitmapImage。 这里有一种从内存中的位图创建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://dev59.com/SUvSa4cB1Zd3GeqPbRG6#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,现在我能够显示60FPS 1024x1024的图像,并且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(...);
/// <summary>
/// [http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.writeablebitmap.aspx]
/// </summary>
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));
}