What Is the Fastest Way I Can Compare Two Equal-Size Bitmaps to Determine Whether They Are Identical

What is the fastest way I can compare two equal-size bitmaps to determine whether they are identical?

Edit 8-31-12: per Joey's comment below, be mindful of the format of the bitmaps you compare. They may contain padding on the strides that render the bitmaps unequal, despite being equivalent pixel-wise. See this question for more details.


Reading this answer to a question regarding comparing byte arrays has yielded a MUCH FASTER method: using P/Invoke and the memcmp API call in msvcrt. Here's the code:

[DllImport("msvcrt.dll")]
private static extern int memcmp(IntPtr b1, IntPtr b2, long count);

public static bool CompareMemCmp(Bitmap b1, Bitmap b2)
{
if ((b1 == null) != (b2 == null)) return false;
if (b1.Size != b2.Size) return false;

var bd1 = b1.LockBits(new Rectangle(new Point(0, 0), b1.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
var bd2 = b2.LockBits(new Rectangle(new Point(0, 0), b2.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

try
{
IntPtr bd1scan0 = bd1.Scan0;
IntPtr bd2scan0 = bd2.Scan0;

int stride = bd1.Stride;
int len = stride * b1.Height;

return memcmp(bd1scan0, bd2scan0, len) == 0;
}
finally
{
b1.UnlockBits(bd1);
b2.UnlockBits(bd2);
}
}

Quickly determining of two bitmaps are the same?

you can check the dimensions first - and abort the comparison if they differ.

For the comparison itself you can use a variaty of ways:

  • CRC32

    very fast but possibly wrong... can be used as a first check, if it differs they are dfferent... otherwise further checking needed
  • MD5 / SHA1 / SHA512

    not so fast but rather precise
  • XOR

    XOR the image content... abort when the first difference comes up...

What is the fastest way to check if two Tbitmaps are the same?

You can save both Bitmaps to TMemoryStream and compare using CompareMem:

function IsSameBitmap(Bitmap1, Bitmap2: TBitmap): Boolean;
var
Stream1, Stream2: TMemoryStream;
begin
Assert((Bitmap1 <> nil) and (Bitmap2 <> nil), 'Params can''t be nil');
Result:= False;
if (Bitmap1.Height <> Bitmap2.Height) or (Bitmap1.Width <> Bitmap2.Width) then
Exit;
Stream1:= TMemoryStream.Create;
try
Bitmap1.SaveToStream(Stream1);
Stream2:= TMemoryStream.Create;
try
Bitmap2.SaveToStream(Stream2);
if Stream1.Size = Stream2.Size Then
Result:= CompareMem(Stream1.Memory, Stream2.Memory, Stream1.Size);
finally
Stream2.Free;
end;
finally
Stream1.Free;
end;
end;

begin
if IsSameBitmap(MyImage1.Picture.Bitmap, MyImage2.Picture.Bitmap) then
begin
// your code for same bitmap
end;
end;

I did not benchmark this code X scanline, if you do, please let us know which one is the fastest.

Why does a bitmap compare not equal to itself?

Take a look at this, which pictorially illustrates a LockBits buffer - it shows the Rows of Strides and where Padding can appear at the end of the Stride (if it's needed).

  • https://web.archive.org/web/20141229164101/http://bobpowell.net/lockingbits.aspx

  • http://supercomputingblog.com/graphics/using-lockbits-in-gdi/

A stride is probably aligned to the 32bit (i.e. word) boundary (for efficiency purposes)...and the extra unused space at the end of the stride is to make the next Stride be aligned.

So that's what's giving you the random behaviour during the comparison...spurious data in the Padding region.

When you are using Format32bppRgb and Format32bppArgb that's naturally word aligned, so I guess you don't have any extra unused bits on the end, which is why it works.

Quickest way to compare two BitmapImages to check if they are different in WPF

You could compare the bytes of the BitmapImage to check if they are equal

Something like:

public static class BitmapImageExtensions
{
public static bool IsEqual(this BitmapImage image1, BitmapImage image2)
{
if (image1 == null || image2 == null)
{
return false;
}
return image1.ToBytes().SequenceEqual(image2.ToBytes());
}

public static byte[] ToBytes(this BitmapImage image)
{
byte[] data = new byte[] { };
if (image != null)
{
try
{
var encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(image));
using (MemoryStream ms = new MemoryStream())
{
encoder.Save(ms);
data = ms.ToArray();
}
return data;
}
catch (Exception ex)
{
}
}
return data;
}
}

Usage:

BitmapImage image1 = ..............
BitmapImage image2 = ................

if (image1.IsEqual(image2))
{
// same image
}

Quickly determining of two bitmaps are the same?

you can check the dimensions first - and abort the comparison if they differ.

For the comparison itself you can use a variaty of ways:

  • CRC32

    very fast but possibly wrong... can be used as a first check, if it differs they are dfferent... otherwise further checking needed
  • MD5 / SHA1 / SHA512

    not so fast but rather precise
  • XOR

    XOR the image content... abort when the first difference comes up...

Fast way of calculating differences between two bitmaps

This method uses unsafe code, assuming bitmaps are the same size and are 4 bytes per pixel.

Rectangle bounds = new Rectangle(0,0,bitmapA.Width,bitmapA.Height);
var bmpDataA = bitmapA.LockBits(bounds, ImageLockMode.ReadWrite, bitmapA.PixelFormat);
var bmpDataB = bitmapB.LockBits(bounds, ImageLockMode.ReadWrite, bitmapB.PixelFormat);

const int height = 720;
int npixels = height * bmpDataA.Stride/4;
unsafe {
int * pPixelsA = (int*)bmpDataA.Scan0.ToPointer();
int * pPixelsB = (int*)bmpDataB.Scan0.ToPointer();

for ( int i = 0; i < npixels; ++i ) {
if (pPixelsA[i] != pPixelsB[i]) {
pPixelsB[i] = Color.Black.ToArgb();
}
}
}
bitmapA.UnlockBits(bmpDataA);
bitmapB.UnlockBits(bmpDataB);

For a safe method, copy the pixel data to an array buffer for processing using the InteropServices.Marshal.Copy methods.

c# memcmp image compare error

The correct signature is:

[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
static extern int memcmp(IntPtr b1, IntPtr b2, IntPtr count);

because in C, count is size_t, so it can be 32 or 64 bits depending if the program is running at 32 or 64 bits.

Then to use it:

return memcmp(bd1scan0, bd2scan0, (IntPtr)len) == 0;


Related Topics



Leave a reply



Submit