13

我在超声波机器上有一个 WPF 应用程序,它以每秒 30 帧以上的速度显示用 C++ 生成的超声波图像。

据我了解,在 WPF 中显示图像的正常过程是为您的图像创建一个 BitmapSource 并为您的图像设置 Source,然后使其无效并显示。

由于 BitmapSources 没有实现 IDisposable,使用这种方法迫使我每秒创建 30 个 BitmapSources。对于具有 32bppArgb 格式的 640x480 图像,这大约是每秒分配 30MB 的内存,然后每 10 秒处理一次垃圾,从而导致明显的延迟。显然不是一个可接受的解决方案。

我目前的解决方案是:

在 C++ 中:我在托管 C++ 中创建 System.Drawing.Bitmap(WinForms 位图),从指针执行 memcpy 以填充图片,使用 Graphics 对象进行一些我需要的额外绘图,并将其传递到 C#/WPF在 ImageReceived 事件期间。

在 C# Image.Source 中设置为由 BitmapBuffer 生成的源,这是一种访问位图源的原始数据的黑客方式:请参阅此链接。我执行 CopyMemory 的 P/Invoke 以将 Bitmap.Scan0 中的数据复制到 BitmapBuffer 中。然后我使 Image 无效以更新屏幕,并 Dispose() Drawing.Bitmap 对象以释放内存。

虽然这种方法已经奏效了一段时间,但它看起来很老套,我很难相信除了通过反射之外没有其他“合适的”方法可以做到这一点。

问:有没有更好的方法?

4

2 回答 2

13

如果您使用最新的 WPF 位,请查看WriteableBitmap,您将不得不做更多的工作,但您将真正快速更新。

做一个快速的谷歌,你会得到一些样本。

于 2009-05-01T18:22:12.147 回答
9

这是我为 WPF BitmapSource 和 GDI 位图(用于我自己的项目)之间的别名(共享内存)编写的一些代码*

显然,您需要根据自己的需要对其进行调整,最终可能会产生一种不那么“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);
    }
}

*“写”是指“10 分钟内拼凑在一起”

于 2009-05-01T17:16:29.217 回答