Как отображать быстро обновляемые изображения без большого выделения памяти?

StackOverflow https://stackoverflow.com/questions/812288

Вопрос

У меня есть приложение WPF на ультразвуковом аппарате, которое отображает ультразвуковые изображения, сгенерированные в C ++, со скоростью более 30 кадров в секунду.

Из того, что я понимаю, обычный процесс отображения изображений в WPF - это создание BitmapSource для вашего изображения и установка Source для вашего изображения, после чего он становится недействительным и отображается.

Поскольку BitmapSources не поддерживают IDisposable, использование этого метода заставило меня создавать 30 BitmapSources в секунду. Для изображения 640x480 с форматом 32bppArgb это примерно 30 МБ / с памяти, которая выделяется в секунду, а затем мусор удаляется каждые 10 секунд, вызывая видимую задержку. Очевидно, что это не приемлемое решение.

Мое настоящее решение:

В C ++: я создаю System.Drawing.Bitmap (растровое изображение WinForms) в Managed C ++, делаю memcpy из указателя для заполнения рисунка, использую объект Graphics для выполнения некоторого дополнительного рисования. I нужно и передать это в C # / WPF во время события ImageReceived.

В C # Image.Source установлен на источник, сгенерированный BitmapBuffer, который является хакерским способом доступа к необработанным данным источника растрового изображения: см. эта ссылка. Я делаю P / Invoke CopyMemory, чтобы скопировать данные из Bitmap.Scan0 в BitmapBuffer. Затем я аннулирую изображение для обновления экрана и Dispose () объект Drawing.Bitmap, чтобы освободить память.

Хотя этот метод работал некоторое время, он кажется очень хакерским, и мне трудно поверить, что другого «подходящего» нет. способ сделать это, чем через отражение.

Вопрос . Есть ли лучший способ?

Это было полезно?

Решение

Вот некоторый код, который я написал * для псевдонимов (совместного использования памяти) между WPF BitmapSource и GDI Bitmap (для моего собственного проекта)

Очевидно, что вам нужно настроить его под свои нужды, скорее всего, в итоге получится менее "хакерский" чувствовать в конце концов.

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 минут"

Другие советы

Если вы используете последние биты WPF, проверьте WriteableBitmap , вам придется проделать большую часть работы, но у вас будут очень быстрые обновления.

Сделайте быстрый Google, и вы получите несколько образцов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top