Domanda

Ho un'applicazione WPF su una macchina ad ultrasuoni che visualizza immagini ad ultrasuoni generate in C ++ ad una velocità superiore a 30 frame al secondo.

Da quello che ho capito, il normale processo di visualizzazione delle immagini in WPF è quello di creare una BitmapSource per la tua immagine e impostare la Fonte per la tua Immagine, che quindi ne fa invalidare e visualizzare.

Poiché BitmapSources non implementa IDisposable, l'uso di questo metodo mi ha costretto a creare 30 BitmapSource al secondo. Per un'immagine 640x480 con formato 32bppArgb, si tratta di circa 30 MB / sec di memoria allocata al secondo e quindi eliminata ogni 10 secondi, causando un ritardo visibile. Ovviamente non è una soluzione accettabile.

La mia soluzione attualmente è:

In C ++: creo un System.Drawing.Bitmap (bitmap WinForms) in Managed C ++, eseguo un memcpy da un puntatore per popolare l'immagine, usa l'oggetto Graphics per fare qualche disegno aggiuntivo I necessario e passalo al C # / WPF durante un evento ImageReceived.

In C # Image.Source è impostato su una fonte generata da BitmapBuffer, che è un modo hack per accedere ai dati grezzi della fonte bitmap: Vedi questo collegamento. Faccio un P / Invoke of CopyMemory per copiare il dati da Bitmap.Scan0 in BitmapBuffer. Quindi invalido l'immagine per aggiornare lo schermo e dispongo () l'oggetto Drawing.Bitmap per liberare la memoria.

Anche se questo metodo ha funzionato per un po ', sembra molto confuso e trovo difficile credere che non ci siano altri "appropriati". modo di farlo che attraverso la riflessione.

Domanda: esiste un modo migliore?

È stato utile?

Soluzione

Ecco un po 'di codice che ho scritto * per l'aliasing (condivisione della memoria) tra una BitmapSource WPF e una Bitmap GDI (per il mio progetto)

Ovviamente, dovrai modificarlo per le tue esigenze, probabilmente finirà con un meno "hacky" sentirsi alla fine.

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);
    }
}

* di " scritto " Intendo "messo insieme in 10 minuti"

Altri suggerimenti

Se si utilizzano gli ultimi bit WPF, consultare WriteableBitmap , dovrai fare molto di più del lavoro delle gambe ma aggiornerai molto velocemente.

Fai un rapido google e otterrai alcuni esempi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top