WPF:如何以高效的方式每秒更新30次图像

14

我正在编写一个使用组件的WPF应用程序,此组件返回一个指向位图像素(stride * height)的指针(IntPtr)。我预先知道位图是24位rgb格式,宽度和高度。

使用这些位图更新图像控件以向用户呈现视频,但我不确定最有效的方法是什么,大部分时间CPU使用率超过75%,内存从40MB变为500MB,然后GC开始工作,再次降至40MB。应用程序开始变得无响应。

我该怎么办?

谢谢!

2个回答

17

你很可能正在分配新的Bitmap,这些Bitmap不可回收。你应该只分配一个WriteableBitmap并更新它。链接的文档描述了锁定、更新和解锁WriteableBitmap的过程。

在我工作的软件中使用WPF实时超声图像,我接收到一个Windows Forms Bitmap,然后使用本地CopyMemory方法直接将其复制到WriteableBitmap中。即使进行这种更复杂的操作,CPU也不会太紧张,只要我适当地处理可以回收的内容,内存使用量就不会变化。希望这个例子能帮到你:

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

CopyMemory的定义如下:

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

为什么你没有在WriteableBitmap上使用WritePixels方法?只是想知道是否有特定的原因。 - nietras
@harrydev 四年过去了,但是回顾一下,我不记得为什么了。WritePixels的实现看起来很相似,只是它使用了不安全的逻辑http://referencesource.microsoft.com/#PresentationCore/src/Core/CSharp/System/Windows/Media/Imaging/WriteableBitmap.cs#1074(并且在逻辑上可能更安全)。就性能而言,我认为它们是相似的,但你必须测试才能确定。我也不确定是否可以在后台线程上调用WritePixels,而我认为你可以在这里的某些逻辑中在后台执行。 - Will Eddins
请务必在 UI 线程中创建 WritableBitmap。因为如果您不这样做,在 UI 线程中执行 bitmap.Lock(),例如在 CompositionTarget.Rendering 或任何其他事件处理程序中,将会导致 InvalidOperation。 - Unicorn

4
使用WriteableBitmap上的名为WritePixels的便捷方法,我们可以像下面这样简化写入操作:
// 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);
}

1
ImageBufferSize 属于哪个类? - user2386301

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接