9

好的,我一直在尝试对来自网络摄像头的视频源做一些特定的事情。我有一个 Lumenera Infinity 2 显微镜,我正试图从中提取饲料,并希望能够在饲料进入时对其进行修改。由于我找不到使用视频源播放器的方法,所以我决定改为将每一帧(相机最大 15fps)拉为位图,以便我可以在那里进行修改。

问题是:我有一个巨大的内存泄漏。当我只使用 videoSourcePlayer 运行视频时,它徘徊在使用大约 30 兆。当我将帧作为位图运行时,它会在几秒钟内破坏 1 gig 的内存。

我在这里错过了什么?我认为自动垃圾收集会在旧框架变得无法访问时将它们铲起。我应该尝试在位图上强制垃圾收集吗?或者它完全是别的东西,我很想念它。

FilterInfoCollection captureDevices;
VideoCaptureDevice cam;
Bitmap bitmap;

public Form1()
{
  InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
  try
  {
    captureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);

    if (captureDevices.Count == 0)
      throw new ApplicationException();

    CameraSelectComboBox.Items.Clear();

    foreach (FilterInfo device in captureDevices)
    {
      CameraSelectComboBox.Items.Add(device.Name);
    }

    CameraSelectComboBox.SelectedIndex = 0;
    CameraSelectComboBox.Enabled = true;
  }
  catch (ApplicationException)
  {
    CameraSelectComboBox.Enabled = false;
  }
}

private void connectButton_Click(object sender, EventArgs e)
{
  cam = new VideoCaptureDevice(captureDevices[CameraSelectComboBox.SelectedIndex].MonikerString);
  cam.NewFrame -= Handle_New_Frame; //Just to avoid the possibility of a second event handler being put on
  cam.NewFrame += new AForge.Video.NewFrameEventHandler(Handle_New_Frame);
  videoSourcePlayer1.Visible = false;
  cam.Start();

  //videoPictureBox1.Visible = false;
  //videoSourcePlayer1.VideoSource = new VideoCaptureDevice(captureDevices[CameraSelectComboBox.SelectedIndex].MonikerString);
  //videoSourcePlayer1.Start();
}

private void Handle_New_Frame(object sender, NewFrameEventArgs eventArgs)
{
  bitmap = (Bitmap)eventArgs.Frame.Clone();

  videoPictureBox1.Image = bitmap;
}
4

2 回答 2

2

Try this:

private void Handle_New_Frame(object sender, NewFrameEventArgs eventArgs)
{
    if(bitmap != null)
        bitmap.Dispose();
    bitmap = new Bitmap(eventArgs.Frame);

    if(videoPictureBox1.Image != null)
        this.Invoke(new MethodInvoker(delegate() {videoPictureBox1.Image.Dispose();}));
    videoPictureBox1.Image = bitmap;
}

It solved some of the memory leaks I experienced with Aforge and PictureBoxes, but the VideoSourcePlayer is much better where memory consumption is concerned.

于 2013-04-15T14:29:29.380 回答
2

我认为这是一个可以改进的领域:

cam = new 
  VideoCaptureDevice(captureDevices[CameraSelectComboBox.SelectedIndex].MonikerString);

cam.NewFrame -= Handle_New_Frame; // you're pointing to the new instance of VCD, so this will have no effect.

cam.NewFrame += new AForge.Video.NewFrameEventHandler(Handle_New_Frame);
videoSourcePlayer1.Visible = false;
cam.Start();

每次按下连接按钮时,该代码块都会占用内存。

您几乎需要在主级别参考 VCD。所以在 Form1 类级别定义一个成员变量:

private VideoCaptureDevice _cameraContext;

在连接事件处理程序中,执行以下操作:

if (_camerContext != null)
{
  _cameraContext.NewFrame -= Handle_New_Frame;
}
_cameraContext = new VideoCaptureDevice(blah blah blah);
_cameraContext.NewFrame += Handle_New_Frame;
videoSourcePlayer1.Visible = false;
_cameraContext.Start();

顺便说一句,我假设您是 .NET 3.5 或更高版本,因此使用了新的委托分配语法。

于 2013-04-15T14:25:55.357 回答