Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF: How to efficiently update an Image 30 times per second

Tags:

c#

bitmap

wpf

I'm writing a WPF application that uses a component, and this component returns a pointer (IntPtr) to pixels of a bitmap (stride * height). I know in advance that the bitmap is a 24bits rgb, its width and height.

Updating the Image control with these bitmaps makes up a video to the user, but I'm not sure what's the most efficient way to do that, most of the time the CPU usage goes to 75%+ and memory changing from 40mb to 500mb and the nI think GC starts to work and then it drops again to 40mm. The app starts to not be responsive.

What shoud I do?

thanks!

like image 289
John Avatar asked Mar 16 '10 14:03

John


2 Answers

You're most likely allocating new Bitmaps, which aren't disposable. You should allocate a single WriteableBitmap and update that instead. The linked documentation describes the process behind locking, updating, and unlocking a WriteableBitmap

On software I work on using live ultrasound images in WPF, I am receiving a Windows Forms Bitmap, which I copy into the WriteableBitmap directly using the native CopyMemory method. Even with this more complicated work, the CPU isn't strained too hard, and the memory usage never moves as long as I properly dispose what I can. Hopefully this example can help you:

// DLL returns images as a WinForms Bitmap
Bitmap bmp = myClass.getWinFormsBitmap();

// In my situation, the images are always 640 x 480.
BitmapData data = bmp.LockBits(new Rectangle(0, 0, 640, 480), ImageLockMode.ReadOnly,  System.Drawing.Imaging.PixelFormat.Format32bppArgb);
this.writeableBitmap.Lock();

// Copy the bitmap's data directly to the on-screen buffers
NativeMethods.CopyMemory(this.writeableBitmap.BackBuffer, data.Scan0, ImageBufferSize);

// Moves the back buffer to the front.
this.writeableBitmap.AddDirtyRect(new Int32Rect(0, 0, 640, 480));
this.writeableBitmap.Unlock();

bmp.UnlockBits(data);

// Free up the memory of the WinForms bitmap
bmp.Dispose();

Where CopyMemory is defined as:

[DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory")]
public static extern void CopyMemory(IntPtr Destination, IntPtr Source, int Length);
like image 148
Will Eddins Avatar answered Nov 02 '22 03:11

Will Eddins


Using the convenience method called WritePixels on WriteableBitmap we can write it a bit shorter like so:

// DLL returns images as a WinForms Bitmap
// It's disposed even if an exception is thrown
using (Bitmap bmp = myClass.getWinFormsBitmap())
{
    // In my situation, the images are always 640 x 480.
    BitmapData data = bmp.LockBits(new Rectangle(0, 0, 640, 480), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
    writeableBitmap.WritePixels(new Int32Rect(0, 0, 640, 480), data.Scan0, ImageBufferSize, data.Stride);
    bmp.UnlockBits(data);
}
like image 42
vidstige Avatar answered Nov 02 '22 03:11

vidstige