close

新增專案名稱 “CameraCapture”

image

加入 references Emgu.CV Emgu.CV.UI Emgu.Util from directory

C:\Emgu\emgucv-windows-universal-cuda 3.0.0.2158\bin

   1: using System;
   2: using System.Collections.Generic;
   3: using System.ComponentModel;
   4: using System.Data;
   5: using System.Drawing;
   6: using System.Linq;
   7: using System.Text;
   8: using System.Windows.Forms;
   9:  
  10: using Emgu.CV;
  11: using Emgu.CV.CvEnum;
  12: using Emgu.CV.Structure;
  13: using Emgu.Util;

Add variables

   1: private Capture m_capture;
   2: private bool m_captureInProgress;
   3: private int m_camIndex = 1;

專案新增x64目錄並加入C:\Emgu\emgucv-windows-universal-cuda 3.0.0.2158\bin\x64目錄下所有dll檔案

image

輸入*.dll按下Enter鍵, 複選全部檔案(方法1:CTRL+a鍵;

方法2:滑鼠點選第一個dll檔案, 按下Shift鍵不放, 點選最後一個dll檔案)

image

設定剛才加入的dll檔案屬性(複製到輸出目錄 = 有更新時才複製)

image

加入x64目錄下dll有個好處, 可以將Release目錄複製到一台沒有安裝Emgu電腦下執行,

缺點是每一個專案都會自己一份dll, 占用不少硬體空間(600多MB)

另一種方式是增加系統變數方式, 讓系統找得到對應的dll檔案即可

==========================================================

設定攝影機FrameGrabber副程式, 框架如下

   1: private void FrameGrabber(object sender, EventArgs e)
   2:   {
   3:   }

定義5張Mat格式變數colorFrame, grayFrame, smallGrayFrame, smoothGrayFrame, cannyFrame

   1: private void FrameGrabber(object sender, EventArgs e)
   2:         {
   3:             using(Mat colorFrame = new Mat())
   4:             using(Mat grayFrame = new Mat())
   5:             using(Mat smallGrayFrame = new Mat())
   6:             using (Mat smoothGrayFrame = new Mat())
   7:             using (Mat cannyFrame = new Mat())
   8:             {
   9:                 m_capture.Retrieve(colorFrame, 0);
  10:                 CvInvoke.CvtColor(colorFrame, grayFrame, ColorConversion.Bgr2Gray);
  11:                 CvInvoke.PyrDown(grayFrame, smallGrayFrame);
  12:                 CvInvoke.PyrUp(smallGrayFrame, smoothGrayFrame);
  13:                 CvInvoke.Canny(smoothGrayFrame, cannyFrame, 100, 60);
  14:  
  15:                 captureImageBox.Image = colorFrame;
  16:                 grayscaleImageBox.Image = grayFrame;
  17:                 smoothedGrayscaleImageBox.Image = smoothGrayFrame;
  18:                 cannyImageBox.Image = cannyFrame;
  19:             }
  20:         }

上述local變數使用using會有一個問題, 當該物件被資源釋放時(IDISPOSABLE),

有可能同時又被指派至imageBox, 這時候就會跳出錯誤訊息

image

測試後改以下列方式(不使用using)

   1:  
   2: Mat colorFrame = new Mat();
   3:            Mat grayFrame = new Mat();
   4:            Mat smallGrayFrame = new Mat();
   5:            Mat smoothGrayFrame = new Mat();
   6:            Mat cannyFrame = new Mat();
   7:            {
   8:                m_capture.Retrieve(colorFrame, 0);
   9:                CvInvoke.CvtColor(colorFrame, grayFrame, ColorConversion.Bgr2Gray);
  10:                CvInvoke.PyrDown(grayFrame, smallGrayFrame);
  11:                CvInvoke.PyrUp(smallGrayFrame, smoothGrayFrame);
  12:                CvInvoke.Canny(smoothGrayFrame, cannyFrame, 100, 60);
  13:                try
  14:                {
  15:                    captureImageBox.Image = colorFrame;
  16:                    grayscaleImageBox.Image = grayFrame;
  17:                    smoothedGrayscaleImageBox.Image = smoothGrayFrame;
  18:                    cannyImageBox.Image = cannyFrame;
  19:                }
  20:                catch (Exception exception)
  21:                {
  22:                    MessageBox.Show(exception.Message);
  23:                }
  24:                GC.Collect();
  25:            }

使用using版本,CameraCapture記憶體固定大概33~35MB,

image

如果不使用using版本, 記憶體可能會飆高到500~700MB甚至更高, 然後才被釋放,

建議可以加入GC.Collect();記憶體固定大概也可以維持在33~35MB

image

附帶一提, GC.Release會花一些時間, 不如將這些變數拉高至Form1成員變數

這樣就不會一直創建/釋放物件

   1: public partial class Form1 : Form
   2:    {
   3:        private Capture m_capture;
   4:        private bool m_captureInProgress;
   5:        private int m_camIndex = 1;
   6:        Mat colorFrame = new Mat();
   7:        Mat grayFrame = new Mat();
   8:        Mat smallGrayFrame = new Mat();
   9:        Mat smoothGrayFrame = new Mat();
  10:        Mat cannyFrame = new Mat();

DoubleBufferOn

   1: private void DoubleBufferOn()
   2: {
   3:     SetStyle(ControlStyles.AllPaintingInWmPaint, true);
   4:     SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
   5:     UpdateStyles();
   6: }

Form1 Constructor

   1: public Form1()
   2: {
   3:     InitializeComponent();
   4:     DoubleBufferOn();
   5:      
   6:     CvInvoke.UseOpenCL = false;
   7:     try
   8:     {
   9:         m_capture = new Capture(m_camIndex);
  10:         this.DoubleBuffered = true;
  11:         m_capture.ImageGrabbed += new EventHandler(FrameGrabber);
  12:     }
  13:     catch (Exception exception)
  14:     {
  15:         MessageBox.Show(exception.Message);
  16:     }
  17: }

Start/Stop Camera

   1: private void captureButton_Click(object sender, EventArgs e)
   2: {
   3:     if (m_capture != null)
   4:     {
   5:         if (m_captureInProgress)
   6:         {
   7:             captureButton.Text = "Start Capture";
   8:             m_capture.Pause();
   9:         }
  10:         else
  11:         {
  12:             captureButton.Text = "Stop Capture";
  13:             m_capture.Start();
  14:         }
  15:         m_captureInProgress = !m_captureInProgress;
  16:     }
  17: }

Flip Horizontally

   1: private void flipHorizontalButton_Click(object sender, EventArgs e)
   2: {
   3:     m_capture.FlipHorizontal = !m_capture.FlipHorizontal;
   4: }
Flip Virtically

   1: private void flipVerticalButton_Click(object sender, EventArgs e)
   2: {
   3:     m_capture.FlipVertical = !m_capture.FlipVertical;
   4: }


範例程式: CameraCapture

參考資料

1. Emgu.CV.Example 3.0.0.2158

2. OpenCL

3. How do I double buffer a Panel in C#?

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 me1237guy 的頭像
    me1237guy

    天天向上

    me1237guy 發表在 痞客邦 留言(0) 人氣()