Search code examples
c#garbage-collectionkinectemgucv

Kinect & EmguCV & GC


I would like to use Kinect and EmguCV together. I've managed to get images from Kinect and create a EmguCV's Image object. I've run the application for a moment and the application crashes after some time because the memory is not released properly.

The little piece of code gets RGB-color images from Kinect and converts them to HSV-color images. I am not able to work out where the memory is not released. I've used "Using structures" just like the examples I've read on the internet and in some book.

I'd like to get some advice about what I am doing wrongly in the code because I'm not very acquainted with C# and I must have pulled my leg converting image data. I'm interested in seeing other -simple- Kinect + EmguCV projects too, I would be very grateful if you recommend any.

Thanks in advance.

This is the code:

    private void showHSV(Bitmap bmp)
    {
        Image<Bgr, byte> img = new Image<Bgr, byte>(bmp);
        Image<Hsv, byte> imgHsv = img.Convert<Hsv, byte>();

        Bitmap bmp2 = imgHsv.ToBitmap();

        image2.Source = sourceFromBitmap(bmp2);
    }


    private BitmapSource sourceFromBitmap(Bitmap bmp)
    {
        BitmapSource bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
            bmp.GetHbitmap(),
            IntPtr.Zero,
            System.Windows.Int32Rect.Empty,
            BitmapSizeOptions.FromWidthAndHeight(bmp.Width, bmp.Height));

        return bs;
    }

    private void ColorImageReady(object sender, ColorImageFrameReadyEventArgs e)
    {
        using (ColorImageFrame imageFrame = e.OpenColorImageFrame())
        {
            if (imageFrame != null)
            {   
                byte[] pixelData = new byte[imageFrame.PixelDataLength];
                imageFrame.CopyPixelDataTo(pixelData);

                BitmapSource bmp = BitmapImage.Create(imageFrame.Width, imageFrame.Height, 96, 96, PixelFormats.Bgr32, null,
                    pixelData, imageFrame.Width * imageFrame.BytesPerPixel);

                image1.Source = bmp;

                showHSV(bitmapFromSource(bmp));
            }
            else
            {
                // imageFrame is null because the request did not arrive in time          }
            }
        }
    }

    private System.Drawing.Bitmap bitmapFromSource(BitmapSource bitmapsource)
    {
        System.Drawing.Bitmap bitmap;

        using (System.IO.MemoryStream outStream = new System.IO.MemoryStream())
        {
            BitmapEncoder enc = new BmpBitmapEncoder();
            enc.Frames.Add(BitmapFrame.Create(bitmapsource));
            enc.Save(outStream);
            bitmap = new System.Drawing.Bitmap(outStream);   
        }
        return bitmap;
    }

Solution

  • There's a lot of undisposed Bitmaps lying around in the code, let me point them out:

    private void showHSV(Bitmap bmp)
    {
        Image<Bgr, byte> img = new Image<Bgr, byte>(bmp); // Not sure what Image<,> is, but I guess it needs disposing at some point
        Image<Hsv, byte> imgHsv = img.Convert<Hsv, byte>(); // same here
    
        Bitmap bmp2 = imgHsv.ToBitmap(); // bmp2 is never disposed in your code
        var oldBmp = image2.Source;
        image2.Source = sourceFromBitmap(bmp2);
        oldBmp.Dispose() // try this
    }
    
    
    private BitmapSource sourceFromBitmap(Bitmap bmp)
    {
        BitmapSource bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
            bmp.GetHbitmap(),
            IntPtr.Zero,
            System.Windows.Int32Rect.Empty,
            BitmapSizeOptions.FromWidthAndHeight(bmp.Width, bmp.Height));
    
        return bs;
    }
    
    private void ColorImageReady(object sender, ColorImageFrameReadyEventArgs e)
    {
        using (ColorImageFrame imageFrame = e.OpenColorImageFrame())
        {
            if (imageFrame != null)
            {   
                byte[] pixelData = new byte[imageFrame.PixelDataLength];
                imageFrame.CopyPixelDataTo(pixelData);
    
                BitmapSource bmp = BitmapImage.Create(imageFrame.Width, imageFrame.Height, 96, 96, PixelFormats.Bgr32, null,
                    pixelData, imageFrame.Width * imageFrame.BytesPerPixel); // bmp never disposed
    
                var oldBmp = image1.Source;
                image1.Source = bmp;
                oldBmp.Dispose(); // try so
    
                showHSV(bitmapFromSource(bmp)); // what happens inside? bmp needs to be disposed at some point...
            }
            else
            {
                // imageFrame is null because the request did not arrive in time          }
            }
        }
    }
    
    private System.Drawing.Bitmap bitmapFromSource(BitmapSource bitmapsource)
    {
        System.Drawing.Bitmap bitmap;
    
        using (System.IO.MemoryStream outStream = new System.IO.MemoryStream())
        {
            BitmapEncoder enc = new BmpBitmapEncoder();
            enc.Frames.Add(BitmapFrame.Create(bitmapsource));
            enc.Save(outStream);
            bitmap = new System.Drawing.Bitmap(outStream);
        }
        return bitmap;
    }
    

    There's probably more leaks. Basic rule is, every disposable resource (like Bitmap) created (by any means, all pure functions returning Bitmaps create them) need to be disposed after you're done with them.

    Do keep in mind, that you should never dispose a Bitmap if it's currently bound to some Control or used otherwise. Replace it with a fresh one and then dispose of the old one.