我在超声波机器上有一个WPF应用程序,它以超过每秒30帧的速度显示用C ++生成的超声图像。
根据我的理解,在WPF中显示图像的正常过程是为您的图像创建一个BitmapSource,并为您的图像设置Source,然后使其无效并显示。
由于BitmapSources没有实现IDisposable,使用这种方法迫使我每秒创建30个BitmapSources。对于具有32bppArgb格式的640x480图像,这是每秒分配大约30MB /秒的内存,然后每10秒进行一次垃圾处理,导致可见的延迟。显然不是一个可以接受的解决方案。
我目前的解决方案是:
在C ++中我在托管C ++中创建一个System.Drawing.Bitmap(WinForms位图),从指针填充图片做一个memcpy,使用Graphics对象做一些额外的绘图我需要,并在ImageReceived事件期间将其传递给C#/ WPF。
在C#中 Image.Source设置为BitmapBuffer生成的源,这是访问位图源的原始数据的一种黑客方式:请参阅this link.我做了P /调用CopyMemory将数据从Bitmap.Scan0复制到BitmapBuffer中。然后我使图像无效以更新屏幕,并使用Dispose()Drawing.Bitmap对象来释放内存。
虽然这种方法已经工作了一段时间,但它看起来非常糟糕,我发现很难相信没有其他“适当”的方法可以做到这一点,而不是通过反思。
问题:有更好的方法吗?
答案 0 :(得分:12)
如果您使用最新的WPF位,请查看WriteableBitmap,您将需要完成更多的腿部工作,但您真的会快速更新。
快速谷歌,你会得到一些样品。
答案 1 :(得分:9)
这是我为WPF BitmapSource和GDI Bitmap(我自己的项目)之间的别名(共享内存)编写的一些代码
显然,你需要根据自己的需要调整它,最终可能最终会产生一种不那么“hacky”的感觉。
class AliasedBitmapSource : BitmapSource {
private Bitmap source;
public AliasedBitmapSource(Bitmap source) {
this.source = source;
this.pixelHeight = source.Height;
this.pixelWidth = source.Width;
this.dpiX = source.HorizontalResolution;
this.dpiY = source.VerticalResolution;
}
public override event EventHandler DownloadCompleted;
public override event EventHandler<ExceptionEventArgs> DownloadFailed;
public override event EventHandler<ExceptionEventArgs> DecodeFailed;
protected override Freezable CreateInstanceCore() {
throw new NotImplementedException();
}
private readonly double dpiX;
public override double DpiX {
get {
return dpiX;
}
}
private readonly double dpiY;
public override double DpiY {
get {
return dpiY;
}
}
private readonly int pixelHeight;
public override int PixelHeight {
get {
return pixelHeight;
}
}
private readonly int pixelWidth;
public override int PixelWidth {
get {
return pixelWidth;
}
}
public override System.Windows.Media.PixelFormat Format {
get {
return PixelFormats.Bgra32;
}
}
public override BitmapPalette Palette {
get {
return null;
}
}
public unsafe override void CopyPixels(Int32Rect sourceRect, Array pixels, int stride, int offset) {
BitmapData sourceData = source.LockBits(
sourceRect.ToRectangle(),
ImageLockMode.ReadWrite,
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
fixed (byte* _ptr = &((byte[])pixels)[0]) {
byte* dstptr = _ptr;
byte* srcptr = (byte*)sourceData.Scan0;
for (int i = 0; i < pixels.Length; ++i) {
*dstptr = *srcptr;
++dstptr;
++srcptr;
}
}
source.UnlockBits(sourceData);
}
}
public static class Extensions {
public static Rectangle ToRectangle(this Int32Rect me) {
return new Rectangle(
me.X,
me.Y,
me.Width,
me.Height);
}
public static Int32Rect ToInt32Rect(this Rectangle me) {
return new Int32Rect(
me.X,
me.Y,
me.Width,
me.Height);
}
}
* by“写道”我的意思是“在10分钟内聚集在一起”