images and equality

  • Thread starter Thread starter Eric Eggermann
  • Start date Start date
E

Eric Eggermann

Hello all,
I'm looking for a way to tell whether two image objects which do not
have object equality are the same image or not, and I mean identical, say
originally loaded from the same file. Any ideas on how to approach this?

TIA,
Eric
 
Eric,

I don't think that there is an easy way to do this. If you can get a
byte array with the contents, then you can cycle through the bytes and then
do a comparison.

Or, you could even attach the byte arrays to a MemoryStream, then feed
that stream through a hash algorithm in the System.Security.Cryptography
namespace and then compare the results.

Hope this helps.
 
Nicholas Paldino said:
Eric,

I don't think that there is an easy way to do this. If you can get a
byte array with the contents, then you can cycle through the bytes and then
do a comparison.

Or, you could even attach the byte arrays to a MemoryStream, then feed
that stream through a hash algorithm in the System.Security.Cryptography
namespace and then compare the results.

Hope this helps.

Thanks, I'll have a whack at those.

Eric
 
This is a great spot to showcase the power of the .NET Framework, this
fairly complex task can be done in less than ten lines of code:

public bool CompareImages(Image first, Image second)
{
System.IO.MemoryStream ms1 = new System.IO.MemoryStream();
System.IO.MemoryStream ms2 = new System.IO.MemoryStream();

first.Save( ms1, System.Drawing.Imaging.ImageFormat.Bmp);
byte[] First = ms1.ToArray();

second.Save( ms2, System.Drawing.Imaging.ImageFormat.Bmp );
byte[] Second = ms2.ToArray();

return System.Text.Encoding.ASCII.GetString(First) ==
System.Text.Encoding.ASCII.GetString(Second);

}
 
JDeats said:
This is a great spot to showcase the power of the .NET Framework, this
fairly complex task can be done in less than ten lines of code:

snip

Thanks a million Jeremy. I hadn't gotten around to trying the suggestions in
the first reply I got, but anyway, I'd have never thought to compare the
bytes as strings. Is this to avoid a reference equality result?

Eric
 
JDeats said:
This is a great spot to showcase the power of the .NET Framework, this
fairly complex task can be done in less than ten lines of code:

public bool CompareImages(Image first, Image second)
{
System.IO.MemoryStream ms1 = new System.IO.MemoryStream();
System.IO.MemoryStream ms2 = new System.IO.MemoryStream();

first.Save( ms1, System.Drawing.Imaging.ImageFormat.Bmp);
byte[] First = ms1.ToArray();

second.Save( ms2, System.Drawing.Imaging.ImageFormat.Bmp );
byte[] Second = ms2.ToArray();

return System.Text.Encoding.ASCII.GetString(First) ==
System.Text.Encoding.ASCII.GetString(Second);

}

However, that isn't accurate, because for some reason you're converting
the two byte arrays into text using ASCII, which only has 128 values.
Forget Encoding.ASCII - just use:

if (First.Length != Second.Length)
return false;

for (int i=0; i < First.Length; i++)
{
if (First != Second)
return false;
}

return true;

Slightly longer, but more reliable and also more efficient (it doesn't
leave two potentially long strings on the heap for no reason).
 
Thanks a million Jeremy. I hadn't gotten around to trying the suggestions in
the first reply I got, but anyway, I'd have never thought to compare the
bytes as strings. Is this to avoid a reference equality result?

Yes, but it's flawed - see my response to Jeremy's post.

If you're commonly comparing byte arrays for equality, you might want
to put the code for it in a utility method somewhere.
 
Jon Skeet said:
However, that isn't accurate, because for some reason you're converting
the two byte arrays into text using ASCII, which only has 128 values.
Forget Encoding.ASCII - just use:

if (First.Length != Second.Length)
return false;

for (int i=0; i < First.Length; i++)
{
if (First != Second)
return false;
}

return true;


I thought about this when I saw the reply, and I'm planning on doing tests
for efficiency. I'm not sure how the string compare is implemented, but
because of the way this section of the code will run, I'm more interested in
speed than memory use. It will run in bursts, so to speak, called many times
consecutively, but then not again for awhile.

Thanks for advice Jon, and I'll try things out both ways, and post back to
the group what I find.

Eric
 
<"Eric Eggermann" <<none>>> wrote:

I thought about this when I saw the reply, and I'm planning on doing tests
for efficiency. I'm not sure how the string compare is implemented, but
because of the way this section of the code will run, I'm more interested in
speed than memory use. It will run in bursts, so to speak, called many times
consecutively, but then not again for awhile.

Thanks for advice Jon, and I'll try things out both ways, and post back to
the group what I find.

The main concern should be *accuracy* though, and using a string
conversion is just not a good idea when it comes to comparing *binary*
data. I'd actually expect the "natural" version to be just as fast
anyway - you only need to go through the data once, as opposed to once
to convert and then once to compare. It also means that if the first
pixel is different, you don't need to go through the rest of the arrays
at all.
 
Really, well it may not be the most optimal approach, but I tested it
multiple times before posting and it seemed to do the trick, I
wouldn't have posted something that didn't work.

The two long strings will be picked up by the garbage collector, so it
should be do problem, but avoiding their creation would be more
efficient. I was just trying to demonstrate the simplest approach
possible, but it's worth the few extra lines of code to do it right.

Thanks,
Jeremy
 
JDeats said:
Really, well it may not be the most optimal approach, but I tested it
multiple times before posting and it seemed to do the trick, I
wouldn't have posted something that didn't work.

I'm afraid you did though. Try this:

using System;
using System.Text;

class Test
{
static void Main()
{
byte[] b1 = {0x20};
byte[] b2 = {0xa0};

String s1 = Encoding.ASCII.GetString (b1);
String s2 = Encoding.ASCII.GetString (b2);

Console.WriteLine (s1==s2);
}
}

It prints "True" because the ASCII encoding truncates the top bit of
each byte. I'm sure your version would always correctly pick up byte
arrays which are equal, but it wouldn't always correctly pick up byte
arrays which *aren't* equal.
The two long strings will be picked up by the garbage collector, so it
should be do problem, but avoiding their creation would be more
efficient.

They would be picked up by the garbage collector, yes, but if the
images are of significant size the strings will be quite large (double
the size of whatever size the byte array is)
I was just trying to demonstrate the simplest approach
possible, but it's worth the few extra lines of code to do it right.

Avoiding the extra memory isn't the main problem here - it's
correctness. The extra speed and memory efficiency of the "brute
force" solution I suggested (which I think is actually simpler too,
fundamentally - it doesn't involve the concepts of text conversion etc)
are just bonuses.
 
Back
Top