3

I'm developing an application in C#, and I developed a library that does some stuff with Aforge cameras. One of the points is to simply capture images of what is in front of the Web Cam and show it on a specific PictureBox to do so:

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;
    }

What I do here, I get every frame and paint it into the PictureBox.

My doubt is:

In some computers, this way of painting produces a really high memory leak. The camera configuration is: 640x480, and if it's higher, memory leak increases.

Computer configuration:

Intel i5: memory leak to 500Mb

Intel i7: NO memory leak.

Double coeur (not so powerful): Not so much memory leak.

EDIT:

    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;
    }

I don't understand why I have memory leak in some computers and others not... Any suggestion please?

NOTE: That memory leaks only happen in Release mode on Visual Studio 2010, but not on debug.

NOTE2: I think the problem comes with the FromBimapImage, because I tried a WindowsForms application instead of a WPF one and no memory leak...

Sonhja
  • 8,230
  • 20
  • 73
  • 131

4 Answers4

5

This works for me.

        if (pictureBox1.Image != null) {
            pictureBox1.Image.Dispose();
        }
        Bitmap bitmap = eventArgs.Frame.Clone() as Bitmap;
        pictureBox1.Image = bitmap;
manit
  • 604
  • 7
  • 11
3

AForge owns the bytes of the image, you should make your own deep copy. Passing the frame to the Bitmap constructor is not enough. If the framework is not able to properly dispose the bitmap because you have a reference to it, there's a leak.

Try with this:

private void NewFrame(object sender, NewFrameEventArgs args)
{
    Bitmap newFrame = AForge.Imaging.Image.Clone(args.Frame);
    PictureBox.FromBitmapImage(newFrame);
    newFrame.Dispose();
}
Joan Charmant
  • 2,012
  • 1
  • 18
  • 23
  • I used this way but I still have some memory leaks. I realized that that memory leaks only exist when I'm on release on Visual Studio 2010. Any idea on why? – Sonhja Apr 10 '13 at 08:10
  • Your solution was part of the problem, but I also had to `Freeze` the `BitmapImage` on the memorystream method :) Solved! – Sonhja Apr 10 '13 at 15:48
0

Disposing picture box image right before assigning new one worked to prevent memory leak, but threw errors when I resized the picture box. Probably the problem is due to disposing the image too soon. What it worked for me was to keep old images in a queue, and dispose them with a delay of 5 images. This will give the picture box enough time to catch up.

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();
  }
}
Aleksandar
  • 1,341
  • 1
  • 12
  • 17
0

We use the image in the picturebox as per it's ratio etc, so I do not want to be disposing of it and have a null image in picturebox.image. So this little workaround has proven to be most effective.

We recently deployed to a Windows 7 machine and I noticed the memory leak. I have found that it seems to be picturebox that is "causing" the leak or rather I am causing it by not disposing picturebox.image, as soon as I added the oldImage part to ref the image in picturebox to then dispose of it after setting a new picturebox.image from the new frame, RAM (memory usage) became totally stable. No need to invoke the garbage collector, as someone once said, "if you need to invoke the garbage collector, you are doing something else wrong in the first place". (this works in win10, will test in win7 soon)

Extra:

Also useful for running more than one video feed at a time, is to use a frame toggle integer variable and ++ it every frame, if the frameToggle greater than 2 then set back to 0 and only set the frame to picturebox when frameToggle == 1; Effectively skipping frames. I find this to be very useful for slower machines where image capture frame rate is not all that important.

picturebox.Image disposal:

    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 for performance improvement:

  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");
        }
    }