WPF BitmapSource图像显示问题

时间:2018-12-21 05:22:34

标签: c# wpf

我需要从RAW字节阵列显示8k RGB图像,该图像是从wpf控制中的帧抓取器以高fps速度获得的。我能够成功地将字节数组转换为BitmapSource并将其显示在WPF的图像窗口中。但是由于抓取器在显示后以大约5 FPS的速度生成图像,因此我释放了对对象的保留,但是GC需要花费一些时间来收集内存,其中我的应用程序内存增加并冻结了应用程序和系统。如何正确处置使用以下方法创建的BitmapSource(CachedBitmap)。使用后请帮助我处理该物体。

我在更改图像时尝试了GC.Collect(),但是它不起作用。

这是我的字节数组到位图的转换代码,

    int Width = 7680;
    int Height = 4320;
    PixelFormat PixelFormat = PixelFormats.Bgr24;
    int BytesPerPixel = 3;

    public BitmapSource ByteToImage(byte[] imageData)
    {            
        var stride = BytesPerPixel * Width;
        BitmapSource bitmapSource = BitmapSource.Create(Width, Height, 96d, 96d, PixelFormat, null, imageData, stride);
        bitmapSource.Freeze();
        return bitmapSource;
    }

2 个答案:

答案 0 :(得分:0)

这听起来像是合成目标渲染的可能候选者,请尝试将其添加到MainWindow构造函数中:

CompositionTarget.Rendering += CompositionTarget_Rendering;

然后实现函数本身:

void CompositionTarget_Rendering(object sender, EventArgs e)
{
    // dispose previous image, create and assign the new one
}

正确执行此操作,它还应处理目标计算机无法跟上所需帧速率的情况。

更新:BitmapSource仅使用常规内存,因此正确的行为是允许GC对其进行清理。如果您的情况没有发生,则意味着某些原因由于某种原因(可能是显示)而使该内存保持不变。这是一个使用CompositionTarget.Rendering的示例,我在收集之前和之后都转储了GC内存,因此您可以很清楚地看到它已被正确收集:

    public MainWindow()
    {
        InitializeComponent();
        CompositionTarget.Rendering += CompositionTarget_Rendering;
    }       

    private void CompositionTarget_Rendering(object sender, EventArgs e)
    {
        // remove reference to old image
        this.theImage.Source = null;

        // invoke GC
        Debug.WriteLine(GC.GetTotalMemory(false));
        GC.Collect();
        Debug.WriteLine(GC.GetTotalMemory(false));

        // create and assign new image
        const int width = 1000;
        const int height = 1000;
        var pixels = new uint[width * height];
        uint color = (uint)((new Random((int)DateTime.Now.Ticks)).Next(0x1000000) | 0xff000000);
        for (int i = 0; i < width * height; i++)
            pixels[i] = color;
        this.theImage.Source = BitmapSource.Create(width, height, 96, 96, PixelFormats.Bgra32, null, pixels, width * 4);
    }

答案 1 :(得分:0)

可能您应该尝试可写位图:

        WriteableBitmap writeableBitmap = new WriteableBitmap(
            (int)width,
            (int)height,
            96,
            96,
            PixelFormats.Bgr32,
            null);

        int stride = width * writeableBitmap.Format.BitsPerPixel / 8

现在,当您收到帧时,可以将其写入可写位图:

        writeableBitmap.Lock();
        writeableBitmap.WritePixels(new Int32Rect(0, 0, width, height), imageData, stride, 0);
        writeableBitmap.Unlock();

通过这种方式,您无需创建新图像。您只需覆盖位图数据。但是请务必始终将数据从源获取到同一缓冲区数组中。

相关问题