t4taurus
t4taurus

Reputation: 465

Out of Memory error during stream capture from camera

I have been exhausted from this error from last 2 weeks.I tried a lot to find out and tried the code in different way but not succeeded yet.I think the main problem is with bitmap, may be i am not using in right way.I am sharing my code for help to understand what i am doing.

First i tell you the scenario.In this app, i am using dslr camera for live view.The main code area from camera class is here below :

internal void Run()
{
    LVrunning = true;
    while (LVrunning)
    {
        Thread.Sleep(20);
        if (LVrunning)
            UpdatePicture();
    }
}

private void UpdatePicture()
{
    try
    {
        if (err == EDSDK.EDS_ERR_OK && LVrunning)
        {
            inSide = true;

            // Download live view image data
            err = EDSDK.EdsDownloadEvfImage(cameraDev, EvfImageRef);

            if (err != EDSDK.EDS_ERR_OK)
            {
                Debug.WriteLine(String.Format("Download of Evf Image: {0:X}", err));
                return;
            }
            IntPtr ipData;
            err = EDSDK.EdsGetPointer(MemStreamRef, out ipData);
            if (err != EDSDK.EDS_ERR_OK)
            {
                Debug.WriteLine(String.Format("EdsGetPointer failed: {0:X}", err));
                return;
            }

            uint len;
            err = EDSDK.EdsGetLength(MemStreamRef, out len);
            if (err != EDSDK.EDS_ERR_OK)
            {
                Debug.WriteLine(String.Format("EdsGetLength failed:{0:X}", err));
                EDSDK.EdsRelease(ipData);
                return;
            }

            Byte[] data = new byte[len];
            Marshal.Copy(ipData, data, 0, (int)len);
            System.IO.MemoryStream memStream = new System.IO.MemoryStream(data);

            // get the bitmap
            Bitmap bitmap = null;
            try
            {
                bitmap = new Bitmap(memStream);
            }
            catch (OutOfMemoryException ex)
            {
                GC.WaitForPendingFinalizers();
                bitmap = new Bitmap(memStream); // sometimes error occur
            }

            NewFrame(bitmap, null); // this is event call back to form area.

            memStream.Dispose();
            EDSDK.EdsRelease(ipData);
        }
    }
    catch (Exception ex)
    {

    }
}
private void getCapturedItem(IntPtr directoryItem)
{
    uint err = EDSDK.EDS_ERR_OK;
    IntPtr stream = IntPtr.Zero;

    EDSDK.EdsDirectoryItemInfo dirItemInfo;

    err = EDSDK.EdsGetDirectoryItemInfo(directoryItem, out dirItemInfo);

    if (err != EDSDK.EDS_ERR_OK)
    {
        throw new CameraException("Unable to get captured item info!", err);
    }

    //  Fill the stream with the resulting image
    if (err == EDSDK.EDS_ERR_OK)
    {
        err = EDSDK.EdsCreateMemoryStream((uint)dirItemInfo.Size, out stream);
    }

    //  Copy the stream to a byte[] and
    if (err == EDSDK.EDS_ERR_OK)
    {
        err = EDSDK.EdsDownload(directoryItem, (uint)dirItemInfo.Size, stream);
    }

    //  Create the returned item
    //CapturedItem item = new CapturedItem();
    if (dirItemInfo.szFileName.ToString().ToLower().Contains("jpg") || dirItemInfo.szFileName.ToString().ToLower().Contains("jpeg"))
    {
        if (err == EDSDK.EDS_ERR_OK)
        {
            IntPtr imageRef = IntPtr.Zero;

            err = EDSDK.EdsCreateImageRef(stream, out imageRef);

            if (err == EDSDK.EDS_ERR_OK)
            {
                EDSDK.EdsImageInfo info;
                err = EDSDK.EdsGetImageInfo(imageRef, EDSDK.EdsImageSource.FullView, out info);
            }
        }
    }

    if (err == EDSDK.EDS_ERR_OK)
    {
        try
        {
            byte[] buffer = new byte[(int)dirItemInfo.Size];
            GCHandle gcHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
            IntPtr address = gcHandle.AddrOfPinnedObject();
            IntPtr streamPtr = IntPtr.Zero;
            err = EDSDK.EdsGetPointer(stream, out streamPtr);
            if (err != EDSDK.EDS_ERR_OK)
            {
                throw new CameraDownloadException("Unable to get resultant image.", err);
            }

            try
            {
                Marshal.Copy(streamPtr, buffer, 0, (int)dirItemInfo.Size);//sometimes error comes here
                System.IO.MemoryStream memStream = new System.IO.MemoryStream(buffer);

                    Bitmap bitmap = null;
                    try
                    {
                        bitmap = new Bitmap(memStream);
                    }
                    catch (OutOfMemoryException ex)
                    {
                        GC.WaitForPendingFinalizers();
                        Bitmap b = new Bitmap(memStream);//sometimes error comes here
                    }

                    if (bitmap != null)
                    {


                            PhotoCaptured(bitmap, null);

                    }

            }
            catch (AccessViolationException ave)
            {
                throw new CameraDownloadException("Error copying unmanaged stream to managed byte[].", ave);
            }
            finally
            {
                gcHandle.Free();
                EDSDK.EdsRelease(stream);
                EDSDK.EdsRelease(streamPtr);
            }
        }
        catch (OutOfMemoryException ex)
        {
            GC.WaitForPendingFinalizers();
            IboothmeObject.minimizeMemory();
            getCapturedItem(directoryItem);
        }
    }
    else
    {
        throw new CameraDownloadException("Unable to get resultant image.", err);
    }
}

On form side, image is updating in picture box simply

private void StartLiveView()
    {
        if (this.liveView.Connected)
        {
            this.liveView.PhotoCaptured += new EventHandler(liveView_PhotoCaptured);
            this.liveView.NewFrame += new EventHandler(liveView_NewFrame);
            this.liveView.StartLiveView();

        }
    }

    void liveView_NewFrame(object sender, EventArgs e)
    {
        this.picMain.Image = sender as Image;
    }
    void liveView_PhotoCaptured(object sender, EventArgs e)
    {
        Image img = sender as Image;
        // this image is big in size like 5000x3000.
        Bitmap tempbitmap = new Bitmap(img.Width, img.Height);// now mostly error comes here
        tempbitmap.SetResolution(img.HorizontalResolution, img.VerticalResolution);
            using (Graphics g = Graphics.FromImage(tempbitmap))
            {
                g.DrawImage(img, new Rectangle(0, 0, img.Width, img.Height));
                g.Save();
            }
        picMain.Image = tempbitmap;
        tempbitmap.Save(path,ImageFormat.Jpeg);
    }

Another area of code which uses the bitmap and live view from camera.This code get the frame from camera and write some objects on frame..In my case, i am writing some ballons on the frame

void liveView_NewFrame(object sender, EventArgs e)
    {
        using (Image<Bgr, byte> Frame = new Image<Bgr, byte>(new Bitmap(sender as Image)))
        {
            Frame._SmoothGaussian(3);
            IntPtr hsvImage = CvInvoke.cvCreateImage(CvInvoke.cvGetSize(Frame), Emgu.CV.CvEnum.IPL_DEPTH.IPL_DEPTH_8U, 3);
            CvInvoke.cvCvtColor(Frame, hsvImage, Emgu.CV.CvEnum.COLOR_CONVERSION.CV_BGR2HSV);

            Image<Gray, byte> imgThresh = new Image<Gray, byte>(Frame.Size);
            imgThresh.Ptr = GetThresholdedImage(hsvImage);
            //CvInvoke.cvSmooth(imgThresh, imgThresh, Emgu.CV.CvEnum.SMOOTH_TYPE.CV_GAUSSIAN, 3, 3, 3, 3);

            #region Draw the contours of difference
            //this is tasken from the ShapeDetection Example
            Rectangle largest = new Rectangle();
            try
            {
                using (MemStorage storage = new MemStorage()) //allocate storage for contour approximation
                    //detect the contours and loop through each of them
                    for (Contour<Point> contours = imgThresh.Convert<Gray, Byte>().FindContours(
                          Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE,
                          Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_EXTERNAL,
                          storage);
                       contours != null;
                       contours = contours.HNext)
                    {
                        //Create a contour for the current variable for us to work with
                        Contour<Point> currentContour = contours.ApproxPoly(contours.Perimeter * 0.05, storage);

                        //Draw the detected contour on the image
                        if (currentContour.Area > ContourThresh) //only consider contours with area greater than 100 as default then take from form control
                        {
                            if (currentContour.BoundingRectangle.Width > largest.Width && currentContour.BoundingRectangle.Height > largest.Height)
                            {
                                largest = currentContour.BoundingRectangle;
                            }
                        }
                        //storage.Dispose();
                    }

            }
            catch (Exception)
            {

            }

            #endregion

            #region Draw Object
            Random r = new Random();
            //Bitmap bb = Frame.Bitmap;
            foreach (var item in objectList)
            {
                using (Graphics g = Graphics.FromImage(Frame.Bitmap))
                {
                    if (DrawAble(item, largest))
                    {
                        if (item.Y < 0)
                        {
                            if (item.X < picMain.Width)
                            {
                                g.DrawImage(item.image, new Rectangle(item.X, 0, item.image.Width, item.image.Height + item.Y),
                                    new Rectangle(), GraphicsUnit.Pixel);
                                item.X += r.Next(-5, 5);
                                item.Y += 15;
                            }
                        }
                        else
                        {
                            if (item.X < picMain.Width && item.Y < picMain.Height)
                            {
                                g.DrawImage(item.image, new Rectangle(item.X, item.Y, item.image.Width, item.image.Height));
                                item.X += r.Next(-5, 5);
                                item.Y += 15;
                            }
                            else
                            {
                                item.X = r.Next(0, picMain.Width - 5);
                                item.Y = r.Next(-item.image.Height, -5);
                            }

                        }
                    }
                    else
                    {
                        item.X = r.Next(0, picMain.Width - 5);
                        item.Y = r.Next(-item.image.Height, -5);
                    }

                }
            }

            #endregion

            picMain.Image = Frame.ToBitmap();

        }

        minimizeMemory();
    }

Now i share the whole problem in detail. First on all i created a form for live view and by using opencv(Emgu) library , i am drawing balloons on the frame.In live view these balloons are moving.The other form is for capture the picture from camera with high resolution. I noticed that, my application memory was increasing with every frame and after 2 live-view and 2 pictures caputured, it goes to 1+ GB.If i tried to show first form again for live view, error occured in UpdatePicture() function. then i add the code to minimize the memory of the current application.now i am calling this function after every frame in live-view. After this solution when i checked the memory of application it does not go over 100mb or 200mb. But problem was still there.after few captures, error occurred in UpdatePicture() when get bitmap from stream ( bitmap = new Bitmap(memStream);).The error was same out of memory. After some search i found this solution.

// get the bitmap
        Bitmap bitmap = null;
        try
        {
            bitmap = new Bitmap(memStream);
        }
        catch (OutOfMemoryException ex)
        {
            GC.WaitForPendingFinalizers();
            bitmap = new Bitmap(memStream);
        }

But not working error is still same.

Error sometimes shown in UpdatePicture() method, sometime occurred in liveView_NewFrame method. Means problem is related to bitmap, bitmap size or memory is corrupt. So please help me.I am worried, 2 weeks passed but i could not solve this.

Upvotes: 1

Views: 2392

Answers (1)

makc
makc

Reputation: 2579

you are calling CvInvoke.cvCreateImage the created data is sitting on the native heap
so it wont be collected by the GC.
you must call cvReleaseImage(IntPtr) to release the data

there are alot of memory profilers which can help understanding the issue

try using ANTS Memory Profiler 7

Upvotes: 3

Related Questions