我使用WebCam_Capture.dll从Web摄像机捕获图像到WPF中的Image控件。对于每个捕获的帧,我都有一个称为webCam_imageCaptured的事件。每当我从网络摄像机接收到新图像时,它都会调用。在这种情况下,我调用方法LoadBitmap来获取hBitmap并接收BitmapSource将此捕获的图片放入Image控件。
这是此方法的代码:

[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr handle);
public BitmapSource bs;
public IntPtr ip;
public BitmapSource LoadBitmap(System.Drawing.Bitmap source)
{
   ip = source.GetHbitmap();
   bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(ip, IntPtr.Zero, System.Windows.Int32Rect.Empty,
   System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
   DeleteObject(ip);
   return bs;
}


这是事件的代码:

private void webcam_ImageCaptured(object source, WebcamEventArgs e)
{
    //_frameImage is Image WPF control.
     _frameImage.Source = LoadBitmap((System.Drawing.Bitmap)e.WebCamImage);
}


我在这里漏水! RAM加载高达1 GB,有时甚至更多! DeleteObject(ip)并非在每次调用时都起作用。当RAM为1 GB或更大时,它会释放或显示内存不足错误。如何解决呢?

最佳答案

没有分析器的帮助,甚至没有看到您的其余代码,我几乎可以保证“泄漏”在这里:

_frameImage.Source = LoadBitmap((System.Drawing.Bitmap)e.WebCamImage);


当然,该方法的调用非常快,并且您没有Dispose()Bitmaps。在您调用每个Bitmap上的终结器之后,GC将没有时间进行清理,因此您的内存不足。

完成后,需要在该Dispose()上调用BitmapBitmapSource还是会复制图像数据,因此不需要它。我会尝试这样的:

private void webcam_ImageCaptured(object source, WebcamEventArgs e)
{
    using( Bitmap b = e.WebCamImage )
    {
         _frameImage.Source = LoadBitmap((System.Drawing.Bitmap)e.WebCamImage);
    }
}


当然,这假定在该事件处理程序中处理位图是一件有效的事情(即,其他人是否可以处理此事件?)您可能想在BitmapSource类中公开一个WebCamEventArgs,以便您可以确保没有其他客户端依赖该Bitmap保持有效。

当然,如果您编写的API是with的话。如果没有,您可以编写包装器以确保您的代码实际上不会看到Bitmap并且仅处理WPF图像类型。

10-07 20:11