2013-07-10 36 views
1

我已經從去年2 weeks.I此錯誤耗盡時嘗試了很多,找出並試圖以不同的方式的代碼,但沒有成功yet.I認爲主要的問題是與位圖,可能是我沒有用正確的方式。我分享我的代碼,以幫助理解我在做什麼。內存不足的錯誤,從攝像頭流捕獲

首先,我給你的scenario.In這個程序,我使用數碼單反相機從相機類活view.The主代碼區域是在這裏下面:

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

在形式方面,圖像更新中圖片框只是

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

它使用從camera.This碼位圖和實時取景從相機的框架和寫frame..In一些對象我的情況,我寫上一些氣球的代碼另一個領域框架

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

現在我分享細節問題的全部。 首先,我創建了一個實時視圖窗體,並使用opencv(Emgu)庫,我在框架上繪製氣球。在實時視圖中,這些氣球正在移動。另一種形式是用於從高分辨率的相機捕捉圖像。 我注意到,我的應用程序內存隨着每幀增加,並且在2個實時視圖和2個圖片合併之後,它會變爲1+ GB。如果我試圖再次顯示實時視圖的第一個窗體,則會在UpdatePicture()函數中發生錯誤。 然後我添加代碼以最小化當前應用程序的內存。現在,我在實時視圖中的每幀之後調用此函數。 當這個解決方案,當我檢查應用程序的內存後,它不會超過100MB或200MB。 但問題仍然存在。在捕獲少量數據後,當從流中獲取位圖時,UpdatePicture()發生錯誤(bitmap = new Bitmap(memStream);)。 經過一番搜索,我發現這個解決方案。

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

但是不工作的錯誤仍然是一樣的。有時在UpdatePicture所示()方法

錯誤,有時發生在liveView_NewFrame方法。 手段問題與位圖有關,位圖大小或內存已損壞。 所以請幫助我。我很擔心,2周過去了,但我無法解決這個問題。

+5

這是一個很大的代碼,希望我們的調試。而當拋出OutOfMemoryException時,想到GC已經太晚了 - 它已經盡力而爲,失敗了。無論何時你正在編寫調用'GC'類的代碼(除了'KeepAlive'),你可能做錯了什麼。 –

+1

與其期待我們調試此代碼,您需要在發生OOM異常時捕獲進程轉儲,然後搜索.NET內存泄漏以獲取有關探索轉儲和查找問題的提示和技巧。苔絲費蘭德斯在過去寫了一些很好的博客文章。 –

+0

嘗試在完成對位圖的調用時調用dispose,可能會有所幫助。 – Pharap

回答

3

您呼叫CvInvoke.cvCreateImage創建的數據是坐在機堆
所以它不會被GC收集。
必須調用cvReleaseImage(IntPtr)釋放數據

有很多內存廓線儀,可以幫助瞭解問題的

嘗試使用ANTS Memory Profiler 7

+0

謝謝你makc,我刪除了這個區域的錯誤。沒有這個指針的處理,內存是up and up.But在此之後,我解決了這件事。但我仍然在應用程序中的其他點的錯誤。現在我試圖正確檢查Bitmap對象。 – t4taurus

+0

@ t4taurus我很高興我可以幫助:),嘗試使用任何內存分析器它將幫助找出問題。 – makc