heartofrevel
heartofrevel

Reputation: 181

How to compare two images?

public void winCheck()
{
    if (button1.Image == img1)
    {
        w1 = "P2";
        button1.Image = new Bitmap(@"win_cross.png");
        button2.Image = new Bitmap(@"win_cross.png");
        button3.Image = new Bitmap(@"win_cross.png");
    }
}

Here both button1.Image and img1 have same image but still, the control doesn't go into the if block. Is their any property of both such that value of both will be same.

Upvotes: 4

Views: 16604

Answers (3)

user3285954
user3285954

Reputation: 4729

Your code doesn't work because you are comparing the variables pointing to the images (i.e. in memory address) not the image data (pixels).

See ImageComparer.Compare method. Has overloads to specify tolerance. It is available since VS2012.

https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.uitesting.imagecomparer.compare.aspx

Upvotes: 0

BartoszKP
BartoszKP

Reputation: 35891

Here is one possibility to do it, if you can have unsafe code and if you want images to be exactly the same on byte level:

public unsafe static bool AreEqual(Bitmap b1, Bitmap b2)
{
    if (b1.Size != b2.Size)
    {
        return false;
    }

    if (b1.PixelFormat != b2.PixelFormat)
    {
        return false;
    }

    if (b1.PixelFormat != PixelFormat.Format32bppArgb)
    {
        return false;
    }

    Rectangle rect = new Rectangle(0, 0, b1.Width, b1.Height);
    BitmapData data1
        = b1.LockBits(rect, ImageLockMode.ReadOnly, b1.PixelFormat);
    BitmapData data2
        = b2.LockBits(rect, ImageLockMode.ReadOnly, b1.PixelFormat);

    int* p1 = (int*)data1.Scan0;
    int* p2 = (int*)data2.Scan0;
    int byteCount = b1.Height * data1.Stride / 4; //only Format32bppArgb 

    bool result = true;
    for (int i = 0; i < byteCount; ++i)
    {
        if (*p1++ != *p2++)
        {
            result = false;
            break;
        }
    }

    b1.UnlockBits(data1);
    b2.UnlockBits(data2);

    return result;
}

This compares images "literally" - all bytes need to be exactly the same. Other possibility would be to compare colours of pixels - then PixelFormats wouldn't have to be the same (taken from here):

public static CompareResult Compare(Bitmap bmp1, Bitmap bmp2)
{
    CompareResult cr = CompareResult.ciCompareOk;

    //Test to see if we have the same size of image
    if (bmp1.Size != bmp2.Size)
    {
        cr = CompareResult.ciSizeMismatch;
    }
    else
    {
        //Sizes are the same so start comparing pixels
        for (int x = 0; x < bmp1.Width 
             && cr == CompareResult.ciCompareOk; x++)
        {
            for (int y = 0; y < bmp1.Height 
                         && cr == CompareResult.ciCompareOk; y++)
            {
                if (bmp1.GetPixel(x, y) != bmp2.GetPixel(x, y))
                    cr = CompareResult.ciPixelMismatch;
            }
        }
    }
    return cr;
}

This can be however very slow. The same link contains an interesting idea of comparing hash values:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Security.Cryptography;

namespace Imagio
{
    public class ComparingImages
    {
        public enum CompareResult
        {
            ciCompareOk,
            ciPixelMismatch,
            ciSizeMismatch
        };

        public static CompareResult Compare(Bitmap bmp1, Bitmap bmp2)
        {
            CompareResult cr = CompareResult.ciCompareOk;

            //Test to see if we have the same size of image
            if (bmp1.Size != bmp2.Size)
            {
                cr = CompareResult.ciSizeMismatch;
            }
            else
            {
                //Convert each image to a byte array
                System.Drawing.ImageConverter ic = 
                       new System.Drawing.ImageConverter();
                byte[] btImage1 = new byte[1];
                btImage1 = (byte[])ic.ConvertTo(bmp1, btImage1.GetType());
                byte[] btImage2 = new byte[1];
                btImage2 = (byte[])ic.ConvertTo(bmp2, btImage2.GetType());

                //Compute a hash for each image
                SHA256Managed shaM = new SHA256Managed();
                byte[] hash1 = shaM.ComputeHash(btImage1);
                byte[] hash2 = shaM.ComputeHash(btImage2);

                //Compare the hash values
                for (int i = 0; i < hash1.Length && i < hash2.Length 
                                  && cr == CompareResult.ciCompareOk; i++)
                {
                    if (hash1[i] != hash2[i])
                        cr = CompareResult.ciPixelMismatch;
                }
            }
            return cr;
        }
    }
}

Upvotes: 9

Asad Ali
Asad Ali

Reputation: 31

dont use double equal (==). use equals method. (if button1.Image.equals(img1)) // you code

Upvotes: -7

Related Questions