Question

J'ai une application WPF sur une machine à ultrasons qui affiche des images ultrasonores générées en C ++ à une vitesse supérieure à 30 images par seconde.

De ce que je comprends, le processus normal d'affichage d'images dans WPF consiste à créer un BitmapSource pour votre image et à définir la source de votre image, ce qui entraîne l'invalidation et l'affichage.

Comme BitmapSources n’implémente pas IDisposable, l’utilisation de cette méthode m’a obligé à créer 30 BitmapSources par seconde. Pour une image 640x480 au format 32bppArgb, cela correspond à environ 30 Mo / s de mémoire allouée pendant une seconde, puis à une poubelle supprimée toutes les 10 secondes, ce qui entraîne un retard visible. De toute évidence pas une solution acceptable.

Ma solution actuelle est la suivante:

En C ++: je crée un System.Drawing.Bitmap (bitmap WinForms) en C ++ managé, crée une mémoire à partir d'un pointeur pour remplir la photo et utilise l'objet Graphiques pour effectuer un dessin supplémentaire. besoin, et transmettez-le au C # / WPF lors d’un événement ImageReceived.

En C # Image.Source est défini sur une source générée par BitmapBuffer, qui permet d'accéder aux données brutes de la source bitmap: voir ce lien. Je fais un P / Invoke de CopyMemory pour copier le données de Bitmap.Scan0 dans BitmapBuffer. J'invalide ensuite l'image pour mettre à jour l'écran et je supprime () l'objet Drawing.Bitmap pour libérer la mémoire.

Bien que cette méthode fonctionne depuis un moment, elle semble très utile et j’ai du mal à croire qu’il n’existe pas d’autre solution "appropriée". façon de le faire que par la réflexion.

Question: Y a-t-il un meilleur moyen?

Était-ce utile?

La solution

Voici le code que j'ai écrit * pour la création d'alias (partage de mémoire) entre un bitmapSource WPF et un bitmap GDI (pour mon propre projet)

De toute évidence, vous devrez le modifier pour vos propres besoins, il se terminera probablement avec un moins "hacky". sentir à la fin.

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

* par " écrit " Je veux dire "jeté ensemble en 10 minutes"

Autres conseils

Si vous utilisez les derniers bits WPF, extrayez-vous WriteableBitmap , vous devrez effectuer davantage de travail sur les jambes, mais vous effectuerez des mises à jour très rapides.

Faites un rapide google et vous aurez des exemples.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top