WPF: как эффективно обновлять изображение 30 раз в секунду

Я пишу приложение WPF, которое использует компонент, и этот компонент возвращает указатель (IntPtr) в пиксели растрового изображения (высота * высота). Я заранее знаю, что битмап - это 24-битный rgb, его ширина и высота.

Обновление элемента управления Image с этими растровыми изображениями делает видео для пользователя, но я не уверен, что это самый эффективный способ сделать это, большую часть времени процессор использует 75% + и память меняется с 40 МБ до 500 мб, и nI думает, что GC начинает работать, а затем снова падает до 40 мм. Приложение начинает не реагировать.

Что я делаю?

спасибо!

Ответ 1

Скорее всего, вы выделяете новые растровые изображения, которые не являются одноразовыми. Вы должны выделить один WriteableBitmap и обновить это вместо этого. Связанная документация описывает процесс блокировки, обновления и разблокировки WriteableBitmap

На программном обеспечении я работаю над использованием живых ультразвуковых изображений в WPF, я получаю Bitmap Windows Forms, который я копирую в WriteableBitmap напрямую, используя собственный метод CopyMemory. Даже при этой более сложной работе процессор не слишком напряжен, и использование памяти никогда не перемещается, пока я правильно распоряжаюсь тем, что могу. Надеюсь, этот пример поможет вам:

// 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 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();

Где CopyMemory определяется как:

[DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory")]
public static extern void CopyMemory(IntPtr Destination, IntPtr Source, int Length);

Ответ 2

Используя метод удобства, называемый WritePixels на WriteableBitmap, мы можем записать его немного короче, например:

// DLL returns images as a WinForms Bitmap
// It 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);
}