I need to display live images in a WPF control. I am looking for the fastest way to do this using WPF.
I am collecting images from the camera using the dll API ( AVT ).
The image is recorded by the dll, and the camera raises the callback using IntPtr to an image structure called tFrame (described below). Pixel data is stored in an ImageBuffer element using InPtr for a byte array.
I know how to create a Bitmap from an array of pixel bytes, but not BitmapImage. This way you can create a Bitmap and then create a BitmapImagem from it. Here is a way to create a BitmapImage from a bitmap in memory . But I want to create a BitmapImage directly from a data source (tFrame). How can i do this?
I know that BitmapImage has a CopyPixels method, but it does not matter 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; }
This is how I create a Bitmap from an array of pixel bytes. This was used in the WinForm software version.
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); }
EDIT 1:
Thanks to dr.mo, I can now display 60 FPS 1024x1024 images using ~ 3% of the processor! What am I doing:
//@ 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)); }