【问题标题】:AForge camera memory leakAForge 相机内存泄漏
【发布时间】:2013-04-09 10:53:03
【问题描述】:

我正在用 C# 开发一个应用程序,并且我开发了一个库来处理 Aforge 相机的一些事情。要点之一是简单地捕获网络摄像头前的图像并将其显示在特定的PictureBox 上:

camera.NewFrame += NewFrame;

private void NewFrame(object sender, NewFrameEventArgs args)
    {
        Bitmap newFrame = new Bitmap(args.Frame);
        args.Frame.Dispose();
        PictureBox.FromBitmapImage(newFrame);
        newFrame.Dispose();
        newFrame = null;
    }

我在这里做什么,我把每一帧都画到PictureBox

我的疑问是:

在某些计算机中,这种绘制方式会产生非常高的内存泄漏。摄像头配置为:640x480,如果更高,内存泄漏会增加。

电脑配置:

Intel i5:内存泄漏到 500Mb

Intel i7:没有内存泄漏。

双心(没那么强大):没有那么多内存泄漏。

编辑:

    public static void FromBitmapImage(this Image image, Bitmap bitmap)
    {
        BitmapImage bitmapImage = new BitmapImage();

        using (MemoryStream memoryStream = new MemoryStream())
        {
            bitmap.Save(memoryStream, ImageFormat.Bmp);
            memoryStream.Position = 0;
            bitmapImage.BeginInit();
            bitmapImage.StreamSource = memoryStream;
            bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
            bitmapImage.EndInit();
        }

        image.Source = bitmapImage;
        bitmapImage = null;
    }

我不明白为什么我在某些计算机中会出现内存泄漏,而在其他计算机中却没有...请问有什么建议吗?

注意:内存泄漏仅在 Visual Studio 2010 的发布模式下发生,而不是在调试时发生。

NOTE2:我认为问题出在FromBimapImage,因为我尝试了WindowsForms 应用程序而不是WPF 应用程序并且没有内存泄漏...

【问题讨论】:

  • PictureBox.FromBitmapImage(Bitmap) 方法是什么,它返回什么?

标签: memory-leaks camera aforge


【解决方案1】:

AForge owns 图像的字节,您应该制作自己的deep副本。将帧传递给 Bitmap 构造函数是不够的。如果框架因为您对位图的引用而无法正确处理位图,则存在泄漏。

试试这个:

private void NewFrame(object sender, NewFrameEventArgs args)
{
    Bitmap newFrame = AForge.Imaging.Image.Clone(args.Frame);
    PictureBox.FromBitmapImage(newFrame);
    newFrame.Dispose();
}

【讨论】:

  • 我用过这种方式,但还是有一些内存泄漏。我意识到只有当我在 Visual Studio 2010 上发布时才存在内存泄漏。知道为什么吗?
  • 您的解决方案是问题的一部分,但我还必须 Freeze BitmapImage 对 memorystream 方法 :) 解决!
【解决方案2】:

这对我有用。

        if (pictureBox1.Image != null) {
            pictureBox1.Image.Dispose();
        }
        Bitmap bitmap = eventArgs.Frame.Clone() as Bitmap;
        pictureBox1.Image = bitmap;

【讨论】:

    【解决方案3】:

    在分配新图片之前处理图片框图像可以防止内存泄漏,但是当我调整图片框大小时会出错。问题可能是由于过早地处理图像。它对我有用的是将旧图像保留在队列中,并延迟 5 个图像处理它们。这将使图片框有足够的时间赶上。

    private Queue<Image> _oldImages = new Queue<Image>();
    ...
    
    if (pictureBox1.Image != null)
    {
      _oldImages.Enqueue(pictureBox1.Image);
      if (_oldImages.Count > 5) 
      {
        var oldest = _oldImages.Dequeue();
        oldest.Dispose();
      }
    }
    

    【讨论】:

      【解决方案4】:

      我们根据它的比例等使用图片框中的图像,所以我不想处理它并且在picturebox.image中有一个空图像。因此,这个小变通方法已被证明是最有效的。

      我们最近部署到一台 Windows 7 机器上,我注意到内存泄漏。 我发现它似乎是“导致”泄漏的图片框,或者更确切地说是我通过不处理图片框。来自新框架的新picturebox.image,RAM(内存使用)变得完全稳定。不需要调用垃圾收集器,正如有人曾经说过的那样,“如果你需要调用垃圾收集器,那么你首先做错了什么”。 (这个在win10下有效,很快会在win7中测试)

      额外:

      对于一次运行多个视频源也很有用,是使用帧切换整数变量并在每一帧 ++ 它,如果 frameToggle 大于 2 则设置回 0 并且仅在以下情况下将帧设置为图片框框架切换 == 1;有效地跳帧。我发现这对于图像捕获帧速率不是那么重要的速度较慢的机器非常有用。

      picturebox.图像处理:

          private void VideoFeedCustID_NewFrame(object sender, NewFrameEventArgs eventArgs)
          {
              try
              {
                  if (eventArgs.Frame != null)
                  {
                      Image oldImage = CustIDPictureBox.Image; 
                      CustIDPictureBox.Image = (Bitmap)eventArgs.Frame.Clone();
                      if (oldImage != null) { oldImage.Dispose(); }
                  }
              }
              catch (Exception ex)
              {
                  custIDCameraActive = false;
                  MessageBox.Show("Camera Settings Frame Feed - Error: \n\n" + ex.Message, "Error");
              }
          }
      

      FrameToggle 用于提高性能:

        private void VideoFeedCustID_NewFrame(object sender, NewFrameEventArgs eventArgs)
          {
              try
              {
                  if (frameToggle == 1)
                  {
                      if (eventArgs.Frame != null)
                      {
                          Image oldImage = CustIDPictureBox.Image;
                          CustIDPictureBox.Image = (Bitmap)eventArgs.Frame.Clone();
                          if (oldImage != null) { oldImage.Dispose(); }
                      }
                  }
                  else if (frameToggle > 3)
                  {
                      frameToggle = 0;
                  }
                  frameToggle++;
              }
              catch (Exception ex)
              {
                  custIDCameraActive = false;
                  MessageBox.Show("Camera Settings Frame Feed - Error: \n\n" + ex.Message, "Error");
              }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-15
        • 2015-08-16
        • 2013-01-25
        • 1970-01-01
        • 2017-07-14
        相关资源
        最近更新 更多