21 Jun

C# Fast Bitmap Compare

This example controls that two bitmap object are same or not. In first method, we use the GetPixel method in Bitmap class. In second example, we use the memory comparison using BitmapData class. “Frog 1” and “Frog 2” files has 1024×768 pixel size. Their thumbnails are shown below. As result:

Total time in first example(Lazy Comparison): ~1644 ms
Total time in second example(Fast Comprasion): ~10 ms

Usage:

            Bitmap bmp1 = (Bitmap)Bitmap.FromFile(@"C:\test\Frog 1.bmp");
            Bitmap bmp2 = (Bitmap)Bitmap.FromFile(@"C:\test\Frog 2.bmp");

            Stopwatch sw = new Stopwatch();
            
            sw.Start();
            bool res1 = BitmapComprasion.CompareBitmapsLazy(bmp1, bmp2);
            sw.Stop();
            Console.WriteLine(string.Format("CompareBitmapsLazy Time: {0} ms", sw.ElapsedMilliseconds));

            sw.Restart();
            bool res2 = BitmapComprasion.CompareBitmapsFast(bmp1, bmp2);
            sw.Stop();
            Console.WriteLine(string.Format("CompareBitmapsFast Time: {0} ms", sw.ElapsedMilliseconds));

            //Output:
            //CompareBitmapsLazy Time: 1644 ms
            //CompareBitmapsFast Time: 10 ms
Frog 1 Thumbnail Frog 2 Thumbnail
Frog 1 Frog 2

Fast Bitmap Comparison Example:

        public static bool CompareBitmapsFast(Bitmap bmp1, Bitmap bmp2)
        {
            if (bmp1 == null || bmp2 == null)
                return false;
            if (object.Equals(bmp1, bmp2))
                return true;
            if (!bmp1.Size.Equals(bmp2.Size) || !bmp1.PixelFormat.Equals(bmp2.PixelFormat))
                return false;

            int bytes = bmp1.Width * bmp1.Height * (Image.GetPixelFormatSize(bmp1.PixelFormat) / 8);

            bool result = true;
            byte[] b1bytes = new byte[bytes];
            byte[] b2bytes = new byte[bytes];

            BitmapData bitmapData1 = bmp1.LockBits(new Rectangle(0, 0, bmp1.Width, bmp1.Height), ImageLockMode.ReadOnly, bmp1.PixelFormat);
            BitmapData bitmapData2 = bmp2.LockBits(new Rectangle(0, 0, bmp2.Width, bmp2.Height), ImageLockMode.ReadOnly, bmp2.PixelFormat);

            Marshal.Copy(bitmapData1.Scan0, b1bytes, 0, bytes);
            Marshal.Copy(bitmapData2.Scan0, b2bytes, 0, bytes);

            for (int n = 0; n <= bytes - 1; n++)
            {
                if (b1bytes[n] != b2bytes[n])
                {
                    result = false;
                    break;
                }
            }

            bmp1.UnlockBits(bitmapData1);
            bmp2.UnlockBits(bitmapData2);

            return result;
        }

Classic Bitmap Comparison Example:

        public static bool CompareBitmapsLazy(Bitmap bmp1, Bitmap bmp2)
        {
            if (bmp1 == null || bmp2 == null)
                return false;
            if (object.Equals(bmp1, bmp2))
                return true;
            if (!bmp1.Size.Equals(bmp2.Size) || !bmp1.PixelFormat.Equals(bmp2.PixelFormat))
                return false;

            //Compare bitmaps using GetPixel method
            for (int column = 0; column < bmp1.Width; column++)
            {
                for (int row = 0; row < bmp1.Height; row++)
                {
                    if (!bmp1.GetPixel(column, row).Equals(bmp2.GetPixel(column, row)))
                        return false;
                }
            }

            return true;
        }

14 thoughts on “C# Fast Bitmap Compare

  1. On the two LockBits lines, any reason why you’re subtracting 1 from width and height? If you try to compare bitmaps of 1 width or height, you’ll get a Parameter Not Valid exception. Also, it seems likely that bitmaps that differ only in the rightmost column or bottom row would erroneously pass.

  2. Does the algorithm take into account the rotation of the bitmap?
    Suppose we have two identical shapes but one rotated 45 ° with respect to the other, what will the result be?
    Thanks a lot!

    • You should create BitmapComparison class and copy/paste methods(CompareBitmapsFast and CompareBitmapsLazy) into the class.

  3. How to get output image when compare two images.If images are same will get output same image else get difference of those images in picturebox.

  4. Hi Turgay, thank you, helped me !
    You can speed up further by replacing the slow “for” loop by

    var a = (ReadOnlySpan<byte>)b1bytes;
    var b = (ReadOnlySpan<byte>)b2bytes;
    var result = a.SequenceEqual(b);
    

    Tested with .Net5.

Leave a Reply to Abdul Noman Cancel reply

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