我需要从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;
}
答案 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();
通过这种方式,您无需创建新图像。您只需覆盖位图数据。但是请务必始终将数据从源获取到同一缓冲区数组中。