Pregunta

Tengo una aplicación WPF en una máquina de ultrasonido que muestra imágenes de ultrasonido generadas en C ++ a una velocidad superior a 30 cuadros por segundo.

Por lo que entiendo, el proceso normal para mostrar imágenes en WPF es crear un BitmapSource para tu imagen y configurar la Fuente para tu Imagen, lo que hace que se invalide y se muestre.

Dado que BitmapSources no implementa IDisposable, el uso de este método me obligó a crear 30 BitmapSources por segundo. Para una imagen de 640x480 con formato 32bppArgb, se trata de una memoria de 30MB / seg asignada a un segundo y luego se desecha la basura cada 10 segundos, lo que provoca un retraso visible. Obviamente no es una solución aceptable.

Mi solución actual es:

En C ++: creo un System.Drawing.Bitmap (WinForms bitmap) en Managed C ++, hago un memcpy desde un puntero para poblar la imagen, usa el objeto Graphics para hacer un dibujo adicional I necesita, y pase esto a C # / WPF durante un evento ImageReceived.

En C # Image.Source se establece en una fuente generada por BitmapBuffer, que es una forma de acceder a los datos en bruto de la fuente del mapa de bits: consulte este enlace. Hago un P / Invocación de CopyMemory para copiar el datos del Bitmap.Scan0 en el BitmapBuffer. Luego invalido la imagen para actualizar la pantalla, y dispongo () el objeto Drawing.Bitmap para liberar la memoria.

Si bien este método ha funcionado por un tiempo, parece muy intrépido y me cuesta creer que no haya otro " apropiado " Manera de hacer esto que a través de la reflexión.

Pregunta: ¿Hay una mejor manera?

¿Fue útil?

Solución

Aquí hay un código que escribí * para crear un alias (compartir memoria) entre un WPF BitmapSource y un GDI Bitmap (para mi propio proyecto)

Obviamente, necesitarás modificarlo para tus propias necesidades, probablemente terminará con menos "hacky". sentir al final.

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

* por " escribió " Me refiero a "tiré juntos en 10 minutos"

Otros consejos

Si está utilizando los últimos bits de WPF, consulte WriteableBitmap , tendrás que hacer más trabajo de pierna, pero las actualizaciones serán realmente rápidas.

Haz un google rápido y obtendrás algunas muestras.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top