Difference between revisions of "Camera Capture"

From Emgu CV: OpenCV in .NET (C#, VB, C++ and more)
Jump to navigation Jump to search
(Initial Save)
 
Line 98: Line 98:
  
  
 +
The method <code>ProcessFrame()</code> simply switches between what type of capture event is used either <code>RetrieveBgrFrame()</code> or <code>RetrieveGrayFrame()</code> according to the selected checkbox on the form. The <code>DisplayImage()</code> method is used to display the image in a picture box.
 +
 +
 +
<syntaxhighlight lang="csharp">
 +
        private void ProcessFrame(object sender, EventArgs arg)
 +
        {
 +
            //***If you want to access the image data the use the following method call***/
 +
            //Image<Bgr, Byte> frame = new Image<Bgr,byte>(_capture.RetrieveBgrFrame().ToBitmap());
 +
 +
            if (RetrieveBgrFrame.Checked)
 +
            {
 +
                Image<Bgr, Byte> frame = _capture.RetrieveBgrFrame();
 +
                //because we are using an autosize picturebox we need to do a thread safe update
 +
                DisplayImage(frame.ToBitmap());
 +
            }
 +
            else if (RetrieveGrayFrame.Checked)
 +
            {
 +
                Image<Gray, Byte> frame = _capture.RetrieveGrayFrame();
 +
                //because we are using an autosize picturebox we need to do a thread safe update
 +
                DisplayImage(frame.ToBitmap());
 +
            }
 +
        }
 +
</syntaxhighlight>
 +
 +
 +
The method <code>DisplayImage()</code> is a thread safe method to display the image in a picture box. We don't need this is we set the Sizemode property of the picturebox to 'Normal' or 'StretchMode'. Since we are using the 'Autosize' Sizemode parameter the size of the picture box is managed on the main thread. Without using a thread safe call a cross thread exception will be thrown as an invoke will be required.
 +
 +
<syntaxhighlight lang="csharp">
 +
        private delegate void DisplayImageDelegate(Bitmap Image);
 +
        private void DisplayImage(Bitmap Image)
 +
        {
 +
            if (captureBox.InvokeRequired)
 +
            {
 +
                try
 +
                {
 +
                    DisplayImageDelegate DI = new DisplayImageDelegate(DisplayImage);
 +
                    this.BeginInvoke(DI, new object[] { Image });
 +
                }
 +
                catch (Exception ex)
 +
                {
 +
                }
 +
            }
 +
            else
 +
            {
 +
                captureBox.Image = Image;
 +
            }
 +
        }
 +
</syntaxhighlight>
 +
 +
 +
The method <code>captureButtonClick()</code> looks complex but it's mainly for error checking purposes. As we are allowing the user to set/change the camera according to form settings we need to look for this. This can be done within the <code>SelectedIndexChanged</code> method as an alternative. First we see if the <code>_capture</code> variable has been initiated yet. If not then we call the <code>SetupCapture();</code> method to set the Camera_Identifier and initialise the capture event. We then recall the same event to initialise the the camera as it will instantly fall down to the <code>RetrieveCaptureInformation()</code> method call.
 +
 +
If a the <code>_capture</code> variable has been initialised the we either stop the camera acquiring or check to see if camera selection has changed before restarting the camera. If the camera selection has changed then <code>SelectedIndexChanged</code> is called again to dispose of the old <code>_capture</code> and re-initialise a new one.
 +
 +
<syntaxhighlight lang="csharp">
 +
        private void captureButtonClick(object sender, EventArgs e)
 +
        {
 +
            if (_capture != null)
 +
            {
 +
                if (_captureInProgress)
 +
                { 
 +
                    //stop the capture
 +
                    captureButton.Text = "Start Capture"; //Change text on button
 +
                    Slider_Enable(false);
 +
                    _capture.Pause(); //Pause the capture
 +
                    _captureInProgress = false; //Flag the state of the camera
 +
                }
 +
                else
 +
                {
 +
                    //Check to see if the selected device has changed
 +
                    if (Camera_Selection.SelectedIndex != CameraDevice)
 +
                    {
 +
                        SetupCapture(Camera_Selection.SelectedIndex); //Setup capture with the new device
 +
                    }
 +
                    else
 +
                    {
 +
                        RetrieveCaptureInformation(); //Get Camera information
 +
                        captureButton.Text = "Stop"; //Change text on button
 +
                        StoreCameraSettings(); //Save Camera Settings
 +
                        Slider_Enable(true);  //Enable User Controls
 +
                        _capture.Start(); //Start the capture
 +
                        _captureInProgress = true; //Flag the state of the camera
 +
                    }
 +
                }
 +
               
 +
            }
 +
            else
 +
            {
 +
                //set up capture with selected device
 +
                SetupCapture(Camera_Selection.SelectedIndex);
 +
                //Be lazy and Recall this method to start camera
 +
                captureButtonClick(null, null);
 +
            }
 +
        }
 +
</syntaxhighlight>
 +
 +
 +
The method <code>SetupCapture()</code>
 +
 +
<syntaxhighlight lang="csharp">
 +
</syntaxhighlight>
 +
 +
 +
The method <code>captureButtonClick()</code> is a simple method it records the selected index for the chosen camera provided to the method. Then it disposes of the existing <code>_capture</code> variable if it exists and then attempts to re-initialise a new one.
 +
 +
<syntaxhighlight lang="csharp">
 +
private void SetupCapture(int Camera_Identifier)
 +
        {
 +
            //update the selected device
 +
            CameraDevice = Camera_Identifier;
 +
 +
          //Dispose of Capture if it was created before
 +
            if (_capture != null) _capture.Dispose();
 +
            try
 +
            {
 +
                //Set up capture device
 +
                _capture = new Capture(CameraDevice);
 +
                _capture.ImageGrabbed += ProcessFrame;
 +
            }
 +
            catch (NullReferenceException excpt)
 +
            {
 +
                MessageBox.Show(excpt.Message);
 +
            }
 +
        }
 +
</syntaxhighlight>
 +
 +
 +
The method <code>FlipHorizontalButtonClick()</code> simply sets the FlipHorizontal flag of the <code>_capture</code> variable. Similarly the <code>FlipVerticalButtonClick()</code> method sets the FlipVertical flag. Each one flips the produced frame according to the flag direction.
 +
 +
 +
The method <code>RetrieveCaptureInformation()</code> demonstrates the use of the <code>GetCaptureProperty()</code>. A majority of the variables gathered from this method are simply displayed in the richtextbox on the form. Only Brightness, Contrast, and Sharpness are saved to variables and slider values for adjustment. If a method is invalid it will usually return a '-1'. The commented <code>GetCaptureProperty()</code> calls are used for specific devices. Not all properties are writeable through the SetCaptureProperty(). For more reference see
 +
 +
<syntaxhighlight lang="csharp">
 +
        private void RetrieveCaptureInformation()
 +
        {
 +
            richTextBox1.Clear();
 +
            richTextBox1.AppendText("Camera: " + WebCams[CameraDevice].Device_Name + " (-1 = Unknown)\n\n");
 +
 +
            //Brightness
 +
            richTextBox1.AppendText("Brightness: " + _capture.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_BRIGHTNESS).ToString() + "\n"); //get the value and add it to richtextbox
 +
            Brigtness_SLD.Value = (int)_capture.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_BRIGHTNESS);  //Set the slider value
 +
            Brigthness_LBL.Text = Brigtness_SLD.Value.ToString(); //set the slider text
 +
 +
            //Contrast
 +
            richTextBox1.AppendText("Contrast: " + _capture.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_CONTRAST).ToString() + "\n");//get the value and add it to richtextbox
 +
            Contrast_SLD.Value = (int)_capture.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_CONTRAST);  //Set the slider value
 +
            Contrast_LBL.Text = Contrast_SLD.Value.ToString(); //set the slider text
 +
 +
            //Sharpness
 +
            richTextBox1.AppendText("Sharpness: " + _capture.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_SHARPNESS).ToString() + "\n");
 +
            Sharpness_SLD.Value = (int)_capture.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_CONTRAST);  //Set the slider value
 +
            Sharpness_LBL.Text = Sharpness_SLD.Value.ToString(); //set the slider text
 +
 +
            ....
 +
        }
 +
 +
</syntaxhighlight>
 +
 +
 +
The method <code>StoreCameraSettings()</code>
 +
 +
<syntaxhighlight lang="csharp">
 +
</syntaxhighlight>
 +
 +
 +
The method <code>Refresh_BTN_Click()</code>
 +
 +
<syntaxhighlight lang="csharp">
 +
</syntaxhighlight>
 +
 +
 +
The method <code>Reset_Cam_Settings_Click()</code>
 +
 +
<syntaxhighlight lang="csharp">
 +
</syntaxhighlight>
 +
 +
 +
 +
Region <code>Sliders</code>
 +
 +
 +
The method <code>OnClosing()</code>
  
 
==Methods Available==
 
==Methods Available==

Revision as of 13:57, 20 November 2012

Camera Capture

Namespace

Emgu.CV.Capture

References

EMGU Reference
EMGU CV_PROP Reference
OpenCV Reference

Downloads

Source Code V2.0

Example

The following example shows the use of the Capture function within EMGU. The function of this library is to allow video streaming for web camera type devices and video files. This example will show an example of web camera capture as well as reading and setting properties of the camera. Only some function is available in this version to demonstrate the methods available to the user. A video file example is available here (Pending...).


Software

ScreenShot


Pre-Requisites

The code provided should run straight out of the Emgu.Example folder (V2.4.2), extract it to this location. If the code fails to execute re-reference the EMGU libraries and include the required opencv dlls in the bin directory. Note that the project is set to build to the output path "..\..\..\bin\" you may wish to change this if you don't extract to the EMGU.Example folder.

A Web camera is required for this example.


EMGU Coding Level: While the coding is not advanced the rated level for this example is Intermediate/Beginner. This is not designed as a full on tutorial and general knowledge of the EMGU is expected. While the coding is basic the are several methods involved that may be of putting the newcomers of EMGU.


The Code

The code provided in this sample is basic there is only someo error checking. Support is available through the Forums but please try and examine the code before saying it doesn't work for you. The code is not optimised instead is better formatted to provided an understanding of the stages involved.

Each method is split up to do it's own function while there are several methods in the code the code is not advanced and is often repetitive. The new features introduced in this code is the ability to select the camera source through Direct Show (dll supplied). The code shows the use of two functions for acquiring the frame the others are legacy based and will not work see the Methods Available section. This example also shows how to get and set camera features such as Brightness, Contrast, and Sharpness. While other settings are available only these three attributes are changeable from the form interface. It is easy to add additional support for other settings, these will be made available in future iterations of the example.


The Code: Variables

There are only a few variables in the example separated into two regions the first Camera Capture Variables contains the variables for camera information and the capture device. The Video_Device[] array is a custom structure to store video information this is discussed bellow.

        #region Camera Capture Variables
        private Capture _capture = null; //Camera
        private bool _captureInProgress = false; //Variable to track camera state
        int CameraDevice = 0; //Variable to track camera device selected
        Video_Device[] WebCams; //List containing all the camera available
        #endregion


The second region Camera Settings simply stores the original setting of the camera when it is loaded this is useful in case we need to reset the values to the way we had them.

        #region Camera Settings
        int Brightness_Store = 0;
        int Contrast_Store = 0;
        int Sharpness_Store = 0;
        #endregion


The Code: Methods

As discussed there are several method in the code, they will be decribed in the order that they appear in the code.

The method CameraCapture() is the form initialiser here we disable all our sliders on the form with the method call of Slider_Enable(false). We gather all the video devices available on the system using the Direct Show library (Supplied in the 'Lib' Folder). We populate both an array of Video_Devices and the combo box on the form to enable user selection. Finally we set the combo box to the first index '0' which will be the default device of the OS.

        public CameraCapture()
        {
            InitializeComponent();
            Slider_Enable(false); //Disable sliders untill capturing

            //-> Find systems cameras with DirectShow.Net dll
            //thanks to carles lloret
            DsDevice[] _SystemCamereas = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
            WebCams = new Video_Device[_SystemCamereas.Length];
            for (int i = 0; i < _SystemCamereas.Length; i++)
            {
                WebCams[i] = new Video_Device(i, _SystemCamereas[i].Name, _SystemCamereas[i].ClassID); //fill web cam array
                Camera_Selection.Items.Add(WebCams[i].ToString());
            }
            if (Camera_Selection.Items.Count > 0)
            {
                Camera_Selection.SelectedIndex = 0; //Set the selected device the default
                captureButton.Enabled = true; //Enable the start
            }
            
        }


The method ProcessFrame() simply switches between what type of capture event is used either RetrieveBgrFrame() or RetrieveGrayFrame() according to the selected checkbox on the form. The DisplayImage() method is used to display the image in a picture box.


        private void ProcessFrame(object sender, EventArgs arg)
        {
            //***If you want to access the image data the use the following method call***/
            //Image<Bgr, Byte> frame = new Image<Bgr,byte>(_capture.RetrieveBgrFrame().ToBitmap());

            if (RetrieveBgrFrame.Checked)
            {
                Image<Bgr, Byte> frame = _capture.RetrieveBgrFrame();
                //because we are using an autosize picturebox we need to do a thread safe update
                DisplayImage(frame.ToBitmap());
            }
            else if (RetrieveGrayFrame.Checked)
            {
                Image<Gray, Byte> frame = _capture.RetrieveGrayFrame();
                //because we are using an autosize picturebox we need to do a thread safe update
                DisplayImage(frame.ToBitmap());
            }
        }


The method DisplayImage() is a thread safe method to display the image in a picture box. We don't need this is we set the Sizemode property of the picturebox to 'Normal' or 'StretchMode'. Since we are using the 'Autosize' Sizemode parameter the size of the picture box is managed on the main thread. Without using a thread safe call a cross thread exception will be thrown as an invoke will be required.

        private delegate void DisplayImageDelegate(Bitmap Image);
        private void DisplayImage(Bitmap Image)
        {
            if (captureBox.InvokeRequired)
            {
                try
                {
                    DisplayImageDelegate DI = new DisplayImageDelegate(DisplayImage);
                    this.BeginInvoke(DI, new object[] { Image });
                }
                catch (Exception ex)
                {
                }
            }
            else
            {
                captureBox.Image = Image;
            }
        }


The method captureButtonClick() looks complex but it's mainly for error checking purposes. As we are allowing the user to set/change the camera according to form settings we need to look for this. This can be done within the SelectedIndexChanged method as an alternative. First we see if the _capture variable has been initiated yet. If not then we call the SetupCapture(); method to set the Camera_Identifier and initialise the capture event. We then recall the same event to initialise the the camera as it will instantly fall down to the RetrieveCaptureInformation() method call.

If a the _capture variable has been initialised the we either stop the camera acquiring or check to see if camera selection has changed before restarting the camera. If the camera selection has changed then SelectedIndexChanged is called again to dispose of the old _capture and re-initialise a new one.

        private void captureButtonClick(object sender, EventArgs e)
        {
            if (_capture != null)
            {
                if (_captureInProgress)
                {  
                    //stop the capture
                    captureButton.Text = "Start Capture"; //Change text on button
                    Slider_Enable(false); 
                    _capture.Pause(); //Pause the capture
                    _captureInProgress = false; //Flag the state of the camera
                }
                else
                {
                    //Check to see if the selected device has changed
                    if (Camera_Selection.SelectedIndex != CameraDevice)
                    {
                        SetupCapture(Camera_Selection.SelectedIndex); //Setup capture with the new device
                    }
                    else
                    {
                        RetrieveCaptureInformation(); //Get Camera information
                        captureButton.Text = "Stop"; //Change text on button
                        StoreCameraSettings(); //Save Camera Settings
                        Slider_Enable(true);  //Enable User Controls
                        _capture.Start(); //Start the capture
                        _captureInProgress = true; //Flag the state of the camera
                    }
                }
                
            }
            else 
            {
                //set up capture with selected device
                SetupCapture(Camera_Selection.SelectedIndex);
                //Be lazy and Recall this method to start camera
                captureButtonClick(null, null);
            }
        }


The method SetupCapture()


The method captureButtonClick() is a simple method it records the selected index for the chosen camera provided to the method. Then it disposes of the existing _capture variable if it exists and then attempts to re-initialise a new one.

private void SetupCapture(int Camera_Identifier)
        {
            //update the selected device
            CameraDevice = Camera_Identifier;

           //Dispose of Capture if it was created before
            if (_capture != null) _capture.Dispose();
            try
            {
                //Set up capture device
                _capture = new Capture(CameraDevice);
                _capture.ImageGrabbed += ProcessFrame;
            }
            catch (NullReferenceException excpt)
            {
                MessageBox.Show(excpt.Message);
            }
        }


The method FlipHorizontalButtonClick() simply sets the FlipHorizontal flag of the _capture variable. Similarly the FlipVerticalButtonClick() method sets the FlipVertical flag. Each one flips the produced frame according to the flag direction.


The method RetrieveCaptureInformation() demonstrates the use of the GetCaptureProperty(). A majority of the variables gathered from this method are simply displayed in the richtextbox on the form. Only Brightness, Contrast, and Sharpness are saved to variables and slider values for adjustment. If a method is invalid it will usually return a '-1'. The commented GetCaptureProperty() calls are used for specific devices. Not all properties are writeable through the SetCaptureProperty(). For more reference see

        private void RetrieveCaptureInformation()
        {
            richTextBox1.Clear();
            richTextBox1.AppendText("Camera: " + WebCams[CameraDevice].Device_Name + " (-1 = Unknown)\n\n");

            //Brightness
            richTextBox1.AppendText("Brightness: " + _capture.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_BRIGHTNESS).ToString() + "\n"); //get the value and add it to richtextbox
            Brigtness_SLD.Value = (int)_capture.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_BRIGHTNESS);  //Set the slider value
            Brigthness_LBL.Text = Brigtness_SLD.Value.ToString(); //set the slider text

            //Contrast
            richTextBox1.AppendText("Contrast: " + _capture.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_CONTRAST).ToString() + "\n");//get the value and add it to richtextbox
            Contrast_SLD.Value = (int)_capture.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_CONTRAST);  //Set the slider value
            Contrast_LBL.Text = Contrast_SLD.Value.ToString(); //set the slider text

            //Sharpness
            richTextBox1.AppendText("Sharpness: " + _capture.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_SHARPNESS).ToString() + "\n");
            Sharpness_SLD.Value = (int)_capture.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_CONTRAST);  //Set the slider value
            Sharpness_LBL.Text = Sharpness_SLD.Value.ToString(); //set the slider text

            ....
        }


The method StoreCameraSettings()


The method Refresh_BTN_Click()


The method Reset_Cam_Settings_Click()


Region Sliders


The method OnClosing()

Methods Available

Used


Unused


Bugs

  1. Numbered list If any