Pergunta

Eu tenho um aplicativo WPF em uma máquina de ultra-som que exibe ultra-som imagens geradas em C ++ a uma velocidade mais de 30 quadros por segundo.

Pelo que eu entendo, o processo normal para exibir imagens em WPF é criar um BitmapSource para a sua imagem e definir a fonte para a sua imagem, que, em seguida, faz com que ele invalidar e display.

Desde BitmapSources não implementar IDisposable, usando este método me obrigou a criar 30 BitmapSources por segundo. Para uma imagem 640x480 com formato 32bppArgb, este é de cerca de 30MB / seg de memória que está sendo atribuído um segundo e, em seguida, o lixo descartado a cada 10 segundos, causando lag visível. Obviamente não é uma solução aceitável.

Meu atualmente solução é:

Em C ++: eu crio um (bitmap WinForms) System.Drawing.Bitmap em Managed C ++, fazer um memcpy de um ponteiro para preencher o quadro, use o objeto Graphics para fazer algum desenho que eu adicional necessidade, e passar isso para o C # / WPF durante um evento ImageReceived.

Em C # Image.Source está definido para uma fonte gerado pelo BitmapBuffer, que é um hack-maneira de acessar os dados brutos da fonte de bitmap: Veja este link. eu um P / Invoke de CopyMemory para copiar o dados do Bitmap.Scan0 no BitmapBuffer. Eu então invalidar a imagem para atualizar a tela, e Dispose () do objeto Drawing.Bitmap para liberar a memória.

Enquanto este método tem funcionado por um tempo, parece muito hacky e acho que é difícil acreditar que não há nenhuma outra maneira "apropriada" para fazer isso do que através da reflexão.

Pergunta:? Existe uma maneira melhor

Foi útil?

Solução

Aqui está algum código que eu escrevi * para aliasing (compartilhamento de memória) entre um WPF BitmapSource e um bitmap GDI (para o meu próprio projeto)

Obviamente, você precisa ajustá-lo para suas próprias necessidades, ele provavelmente vai acabar com uma sensação menos "hacky" no 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 "escreveu" Quero dizer "jogou juntos em 10 minutos"

Outras dicas

Se você estiver usando os mais recentes pedaços WPF verificar WriteableBitmap , você vai ter que fazer mais do trabalho de perna, mas você vai atualizações muito rápido.

Fazer um google rápido e você vai ter algumas amostras.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top