CompareImages - Difference

From Emgu CV: OpenCV in .NET (C#, VB, C++ and more)
Jump to: navigation, search

Compare Image: Difference

Namespace

Emgu.CV

References

EMGU Reference
OpenCV Use Reference

Downloads

Source Code V1.0

Example

The following example shows the use of the AbsDiff() method within EMGU. The function of this method is to calculate the absolute difference between two images by subtracting one from the other and taking the absolute value.


Software

ABSDifff 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 to run this source code.

EMGU Coding Level: While the coding is not advanced the rated level for this example is Beginer/Intermediate. The code is simple and well commented although to understand the use of the method call some experience with EMGU is expected.


The Code

The code provided in this sample is basic there is little or no 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.

The program is fairly simple in its application of the AbsDiff() method. Two frames successively acquired from the webcam are used to look for a difference between them. The previous frame acquired is subtracted from the current frame ant the absolute values shown in the resultant picture box.


The Code: Variables

The _capture variable simply holds details about the image acquisition device

        Capture _capture;


The Image variables hold information about the current frame, previous frame, and their difference. They are named suitably for their role.

        Image<Bgr, Byte> Frame; //current Frame from camera
        Image<Bgr, Byte> Previous_Frame; //Previiousframe aquired
        Image<Bgr, Byte> Difference; //Difference between the two frames


The two variables ContourThresh and Threshold are used to classify movement within the frame. The threshold sets the difference caused by movement to be considered, while ContourThresh is the region size to be marked as movement. The lower the ContourThresh and Threshold the less movement will be suppressed.

        double ContourThresh = 0.003; //stores alpha for thread access
        int Threshold = 60; //stores threshold for thread access


The Code: Methods

The capture device is initialised to the default device in the public Form1() method. This code is not designed to deal with camera capture specifics see here for further reference. The key method of interest is the ProcessFrame() method. This is where the movement between frames is established it is split up into two parts. 2 frames or images are required to calculate the AbsDiff(). The if statement checks to see if a Frame variable is null, this will only occur when the first frame is acquired as it's not been written to yet. Here the frame will be saved into Frame and the Previous_Frame variables. This results in the else statement executing from now on and two frames being available for the AbsDiff() calculation.

            if (Frame == null) //we need at least one fram to work out running average so acquire one before doing anything
            {
                //display the frame aquired
                Frame = _capture.RetrieveBgrFrame(); //we could use RetrieveGrayFrame if we didn't care about displaying colour image
                DisplayImage(Frame.ToBitmap(), CurrentFrame); //display the image using thread safe call
                Previous_Frame = Frame.Copy(); //copy the frame to act as the previous
            }


The AbsDiff() is a simple calculation performed by calling the method from the newly acquired current frame and passing in the previous one from the if section execution. Once calculated thresholding is applied and the image is displayed using a thread safe call to the picturebox. The previous frame is updated with the current although code could easily be added to update this every 3 or so frames to show more movement. To draw the movement on the acquired frame contour detection is used. The code is taken from the Shape Detection example provided with EMGU. A simple bounding rectangle is drawn around the blob detected within the image.

            else
            {
                //acquire the frame
                Frame = _capture.RetrieveBgrFrame(); //aquire a frame

                Difference = Previous_Frame.AbsDiff(Frame); //find the absolute difference 
                /*Play with the value 60 to set a threshold for movement*/
                Difference = Difference.ThresholdBinary(new Bgr(Threshold, Threshold, Threshold), new Bgr(255,255,255)); //if value > 60 set to 255, 0 otherwise 
                DisplayImage(Difference.ToBitmap(), resultbox); //display the absolute difference 

                Previous_Frame = Frame.Copy(); //copy the frame to act as the previous frame

                #region Draw the contours of difference
                //this is tasken from the ShapeDetection Example
                using (MemStorage storage = new MemStorage()) //allocate storage for contour approximation
                //detect the contours and loop through each of them
                    for (Contour<Point> contours = Difference.Convert<Gray, Byte>().FindContours(
                          Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE,
                          Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_LIST,
                          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
                        {
                            Frame.Draw(currentContour.BoundingRectangle, new Bgr(Color.Red), 2);
                        }
                    }
                #endregion

                DisplayImage(Frame.ToBitmap(), CurrentFrame); //display the image using thread safe call
                DisplayImage(Previous_Frame.ToBitmap(), PreviousFrame); //display the previous image using thread safe call


                
            }


The DisplayImage() method is a thread safe method to update the contents of a picturebox from the camera acquisition thread. The image is passed as a Bitmap and a PictureBox control is passed in which to draw the image.The Threshold_Value_Scroll and Contour_Value_Scroll methods simply update the associated label and global variable used in the processing of the frame. The OnClosing method ensures that the camera _capture variable is disposed of correctly.


Methods Available

Used

  • Image()
  • ThresholdBinary()
  • ToBitmap()
  • AbsDiff()
  • Draw()


See the Online Documentation for all methods availabl


Bugs

  1. Sometimes the images will not display correctly when the form is maximised this is down to the load on the system in painting the images to 3 picture boxes.