3

我正在用 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 的发布模式下发生,而不是在调试时发生。

注意2:我认为问题来自于FromBimapImage,因为我尝试了一个WindowsForms应用程序而不是一个应用程序WPF并且没有内存泄漏......

4

4 回答 4

3

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

试试这个:

private void NewFrame(object sender, NewFrameEventArgs args)
{
    Bitmap newFrame = AForge.Imaging.Image.Clone(args.Frame);
    PictureBox.FromBitmapImage(newFrame);
    newFrame.Dispose();
}
于 2013-04-09T19:30:41.020 回答
3

这对我有用。

        if (pictureBox1.Image != null) {
            pictureBox1.Image.Dispose();
        }
        Bitmap bitmap = eventArgs.Frame.Clone() as Bitmap;
        pictureBox1.Image = bitmap;
于 2014-09-09T23:41:20.793 回答
0

在分配新图片之前处理图片框图像可以防止内存泄漏,但是当我调整图片框大小时会出错。问题可能是由于过早地处理图像。它对我有用的是将旧图像保留在队列中,并延迟 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();
  }
}
于 2017-07-25T07:16:08.527 回答
0

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

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

额外的:

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

图片框。图像处理:

    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");
        }
    }
于 2022-01-30T11:36:43.173 回答