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
Passing Data to Master Page in ASP.NET MVC
How to Save Console.Writeline Output to Text File
How to Use the C#6 "Using Static" Feature
How to Convert Ienumerable to Observablecollection
How to Detect When a Windows Form Is Being Minimized
How to Throttle Event Stream Using Rx
Can a C# Lambda Expression Have More Than One Statement
How to Clear the Text of All Textboxes in the Form
Streamwriter and Utf-8 Byte Order Marks
Regex That Accepts Only Numbers (0-9) and No Characters
What's Better: Dataset or Datareader
Mapping Composite Keys Using Ef Code First
Creating a Temporary Directory in Windows