Image Differencing
<< Back to the EasyImage Toolkit page
Tutorial - Image Differencing

What you will learn
This tutorial shows:
- how you can use the ImageGenerator.Operation method to visually subtract two images and generate a new one that shows the differences between them (as in the image above),
- two ImageAnalyzer methods for calculating a numeric value that represencts how different these images are.
- PercentDifferentDegree averages as a fraction how pixels in corresponding images differ in RGB values
- PercentDifferentPixels averages the fraction of pixels in corresponding images that differ by a threshold. Note: Since each RGB value ranges from 0 - 255, the maximum two pixels can differ is (3*255) = 765. Thus your threshold range is 0 - 765. A threshold of around 100 - 300 is reasonable for filtering out color changes due to video camera noise and / or light changes between successive frames from cameras that automatically adjust the light levels.
In the above picture,
- the Original image is what the camera is capturing
- the Snapshot image is a frame that is grabbed whenever you select the from Snapshot radio button
- the Subtracted image is a frame that represents the visual difference between two successive video frames (if the from Video radio button is selected) or the current video frame and the snapshot (if the from Snapshot radio button is selected)
- The numbers below are from different methods of analyzing the differences in the image. The Pixels method uses a threshold to calculate this difference, which you can set with the trackbar.
Download
While we recommend you create this program from scratch, you can also download the source and executables.
Source and Executables of this and other examples: EasyImagesExamples.zip
|
Step 1. Preconditions
Including EasyImages in your new Visual Studio 2005 C# project. This was described in Minimal Camera Example. Make sure to include the using EasyImages; line in your project.
Step 2. Creating GUI controls
Add the following GUI controls to your form window. Thei locations and purpose should be obvious if you check the image at the top of this page.
- 3 PictureBoxes will display your camera's frames
- Name = pbOriginal, pbSnapshot and pbSubtracted
- Size = 640,480 (the Width and Height of the frame we will put in it)
- BorderStyle = FixedSingle (for pbSnapshot)
- 3 Labels
- Text = Original image, Snapshot, and Subtracted Image as seen in the image above
- 2 RadioButtons
- Name = rbOriginal, rbSnapShot
- Text = fromVideo, from Snapshot
- GroupBox
- Text = Differences between images, as seen in the image above
- 3 More Labels
- Name = lblDiffDegree, lblDiffPixels, lblThreshold
- Text = Degree:, Pixels:, Threshold: 1
- TrackBar interactively change the threshold
- Name = tbThreshold
- Minimum = 0
- Maximum = 765
Step 3. Writing the program
The complete program is listed below.
using System.Drawing;
using System.Windows.Forms;
using EasyImages;
namespace ImageDifferencing
{
public partial class Form1 : Form
{
EasyImages.CameraClient camera;
Bitmap lastFrame;
private delegate void SetPictureBoxImage(PictureBox pbox, Bitmap image);
public Form1()
{
InitializeComponent();
}
//As the GUI is loaded, create a new camera object and set its initial properties
private void Form1_Load(object sender, EventArgs e)
{
lblThreshold.Text = "Threshold: " + tbThreshold.Value.ToString();
//Create a new camera object and set its initial properties
camera = new EasyImages.CameraClient ("DefaultCamera");
camera.FramesPerSecond = 10;
camera.ReceivedFrame += new EasyImages.CameraClient.ReceivedFrameEventHandler (camera_ReceivedFrame);
camera.Start();
}
//We just received a frame...
void camera_ReceivedFrame(object sender, EasyImages.CameraEventArgs e)
{
// Display the original frame
this.DisplayImageInPictureBox(pbOriginal, e.Bitmap);
// Generate a frame that visually shows the one image subtracted from the other
// We first decide (by the state of the radio buttons) if we are going to subtract
// the current frame from the last frame seen, or from a static snapshot
Bitmap tempBitmap;
if (rbSnapshot.Checked) tempBitmap = (Bitmap) pbSnapshot.Image;
else tempBitmap = lastFrame;
if (tempBitmap != null)
{
// Now we subtract the image
this.DisplayImageInPictureBox(pbSubtracted, EasyImages.ImageGenerator.Operation(EasyImages.OperationType.Subtract, e.Bitmap, tempBitmap));
//Calculate and show the degree differences between images
lblDiffDegree.Text = "Degree: " + EasyImages.ImageAnalyzer.PercentDifferentDegree(e.Bitmap, tempBitmap).ToString();
//Calculate and show the number of pixels that differ by at least the threshold amount set in the trackbarr
lblDiffPixels.Text = "Pixels: " + EasyImages.ImageAnalyzer.PercentDifferentPixels(tbThreshold.Value, e.Bitmap, tempBitmap).ToString();
}
//Save this frame, so we can use it on the next go round.
lastFrame = e.Bitmap;
}
// Interactively set the threshold for calculating the PercentDifferencePixels
private void tbThreshold_Scroll(object sender, EventArgs e)
{
lblThreshold.Text = "Threshold: " + tbThreshold.Value.ToString();
}
// When we click the snapshot radio button, take a snapshot.
private void rbSnapshot_CheckedChanged (object sender, EventArgs e)
{
if (rbSnapshot.Checked)
{
this.DisplayImageInPictureBox(pbSnapshot, camera.GetFrame ());
}
}
// Display an image in a picture box, making sure we are in the correcct thread.
private void DisplayImageInPictureBox(PictureBox pbox, Image image)
{
if (pbox.InvokeRequired) // We are in the wrong thread. Call ourselves in the correct thread
{
SetPictureBoxImage theDelegate = new SetPictureBoxImage(DisplayImageInPictureBox);
BeginInvoke(theDelegate, new object[] { pbox, image });
}
else // we are in the correct thread, so assign the image
{
pbox.Image = image;
}
}
}
}
Explanation
Much of this program is similar to what was seen in the Minimal Camera, so we only describe what is different. The new parts illustrate how to display an image that is the result of subtracting two images, and how to analyze its difference (returned as a fraction).
- Form1_Load is the load even handler for the form; it creates a new camera client object, sets its initial properties, and creates the camera client event handler to process generated frames as bitmaps
- camera_ReceivedFrame is the event handler for the camera.
- It displays the current frame in the Original PictureBox
- It subtracts the current frame from either the previous frame or the static snapshot (depending on the radio button state) and displays it in the Subtract PictureBox
- It calculates the differences between the images, using two different methods
- tbThreshold_Scroll is the event handler for the tbThreshold trackbar; it just sets the threshold value used by one of the difference analyzers
- rbSnapshot_CheckedChanged is the event handler for the rbSnapshot radio button; it gets the current video frame and puts it into the Snapshot PictureBox