Use image subtraction to compare images in C#

[image subtraction]

The following examples shows two approaches for seeing how much two images differ.

The first example only works well with drawn images, not photographs, because it marks pixels that differ by even the smallest amount. The second example uses a cutoff value so it only shows pixels where the two images differ by some minimum value. That’s better, but it doesn’t give you any indication of the amount by which two pixels differ.

This example compares two images by using image subtraction, a process where you subtract the color values of corresponding pixels in two images to see by how much they differ. (You take the absolute value of the difference so you don’t end up with color values less than 0.)

If the two images are mostly the same, then the result is mostly black with dark grays where two pixels differ. To make it easier to see differences, you can scale the results by multiplying them by 255 and dividing them by the largest difference. For example, if the largest difference is 10, then you multiply each value by 255 / 10.

You can also make the image easier to understand by inverting the colors by subtracting each value from 255. Then instead of a picture that’s mostly dark gray, you get a result that’s mostly light gray. The darker a pixel is in the result, the greater the difference is between the two images.

The following code shows how the example finds the difference image.

private void btnGo_Click(object sender, EventArgs e)
{
    this.Cursor = Cursors.WaitCursor;
    Application.DoEvents();

    // Load the images.
    Bitmap bm1 = (Bitmap)picImage1.Image;
    Bitmap bm2 = (Bitmap)picImage2.Image;

    // Make a difference image.
    int wid = Math.Min(bm1.Width, bm2.Width);
    int hgt = Math.Min(bm1.Height, bm2.Height);

    // Get the differences.
    int[,] diffs = new int[wid, hgt];
    int max_diff = 0;
    for (int x = 0; x < wid; x++)
    {
        for (int y = 0; y < hgt; y++)
        {
            // Calculate the pixels' difference.
            Color color1 = bm1.GetPixel(x, y);
            Color color2 = bm2.GetPixel(x, y);
            diffs[x, y] = (int)(
                Math.Abs(color1.R - color2.R) +
                Math.Abs(color1.G - color2.G) +
                Math.Abs(color1.B - color2.B));
            if (diffs[x, y] > max_diff)
                max_diff = diffs[x, y];
        }
    }
    //max_diff = 255;

    // Create the difference image.
    Bitmap bm3 = new Bitmap(wid, hgt);
    for (int x = 0; x < wid; x++)
    {
        for (int y = 0; y < hgt; y++)
        {
            int clr = 255 - (int)(255.0 / max_diff * diffs[x, y]);
            bm3.SetPixel(x, y, Color.FromArgb(clr, clr, clr));
        }
    }

    // Display the result.
    picResult.Image = bm3;

    this.Cursor = Cursors.Default;
}

The code starts by looping through the images’ pixels and calculating the sums of the differences between the pixels’ color components. As it does that, it keeps track of the largest difference in the variable max_diff.

Next the code makes a Bitmap of the correct size and loops through its pixels. For each pixel, it scales the difference by 255 / max_diff. That maps large differences to values near 255 and small differences to values near 0. That stretches the values so they span more of the range 0 to 255. (To see what happens if you don’t do this, uncomment the code that sets max_diff to 255. Then the values aren’t scaled and the result is much lighter.) The code subtracts each pixel’s result from 255 to invert the color and then sets the difference pixel’s value.

The code finishes by displaying the resulting image.

This technique lets you see all of the pixels that are different in the two input images, and shading lets you know which pixels differ the most.

If you look very closely at the picture at the top of this post, you’ll see that many of the result pixels are very light gray, indicating that the corresponding pixels in the input images are very similar, but few of the pixels are white. That means the two input images differ slightly in most of their pixels.


Download Example   Follow me on Twitter   RSS feed   Donate




About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.
This entry was posted in graphics, image processing and tagged , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *