Determining if 2 images are the same
up vote
18
down vote
favorite
This is my program code for comparing if 2 images are the same. It basically uses the open dialog and opens 1 image at a time and puts it in 1 picture box.
I heard that GetPixel()
method may be slow. Is there a more efficient and faster way to compare 2 if 2 images are the same?
Bitmap image1 = null;
Bitmap image2 = null;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) //first image open
{
OpenFileDialog openDialog = new OpenFileDialog();
if (openDialog.ShowDialog() == DialogResult.OK)
{
image1 = new Bitmap(openDialog.FileName);
pictureBox1.Image = image1;
}
}
private void button2_Click(object sender, EventArgs e) //second image open
{
OpenFileDialog openDialog = new OpenFileDialog();
if (openDialog.ShowDialog() == DialogResult.OK)
{
image2 = new Bitmap(openDialog.FileName);
pictureBox2.Image = image2;
}
}
private void button3_Click(object sender, EventArgs e) //compare button
{
if (compare(image1, image2))
{
MessageBox.Show("Same Image.");
}
else
{
MessageBox.Show("Different Image.");
}
}
private bool compare(Bitmap bmp1, Bitmap bmp2)
{
bool equals = true;
bool flag = true; //Inner loop isn't broken
//Test to see if we have the same size of image
if (bmp1.Size == bmp2.Size)
{
for (int x = 0; x < bmp1.Width; ++x)
{
for (int y = 0; y < bmp1.Height; ++y)
{
if (bmp1.GetPixel(x, y) != bmp2.GetPixel(x, y))
{
equals = false;
flag = false;
break;
}
}
if (!flag)
{
break;
}
}
}
else
{
equals = false;
}
return equals;
}
c# image
add a comment |
up vote
18
down vote
favorite
This is my program code for comparing if 2 images are the same. It basically uses the open dialog and opens 1 image at a time and puts it in 1 picture box.
I heard that GetPixel()
method may be slow. Is there a more efficient and faster way to compare 2 if 2 images are the same?
Bitmap image1 = null;
Bitmap image2 = null;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) //first image open
{
OpenFileDialog openDialog = new OpenFileDialog();
if (openDialog.ShowDialog() == DialogResult.OK)
{
image1 = new Bitmap(openDialog.FileName);
pictureBox1.Image = image1;
}
}
private void button2_Click(object sender, EventArgs e) //second image open
{
OpenFileDialog openDialog = new OpenFileDialog();
if (openDialog.ShowDialog() == DialogResult.OK)
{
image2 = new Bitmap(openDialog.FileName);
pictureBox2.Image = image2;
}
}
private void button3_Click(object sender, EventArgs e) //compare button
{
if (compare(image1, image2))
{
MessageBox.Show("Same Image.");
}
else
{
MessageBox.Show("Different Image.");
}
}
private bool compare(Bitmap bmp1, Bitmap bmp2)
{
bool equals = true;
bool flag = true; //Inner loop isn't broken
//Test to see if we have the same size of image
if (bmp1.Size == bmp2.Size)
{
for (int x = 0; x < bmp1.Width; ++x)
{
for (int y = 0; y < bmp1.Height; ++y)
{
if (bmp1.GetPixel(x, y) != bmp2.GetPixel(x, y))
{
equals = false;
flag = false;
break;
}
}
if (!flag)
{
break;
}
}
}
else
{
equals = false;
}
return equals;
}
c# image
1
Note thatBitmap
inherits fromImage
, which implementsIDisposable
. This means you very much better callDispose()
on those objects are you are done with them (way many paths here with UI event handlers), or put them intousing
blocks.
– Jesse C. Slicer
Jan 24 '14 at 18:45
1
Oh, and same goes forOpenFileDialog
. I'll probably post an answer to show some of this.
– Jesse C. Slicer
Jan 24 '14 at 18:48
1
See ImageComparer.Compare method. Has overloads to specify tolerance. It is available since VS2102. msdn.microsoft.com/en-us/library/…
– user3285954
Jul 2 '15 at 20:06
add a comment |
up vote
18
down vote
favorite
up vote
18
down vote
favorite
This is my program code for comparing if 2 images are the same. It basically uses the open dialog and opens 1 image at a time and puts it in 1 picture box.
I heard that GetPixel()
method may be slow. Is there a more efficient and faster way to compare 2 if 2 images are the same?
Bitmap image1 = null;
Bitmap image2 = null;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) //first image open
{
OpenFileDialog openDialog = new OpenFileDialog();
if (openDialog.ShowDialog() == DialogResult.OK)
{
image1 = new Bitmap(openDialog.FileName);
pictureBox1.Image = image1;
}
}
private void button2_Click(object sender, EventArgs e) //second image open
{
OpenFileDialog openDialog = new OpenFileDialog();
if (openDialog.ShowDialog() == DialogResult.OK)
{
image2 = new Bitmap(openDialog.FileName);
pictureBox2.Image = image2;
}
}
private void button3_Click(object sender, EventArgs e) //compare button
{
if (compare(image1, image2))
{
MessageBox.Show("Same Image.");
}
else
{
MessageBox.Show("Different Image.");
}
}
private bool compare(Bitmap bmp1, Bitmap bmp2)
{
bool equals = true;
bool flag = true; //Inner loop isn't broken
//Test to see if we have the same size of image
if (bmp1.Size == bmp2.Size)
{
for (int x = 0; x < bmp1.Width; ++x)
{
for (int y = 0; y < bmp1.Height; ++y)
{
if (bmp1.GetPixel(x, y) != bmp2.GetPixel(x, y))
{
equals = false;
flag = false;
break;
}
}
if (!flag)
{
break;
}
}
}
else
{
equals = false;
}
return equals;
}
c# image
This is my program code for comparing if 2 images are the same. It basically uses the open dialog and opens 1 image at a time and puts it in 1 picture box.
I heard that GetPixel()
method may be slow. Is there a more efficient and faster way to compare 2 if 2 images are the same?
Bitmap image1 = null;
Bitmap image2 = null;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) //first image open
{
OpenFileDialog openDialog = new OpenFileDialog();
if (openDialog.ShowDialog() == DialogResult.OK)
{
image1 = new Bitmap(openDialog.FileName);
pictureBox1.Image = image1;
}
}
private void button2_Click(object sender, EventArgs e) //second image open
{
OpenFileDialog openDialog = new OpenFileDialog();
if (openDialog.ShowDialog() == DialogResult.OK)
{
image2 = new Bitmap(openDialog.FileName);
pictureBox2.Image = image2;
}
}
private void button3_Click(object sender, EventArgs e) //compare button
{
if (compare(image1, image2))
{
MessageBox.Show("Same Image.");
}
else
{
MessageBox.Show("Different Image.");
}
}
private bool compare(Bitmap bmp1, Bitmap bmp2)
{
bool equals = true;
bool flag = true; //Inner loop isn't broken
//Test to see if we have the same size of image
if (bmp1.Size == bmp2.Size)
{
for (int x = 0; x < bmp1.Width; ++x)
{
for (int y = 0; y < bmp1.Height; ++y)
{
if (bmp1.GetPixel(x, y) != bmp2.GetPixel(x, y))
{
equals = false;
flag = false;
break;
}
}
if (!flag)
{
break;
}
}
}
else
{
equals = false;
}
return equals;
}
c# image
c# image
edited Feb 22 '15 at 6:27
Jamal♦
30.2k11115226
30.2k11115226
asked Jan 24 '14 at 18:22
puretppc
2431212
2431212
1
Note thatBitmap
inherits fromImage
, which implementsIDisposable
. This means you very much better callDispose()
on those objects are you are done with them (way many paths here with UI event handlers), or put them intousing
blocks.
– Jesse C. Slicer
Jan 24 '14 at 18:45
1
Oh, and same goes forOpenFileDialog
. I'll probably post an answer to show some of this.
– Jesse C. Slicer
Jan 24 '14 at 18:48
1
See ImageComparer.Compare method. Has overloads to specify tolerance. It is available since VS2102. msdn.microsoft.com/en-us/library/…
– user3285954
Jul 2 '15 at 20:06
add a comment |
1
Note thatBitmap
inherits fromImage
, which implementsIDisposable
. This means you very much better callDispose()
on those objects are you are done with them (way many paths here with UI event handlers), or put them intousing
blocks.
– Jesse C. Slicer
Jan 24 '14 at 18:45
1
Oh, and same goes forOpenFileDialog
. I'll probably post an answer to show some of this.
– Jesse C. Slicer
Jan 24 '14 at 18:48
1
See ImageComparer.Compare method. Has overloads to specify tolerance. It is available since VS2102. msdn.microsoft.com/en-us/library/…
– user3285954
Jul 2 '15 at 20:06
1
1
Note that
Bitmap
inherits from Image
, which implements IDisposable
. This means you very much better call Dispose()
on those objects are you are done with them (way many paths here with UI event handlers), or put them into using
blocks.– Jesse C. Slicer
Jan 24 '14 at 18:45
Note that
Bitmap
inherits from Image
, which implements IDisposable
. This means you very much better call Dispose()
on those objects are you are done with them (way many paths here with UI event handlers), or put them into using
blocks.– Jesse C. Slicer
Jan 24 '14 at 18:45
1
1
Oh, and same goes for
OpenFileDialog
. I'll probably post an answer to show some of this.– Jesse C. Slicer
Jan 24 '14 at 18:48
Oh, and same goes for
OpenFileDialog
. I'll probably post an answer to show some of this.– Jesse C. Slicer
Jan 24 '14 at 18:48
1
1
See ImageComparer.Compare method. Has overloads to specify tolerance. It is available since VS2102. msdn.microsoft.com/en-us/library/…
– user3285954
Jul 2 '15 at 20:06
See ImageComparer.Compare method. Has overloads to specify tolerance. It is available since VS2102. msdn.microsoft.com/en-us/library/…
– user3285954
Jul 2 '15 at 20:06
add a comment |
6 Answers
6
active
oldest
votes
up vote
13
down vote
accepted
You can use the LockBits
method and pointers to access the image data directly.
Example for 24 bpp images:
bool equals = true;
Rectangle rect = new Rectangle(0, 0, bmp1.Width, bmp1.Height);
BitmapData bmpData1 = bmp1.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat);
BitmapData bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp2.PixelFormat);
unsafe {
byte* ptr1 = (byte*)bmpData1.Scan0.ToPointer();
byte* ptr2 = (byte*)bmpData2.Scan0.ToPointer();
int width = rect.Width * 3; // for 24bpp pixel data
for (int y = 0; equals && y < rect.Height; y++) {
for (int x = 0; x < width; x++) {
if (*ptr1 != *ptr2) {
equals = false;
break;
}
ptr1++;
ptr2++;
}
ptr1 += bmpData1.Stride - width;
ptr2 += bmpData2.Stride - width;
}
}
bmp1.UnlockBits(bmpData1);
bmp2.UnlockBits(bmpData2);
I assume I drag this in mycompare()
method?
– puretppc
Jan 24 '14 at 18:57
@puretppc: Yes, that is correct. After checking that the images have the same size and the correct pixel format.
– Guffa
Jan 24 '14 at 19:13
BitmapData
doesn't exist for me. AlsoUnsafe code may only appear if compiling with /unsafe
.
– puretppc
Jan 24 '14 at 19:16
@puretppc: Addusing System.Drawing.Imaging;
at the top, or useSystem.Drawing.Imaging.BitmapData
. (If you right click onBitmapData
both options can be done automatically underResolve
.) To use unsafe code you need to enable it in the project properties.
– Guffa
Jan 24 '14 at 19:24
Oh ok. But now I'm getting an error saying'System.Drawing.Imaging.ImageLockMode' does not contain a definition for 'Read'
At the very top of the program I putusing System.Drawing.Imaging;
– puretppc
Jan 24 '14 at 19:31
|
show 9 more comments
up vote
10
down vote
One thing I have done in the past is to convert the images to 64-bit encoded strings and just string compare. It won't be as fast as using pointers, naturally. However, it can be done entirely in managed code, it doesn't require you to know bits per pixel, and it works for the Image base class.
byte image1Bytes;
byte image2Bytes;
using(var mstream = new MemoryStream())
{
image1.Save(mstream, image1.RawFormat);
image1Bytes = mstream.ToArray();
}
using(var mstream = new MemoryStream())
{
image2.Save(mstream, image2.RawFormat);
image2Bytes = mstream.ToArray();
}
var image164 = Convert.ToBase64String(image1Bytes);
var image264 = Convert.ToBase64String(image2Bytes);
return string.Equals(image164, image264);
Thanks this worked :) So my old code was about comparing BPP (bits per pixel)? I don't really know this since I got this off the another site
– puretppc
Jan 24 '14 at 18:58
3
Note that this will also compare any meta data in the images. If they for example are identical but with different resolution settings, this will return false.
– Guffa
Jan 24 '14 at 19:14
4
What is the purpose of converting to a base64 string? Why not simple compare the elements of both arrays (or streams)?
– NPSF3000
May 5 '14 at 8:30
add a comment |
up vote
9
down vote
I'll focus on problems in compare()
.
You're using the wrong equality comparison for the bitmap size. You need to compare the contents of the Size
objects, not whether they are the same reference.
A variable named flag
should be a… red flag! Not only is it vaguely named, its presence suggests that your code is ineffective. Avoid using variables for flow control; find more active ways to get to where you need to go.
In this case, the solution is an early return
. As soon as you find a single difference between the two images, you're done! You don't even need the equals
variable.
I would also rename compare()
for clarity, and make it static
because it is a pure function of its two parameters.
private static bool Equals(Bitmap bmp1, Bitmap bmp2)
{
if (!bmp1.Size.Equals(bmp2.Size))
{
return false;
}
for (int x = 0; x < bmp1.Width; ++x)
{
for (int y = 0; y < bmp1.Height; ++y)
{
if (bmp1.GetPixel(x, y) != bmp2.GetPixel(x, y))
{
return false;
}
}
}
return true;
}
add a comment |
up vote
5
down vote
Note that Bitmap inherits from Image, which implements IDisposable
. This means you very much better call Dispose()
on those objects are you are done with them (way many paths here with UI event handlers), or put them into using blocks. Same goes for OpenFileDialog
.
As per my comments, some using
usage (and try..finally
usage, incorporating Guffa's answer):
private Bitmap image1;
private Bitmap image2;
public Form1()
{
this.InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
using (var openDialog = new OpenFileDialog())
{
if (openDialog.ShowDialog() != DialogResult.OK)
{
return;
}
this.DisposeImage1();
this.image1 = new Bitmap(openDialog.FileName);
}
this.pictureBox1.Image = this.image1;
}
private void button2_Click(object sender, EventArgs e)
{
using (var openDialog = new OpenFileDialog())
{
if (openDialog.ShowDialog() != DialogResult.OK)
{
return;
}
this.DisposeImage2();
this.image2 = new Bitmap(openDialog.FileName);
}
this.pictureBox2.Image = this.image2;
}
private void button3_Click(object sender, EventArgs e)
{
MessageBox.Show(Compare(this.image1, this.image2) ? "Same Image." : "Different Image.");
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
this.DisposeImage2();
this.DisposeImage1();
}
private static bool Compare(Bitmap bmp1, Bitmap bmp2)
{
// Test to see if we have the same size of image
if (bmp1.Size != bmp2.Size)
{
return false;
}
var rect = new Rectangle(0, 0, bmp1.Width, bmp1.Height);
var bmpData1 = bmp1.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat);
try
{
var bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat);
try
{
unsafe
{
var ptr1 = (byte*)bmpData1.Scan0.ToPointer();
var ptr2 = (byte*)bmpData2.Scan0.ToPointer();
var width = 3 * rect.Width; // for 24bpp pixel data
for (var y = 0; y < rect.Height; y++)
{
for (var x = 0; x < width; x++)
{
if (*ptr1 != *ptr2)
{
return false;
}
ptr1++;
ptr2++;
}
ptr1 += bmpData1.Stride - width;
ptr2 += bmpData2.Stride - width;
}
}
}
finally
{
bmp2.UnlockBits(bmpData2);
}
}
finally
{
bmp1.UnlockBits(bmpData1);
}
return true;
}
private void DisposeImage1()
{
if (this.image1 == null)
{
return;
}
this.pictureBox1.Image = null;
this.image1.Dispose();
this.image1 = null;
}
private void DisposeImage2()
{
if (this.image2 == null)
{
return;
}
this.pictureBox2.Image = null;
this.image2.Dispose();
this.image2 = null;
}
ImageLockMode
doesn't exist? Also, the unsafe I'm getting an error
– puretppc
Jan 24 '14 at 19:17
1
You'll need to checkenable unsafe code
on the Build page of your project's options. Also, addusing System.Drawing.Imaging
to yourusing
directives at the top of the file to get access toImageLockMode
.
– Jesse C. Slicer
Jan 24 '14 at 20:53
in "var bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat)" last parameter bmp1.PixelFormat or bmp2.PixelFormat?
– Sajitha Rathnayake
Aug 15 '14 at 5:26
I got error "Bitmap region is already locked." in code "var bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat)"
– Sajitha Rathnayake
Aug 15 '14 at 5:30
add a comment |
up vote
0
down vote
Why convert in base64 or compare every pixel if there's hash comparison?
Do something like this:
byte fileData = File.ReadAllBytes(filePath);
byte hash = MD5.Create().ComputeHash(fileData);
And simply compare the hashes.
You'll need MD5CryptoServiceProvider
for that.
New contributor
add a comment |
up vote
-1
down vote
Have a look at this SO question.
https://stackoverflow.com/q/35151067/4062881
It decreases the size of image, turns it B&W, and then uses GetPixel() to generate hash.
It is much faster, efficient, and works! It is able to find equal images with:
- different file formats (e.g. jpg, png, bmp)
- rotation (90, 180, 270) - by changing the iteration order of i and j
- different dimensions (same aspect is required)
- different compression (tolerance is required in case of quality loss like jpeg artifacts) - you can accept a 99% equality to be the same image and 50% to be a different one.
Cheers..!! ;)
add a comment |
protected by Jamal♦ 5 hours ago
Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).
Would you like to answer one of these unanswered questions instead?
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
13
down vote
accepted
You can use the LockBits
method and pointers to access the image data directly.
Example for 24 bpp images:
bool equals = true;
Rectangle rect = new Rectangle(0, 0, bmp1.Width, bmp1.Height);
BitmapData bmpData1 = bmp1.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat);
BitmapData bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp2.PixelFormat);
unsafe {
byte* ptr1 = (byte*)bmpData1.Scan0.ToPointer();
byte* ptr2 = (byte*)bmpData2.Scan0.ToPointer();
int width = rect.Width * 3; // for 24bpp pixel data
for (int y = 0; equals && y < rect.Height; y++) {
for (int x = 0; x < width; x++) {
if (*ptr1 != *ptr2) {
equals = false;
break;
}
ptr1++;
ptr2++;
}
ptr1 += bmpData1.Stride - width;
ptr2 += bmpData2.Stride - width;
}
}
bmp1.UnlockBits(bmpData1);
bmp2.UnlockBits(bmpData2);
I assume I drag this in mycompare()
method?
– puretppc
Jan 24 '14 at 18:57
@puretppc: Yes, that is correct. After checking that the images have the same size and the correct pixel format.
– Guffa
Jan 24 '14 at 19:13
BitmapData
doesn't exist for me. AlsoUnsafe code may only appear if compiling with /unsafe
.
– puretppc
Jan 24 '14 at 19:16
@puretppc: Addusing System.Drawing.Imaging;
at the top, or useSystem.Drawing.Imaging.BitmapData
. (If you right click onBitmapData
both options can be done automatically underResolve
.) To use unsafe code you need to enable it in the project properties.
– Guffa
Jan 24 '14 at 19:24
Oh ok. But now I'm getting an error saying'System.Drawing.Imaging.ImageLockMode' does not contain a definition for 'Read'
At the very top of the program I putusing System.Drawing.Imaging;
– puretppc
Jan 24 '14 at 19:31
|
show 9 more comments
up vote
13
down vote
accepted
You can use the LockBits
method and pointers to access the image data directly.
Example for 24 bpp images:
bool equals = true;
Rectangle rect = new Rectangle(0, 0, bmp1.Width, bmp1.Height);
BitmapData bmpData1 = bmp1.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat);
BitmapData bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp2.PixelFormat);
unsafe {
byte* ptr1 = (byte*)bmpData1.Scan0.ToPointer();
byte* ptr2 = (byte*)bmpData2.Scan0.ToPointer();
int width = rect.Width * 3; // for 24bpp pixel data
for (int y = 0; equals && y < rect.Height; y++) {
for (int x = 0; x < width; x++) {
if (*ptr1 != *ptr2) {
equals = false;
break;
}
ptr1++;
ptr2++;
}
ptr1 += bmpData1.Stride - width;
ptr2 += bmpData2.Stride - width;
}
}
bmp1.UnlockBits(bmpData1);
bmp2.UnlockBits(bmpData2);
I assume I drag this in mycompare()
method?
– puretppc
Jan 24 '14 at 18:57
@puretppc: Yes, that is correct. After checking that the images have the same size and the correct pixel format.
– Guffa
Jan 24 '14 at 19:13
BitmapData
doesn't exist for me. AlsoUnsafe code may only appear if compiling with /unsafe
.
– puretppc
Jan 24 '14 at 19:16
@puretppc: Addusing System.Drawing.Imaging;
at the top, or useSystem.Drawing.Imaging.BitmapData
. (If you right click onBitmapData
both options can be done automatically underResolve
.) To use unsafe code you need to enable it in the project properties.
– Guffa
Jan 24 '14 at 19:24
Oh ok. But now I'm getting an error saying'System.Drawing.Imaging.ImageLockMode' does not contain a definition for 'Read'
At the very top of the program I putusing System.Drawing.Imaging;
– puretppc
Jan 24 '14 at 19:31
|
show 9 more comments
up vote
13
down vote
accepted
up vote
13
down vote
accepted
You can use the LockBits
method and pointers to access the image data directly.
Example for 24 bpp images:
bool equals = true;
Rectangle rect = new Rectangle(0, 0, bmp1.Width, bmp1.Height);
BitmapData bmpData1 = bmp1.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat);
BitmapData bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp2.PixelFormat);
unsafe {
byte* ptr1 = (byte*)bmpData1.Scan0.ToPointer();
byte* ptr2 = (byte*)bmpData2.Scan0.ToPointer();
int width = rect.Width * 3; // for 24bpp pixel data
for (int y = 0; equals && y < rect.Height; y++) {
for (int x = 0; x < width; x++) {
if (*ptr1 != *ptr2) {
equals = false;
break;
}
ptr1++;
ptr2++;
}
ptr1 += bmpData1.Stride - width;
ptr2 += bmpData2.Stride - width;
}
}
bmp1.UnlockBits(bmpData1);
bmp2.UnlockBits(bmpData2);
You can use the LockBits
method and pointers to access the image data directly.
Example for 24 bpp images:
bool equals = true;
Rectangle rect = new Rectangle(0, 0, bmp1.Width, bmp1.Height);
BitmapData bmpData1 = bmp1.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat);
BitmapData bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp2.PixelFormat);
unsafe {
byte* ptr1 = (byte*)bmpData1.Scan0.ToPointer();
byte* ptr2 = (byte*)bmpData2.Scan0.ToPointer();
int width = rect.Width * 3; // for 24bpp pixel data
for (int y = 0; equals && y < rect.Height; y++) {
for (int x = 0; x < width; x++) {
if (*ptr1 != *ptr2) {
equals = false;
break;
}
ptr1++;
ptr2++;
}
ptr1 += bmpData1.Stride - width;
ptr2 += bmpData2.Stride - width;
}
}
bmp1.UnlockBits(bmpData1);
bmp2.UnlockBits(bmpData2);
edited Jan 24 '14 at 20:14
answered Jan 24 '14 at 18:38
Guffa
6,6621226
6,6621226
I assume I drag this in mycompare()
method?
– puretppc
Jan 24 '14 at 18:57
@puretppc: Yes, that is correct. After checking that the images have the same size and the correct pixel format.
– Guffa
Jan 24 '14 at 19:13
BitmapData
doesn't exist for me. AlsoUnsafe code may only appear if compiling with /unsafe
.
– puretppc
Jan 24 '14 at 19:16
@puretppc: Addusing System.Drawing.Imaging;
at the top, or useSystem.Drawing.Imaging.BitmapData
. (If you right click onBitmapData
both options can be done automatically underResolve
.) To use unsafe code you need to enable it in the project properties.
– Guffa
Jan 24 '14 at 19:24
Oh ok. But now I'm getting an error saying'System.Drawing.Imaging.ImageLockMode' does not contain a definition for 'Read'
At the very top of the program I putusing System.Drawing.Imaging;
– puretppc
Jan 24 '14 at 19:31
|
show 9 more comments
I assume I drag this in mycompare()
method?
– puretppc
Jan 24 '14 at 18:57
@puretppc: Yes, that is correct. After checking that the images have the same size and the correct pixel format.
– Guffa
Jan 24 '14 at 19:13
BitmapData
doesn't exist for me. AlsoUnsafe code may only appear if compiling with /unsafe
.
– puretppc
Jan 24 '14 at 19:16
@puretppc: Addusing System.Drawing.Imaging;
at the top, or useSystem.Drawing.Imaging.BitmapData
. (If you right click onBitmapData
both options can be done automatically underResolve
.) To use unsafe code you need to enable it in the project properties.
– Guffa
Jan 24 '14 at 19:24
Oh ok. But now I'm getting an error saying'System.Drawing.Imaging.ImageLockMode' does not contain a definition for 'Read'
At the very top of the program I putusing System.Drawing.Imaging;
– puretppc
Jan 24 '14 at 19:31
I assume I drag this in my
compare()
method?– puretppc
Jan 24 '14 at 18:57
I assume I drag this in my
compare()
method?– puretppc
Jan 24 '14 at 18:57
@puretppc: Yes, that is correct. After checking that the images have the same size and the correct pixel format.
– Guffa
Jan 24 '14 at 19:13
@puretppc: Yes, that is correct. After checking that the images have the same size and the correct pixel format.
– Guffa
Jan 24 '14 at 19:13
BitmapData
doesn't exist for me. Also Unsafe code may only appear if compiling with /unsafe
.– puretppc
Jan 24 '14 at 19:16
BitmapData
doesn't exist for me. Also Unsafe code may only appear if compiling with /unsafe
.– puretppc
Jan 24 '14 at 19:16
@puretppc: Add
using System.Drawing.Imaging;
at the top, or use System.Drawing.Imaging.BitmapData
. (If you right click on BitmapData
both options can be done automatically under Resolve
.) To use unsafe code you need to enable it in the project properties.– Guffa
Jan 24 '14 at 19:24
@puretppc: Add
using System.Drawing.Imaging;
at the top, or use System.Drawing.Imaging.BitmapData
. (If you right click on BitmapData
both options can be done automatically under Resolve
.) To use unsafe code you need to enable it in the project properties.– Guffa
Jan 24 '14 at 19:24
Oh ok. But now I'm getting an error saying
'System.Drawing.Imaging.ImageLockMode' does not contain a definition for 'Read'
At the very top of the program I put using System.Drawing.Imaging;
– puretppc
Jan 24 '14 at 19:31
Oh ok. But now I'm getting an error saying
'System.Drawing.Imaging.ImageLockMode' does not contain a definition for 'Read'
At the very top of the program I put using System.Drawing.Imaging;
– puretppc
Jan 24 '14 at 19:31
|
show 9 more comments
up vote
10
down vote
One thing I have done in the past is to convert the images to 64-bit encoded strings and just string compare. It won't be as fast as using pointers, naturally. However, it can be done entirely in managed code, it doesn't require you to know bits per pixel, and it works for the Image base class.
byte image1Bytes;
byte image2Bytes;
using(var mstream = new MemoryStream())
{
image1.Save(mstream, image1.RawFormat);
image1Bytes = mstream.ToArray();
}
using(var mstream = new MemoryStream())
{
image2.Save(mstream, image2.RawFormat);
image2Bytes = mstream.ToArray();
}
var image164 = Convert.ToBase64String(image1Bytes);
var image264 = Convert.ToBase64String(image2Bytes);
return string.Equals(image164, image264);
Thanks this worked :) So my old code was about comparing BPP (bits per pixel)? I don't really know this since I got this off the another site
– puretppc
Jan 24 '14 at 18:58
3
Note that this will also compare any meta data in the images. If they for example are identical but with different resolution settings, this will return false.
– Guffa
Jan 24 '14 at 19:14
4
What is the purpose of converting to a base64 string? Why not simple compare the elements of both arrays (or streams)?
– NPSF3000
May 5 '14 at 8:30
add a comment |
up vote
10
down vote
One thing I have done in the past is to convert the images to 64-bit encoded strings and just string compare. It won't be as fast as using pointers, naturally. However, it can be done entirely in managed code, it doesn't require you to know bits per pixel, and it works for the Image base class.
byte image1Bytes;
byte image2Bytes;
using(var mstream = new MemoryStream())
{
image1.Save(mstream, image1.RawFormat);
image1Bytes = mstream.ToArray();
}
using(var mstream = new MemoryStream())
{
image2.Save(mstream, image2.RawFormat);
image2Bytes = mstream.ToArray();
}
var image164 = Convert.ToBase64String(image1Bytes);
var image264 = Convert.ToBase64String(image2Bytes);
return string.Equals(image164, image264);
Thanks this worked :) So my old code was about comparing BPP (bits per pixel)? I don't really know this since I got this off the another site
– puretppc
Jan 24 '14 at 18:58
3
Note that this will also compare any meta data in the images. If they for example are identical but with different resolution settings, this will return false.
– Guffa
Jan 24 '14 at 19:14
4
What is the purpose of converting to a base64 string? Why not simple compare the elements of both arrays (or streams)?
– NPSF3000
May 5 '14 at 8:30
add a comment |
up vote
10
down vote
up vote
10
down vote
One thing I have done in the past is to convert the images to 64-bit encoded strings and just string compare. It won't be as fast as using pointers, naturally. However, it can be done entirely in managed code, it doesn't require you to know bits per pixel, and it works for the Image base class.
byte image1Bytes;
byte image2Bytes;
using(var mstream = new MemoryStream())
{
image1.Save(mstream, image1.RawFormat);
image1Bytes = mstream.ToArray();
}
using(var mstream = new MemoryStream())
{
image2.Save(mstream, image2.RawFormat);
image2Bytes = mstream.ToArray();
}
var image164 = Convert.ToBase64String(image1Bytes);
var image264 = Convert.ToBase64String(image2Bytes);
return string.Equals(image164, image264);
One thing I have done in the past is to convert the images to 64-bit encoded strings and just string compare. It won't be as fast as using pointers, naturally. However, it can be done entirely in managed code, it doesn't require you to know bits per pixel, and it works for the Image base class.
byte image1Bytes;
byte image2Bytes;
using(var mstream = new MemoryStream())
{
image1.Save(mstream, image1.RawFormat);
image1Bytes = mstream.ToArray();
}
using(var mstream = new MemoryStream())
{
image2.Save(mstream, image2.RawFormat);
image2Bytes = mstream.ToArray();
}
var image164 = Convert.ToBase64String(image1Bytes);
var image264 = Convert.ToBase64String(image2Bytes);
return string.Equals(image164, image264);
edited Oct 26 '17 at 15:32
wonea
1034
1034
answered Jan 24 '14 at 18:47
Dan Lyons
3,4881019
3,4881019
Thanks this worked :) So my old code was about comparing BPP (bits per pixel)? I don't really know this since I got this off the another site
– puretppc
Jan 24 '14 at 18:58
3
Note that this will also compare any meta data in the images. If they for example are identical but with different resolution settings, this will return false.
– Guffa
Jan 24 '14 at 19:14
4
What is the purpose of converting to a base64 string? Why not simple compare the elements of both arrays (or streams)?
– NPSF3000
May 5 '14 at 8:30
add a comment |
Thanks this worked :) So my old code was about comparing BPP (bits per pixel)? I don't really know this since I got this off the another site
– puretppc
Jan 24 '14 at 18:58
3
Note that this will also compare any meta data in the images. If they for example are identical but with different resolution settings, this will return false.
– Guffa
Jan 24 '14 at 19:14
4
What is the purpose of converting to a base64 string? Why not simple compare the elements of both arrays (or streams)?
– NPSF3000
May 5 '14 at 8:30
Thanks this worked :) So my old code was about comparing BPP (bits per pixel)? I don't really know this since I got this off the another site
– puretppc
Jan 24 '14 at 18:58
Thanks this worked :) So my old code was about comparing BPP (bits per pixel)? I don't really know this since I got this off the another site
– puretppc
Jan 24 '14 at 18:58
3
3
Note that this will also compare any meta data in the images. If they for example are identical but with different resolution settings, this will return false.
– Guffa
Jan 24 '14 at 19:14
Note that this will also compare any meta data in the images. If they for example are identical but with different resolution settings, this will return false.
– Guffa
Jan 24 '14 at 19:14
4
4
What is the purpose of converting to a base64 string? Why not simple compare the elements of both arrays (or streams)?
– NPSF3000
May 5 '14 at 8:30
What is the purpose of converting to a base64 string? Why not simple compare the elements of both arrays (or streams)?
– NPSF3000
May 5 '14 at 8:30
add a comment |
up vote
9
down vote
I'll focus on problems in compare()
.
You're using the wrong equality comparison for the bitmap size. You need to compare the contents of the Size
objects, not whether they are the same reference.
A variable named flag
should be a… red flag! Not only is it vaguely named, its presence suggests that your code is ineffective. Avoid using variables for flow control; find more active ways to get to where you need to go.
In this case, the solution is an early return
. As soon as you find a single difference between the two images, you're done! You don't even need the equals
variable.
I would also rename compare()
for clarity, and make it static
because it is a pure function of its two parameters.
private static bool Equals(Bitmap bmp1, Bitmap bmp2)
{
if (!bmp1.Size.Equals(bmp2.Size))
{
return false;
}
for (int x = 0; x < bmp1.Width; ++x)
{
for (int y = 0; y < bmp1.Height; ++y)
{
if (bmp1.GetPixel(x, y) != bmp2.GetPixel(x, y))
{
return false;
}
}
}
return true;
}
add a comment |
up vote
9
down vote
I'll focus on problems in compare()
.
You're using the wrong equality comparison for the bitmap size. You need to compare the contents of the Size
objects, not whether they are the same reference.
A variable named flag
should be a… red flag! Not only is it vaguely named, its presence suggests that your code is ineffective. Avoid using variables for flow control; find more active ways to get to where you need to go.
In this case, the solution is an early return
. As soon as you find a single difference between the two images, you're done! You don't even need the equals
variable.
I would also rename compare()
for clarity, and make it static
because it is a pure function of its two parameters.
private static bool Equals(Bitmap bmp1, Bitmap bmp2)
{
if (!bmp1.Size.Equals(bmp2.Size))
{
return false;
}
for (int x = 0; x < bmp1.Width; ++x)
{
for (int y = 0; y < bmp1.Height; ++y)
{
if (bmp1.GetPixel(x, y) != bmp2.GetPixel(x, y))
{
return false;
}
}
}
return true;
}
add a comment |
up vote
9
down vote
up vote
9
down vote
I'll focus on problems in compare()
.
You're using the wrong equality comparison for the bitmap size. You need to compare the contents of the Size
objects, not whether they are the same reference.
A variable named flag
should be a… red flag! Not only is it vaguely named, its presence suggests that your code is ineffective. Avoid using variables for flow control; find more active ways to get to where you need to go.
In this case, the solution is an early return
. As soon as you find a single difference between the two images, you're done! You don't even need the equals
variable.
I would also rename compare()
for clarity, and make it static
because it is a pure function of its two parameters.
private static bool Equals(Bitmap bmp1, Bitmap bmp2)
{
if (!bmp1.Size.Equals(bmp2.Size))
{
return false;
}
for (int x = 0; x < bmp1.Width; ++x)
{
for (int y = 0; y < bmp1.Height; ++y)
{
if (bmp1.GetPixel(x, y) != bmp2.GetPixel(x, y))
{
return false;
}
}
}
return true;
}
I'll focus on problems in compare()
.
You're using the wrong equality comparison for the bitmap size. You need to compare the contents of the Size
objects, not whether they are the same reference.
A variable named flag
should be a… red flag! Not only is it vaguely named, its presence suggests that your code is ineffective. Avoid using variables for flow control; find more active ways to get to where you need to go.
In this case, the solution is an early return
. As soon as you find a single difference between the two images, you're done! You don't even need the equals
variable.
I would also rename compare()
for clarity, and make it static
because it is a pure function of its two parameters.
private static bool Equals(Bitmap bmp1, Bitmap bmp2)
{
if (!bmp1.Size.Equals(bmp2.Size))
{
return false;
}
for (int x = 0; x < bmp1.Width; ++x)
{
for (int y = 0; y < bmp1.Height; ++y)
{
if (bmp1.GetPixel(x, y) != bmp2.GetPixel(x, y))
{
return false;
}
}
}
return true;
}
answered Jan 25 '14 at 17:04
200_success
127k15148410
127k15148410
add a comment |
add a comment |
up vote
5
down vote
Note that Bitmap inherits from Image, which implements IDisposable
. This means you very much better call Dispose()
on those objects are you are done with them (way many paths here with UI event handlers), or put them into using blocks. Same goes for OpenFileDialog
.
As per my comments, some using
usage (and try..finally
usage, incorporating Guffa's answer):
private Bitmap image1;
private Bitmap image2;
public Form1()
{
this.InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
using (var openDialog = new OpenFileDialog())
{
if (openDialog.ShowDialog() != DialogResult.OK)
{
return;
}
this.DisposeImage1();
this.image1 = new Bitmap(openDialog.FileName);
}
this.pictureBox1.Image = this.image1;
}
private void button2_Click(object sender, EventArgs e)
{
using (var openDialog = new OpenFileDialog())
{
if (openDialog.ShowDialog() != DialogResult.OK)
{
return;
}
this.DisposeImage2();
this.image2 = new Bitmap(openDialog.FileName);
}
this.pictureBox2.Image = this.image2;
}
private void button3_Click(object sender, EventArgs e)
{
MessageBox.Show(Compare(this.image1, this.image2) ? "Same Image." : "Different Image.");
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
this.DisposeImage2();
this.DisposeImage1();
}
private static bool Compare(Bitmap bmp1, Bitmap bmp2)
{
// Test to see if we have the same size of image
if (bmp1.Size != bmp2.Size)
{
return false;
}
var rect = new Rectangle(0, 0, bmp1.Width, bmp1.Height);
var bmpData1 = bmp1.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat);
try
{
var bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat);
try
{
unsafe
{
var ptr1 = (byte*)bmpData1.Scan0.ToPointer();
var ptr2 = (byte*)bmpData2.Scan0.ToPointer();
var width = 3 * rect.Width; // for 24bpp pixel data
for (var y = 0; y < rect.Height; y++)
{
for (var x = 0; x < width; x++)
{
if (*ptr1 != *ptr2)
{
return false;
}
ptr1++;
ptr2++;
}
ptr1 += bmpData1.Stride - width;
ptr2 += bmpData2.Stride - width;
}
}
}
finally
{
bmp2.UnlockBits(bmpData2);
}
}
finally
{
bmp1.UnlockBits(bmpData1);
}
return true;
}
private void DisposeImage1()
{
if (this.image1 == null)
{
return;
}
this.pictureBox1.Image = null;
this.image1.Dispose();
this.image1 = null;
}
private void DisposeImage2()
{
if (this.image2 == null)
{
return;
}
this.pictureBox2.Image = null;
this.image2.Dispose();
this.image2 = null;
}
ImageLockMode
doesn't exist? Also, the unsafe I'm getting an error
– puretppc
Jan 24 '14 at 19:17
1
You'll need to checkenable unsafe code
on the Build page of your project's options. Also, addusing System.Drawing.Imaging
to yourusing
directives at the top of the file to get access toImageLockMode
.
– Jesse C. Slicer
Jan 24 '14 at 20:53
in "var bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat)" last parameter bmp1.PixelFormat or bmp2.PixelFormat?
– Sajitha Rathnayake
Aug 15 '14 at 5:26
I got error "Bitmap region is already locked." in code "var bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat)"
– Sajitha Rathnayake
Aug 15 '14 at 5:30
add a comment |
up vote
5
down vote
Note that Bitmap inherits from Image, which implements IDisposable
. This means you very much better call Dispose()
on those objects are you are done with them (way many paths here with UI event handlers), or put them into using blocks. Same goes for OpenFileDialog
.
As per my comments, some using
usage (and try..finally
usage, incorporating Guffa's answer):
private Bitmap image1;
private Bitmap image2;
public Form1()
{
this.InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
using (var openDialog = new OpenFileDialog())
{
if (openDialog.ShowDialog() != DialogResult.OK)
{
return;
}
this.DisposeImage1();
this.image1 = new Bitmap(openDialog.FileName);
}
this.pictureBox1.Image = this.image1;
}
private void button2_Click(object sender, EventArgs e)
{
using (var openDialog = new OpenFileDialog())
{
if (openDialog.ShowDialog() != DialogResult.OK)
{
return;
}
this.DisposeImage2();
this.image2 = new Bitmap(openDialog.FileName);
}
this.pictureBox2.Image = this.image2;
}
private void button3_Click(object sender, EventArgs e)
{
MessageBox.Show(Compare(this.image1, this.image2) ? "Same Image." : "Different Image.");
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
this.DisposeImage2();
this.DisposeImage1();
}
private static bool Compare(Bitmap bmp1, Bitmap bmp2)
{
// Test to see if we have the same size of image
if (bmp1.Size != bmp2.Size)
{
return false;
}
var rect = new Rectangle(0, 0, bmp1.Width, bmp1.Height);
var bmpData1 = bmp1.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat);
try
{
var bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat);
try
{
unsafe
{
var ptr1 = (byte*)bmpData1.Scan0.ToPointer();
var ptr2 = (byte*)bmpData2.Scan0.ToPointer();
var width = 3 * rect.Width; // for 24bpp pixel data
for (var y = 0; y < rect.Height; y++)
{
for (var x = 0; x < width; x++)
{
if (*ptr1 != *ptr2)
{
return false;
}
ptr1++;
ptr2++;
}
ptr1 += bmpData1.Stride - width;
ptr2 += bmpData2.Stride - width;
}
}
}
finally
{
bmp2.UnlockBits(bmpData2);
}
}
finally
{
bmp1.UnlockBits(bmpData1);
}
return true;
}
private void DisposeImage1()
{
if (this.image1 == null)
{
return;
}
this.pictureBox1.Image = null;
this.image1.Dispose();
this.image1 = null;
}
private void DisposeImage2()
{
if (this.image2 == null)
{
return;
}
this.pictureBox2.Image = null;
this.image2.Dispose();
this.image2 = null;
}
ImageLockMode
doesn't exist? Also, the unsafe I'm getting an error
– puretppc
Jan 24 '14 at 19:17
1
You'll need to checkenable unsafe code
on the Build page of your project's options. Also, addusing System.Drawing.Imaging
to yourusing
directives at the top of the file to get access toImageLockMode
.
– Jesse C. Slicer
Jan 24 '14 at 20:53
in "var bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat)" last parameter bmp1.PixelFormat or bmp2.PixelFormat?
– Sajitha Rathnayake
Aug 15 '14 at 5:26
I got error "Bitmap region is already locked." in code "var bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat)"
– Sajitha Rathnayake
Aug 15 '14 at 5:30
add a comment |
up vote
5
down vote
up vote
5
down vote
Note that Bitmap inherits from Image, which implements IDisposable
. This means you very much better call Dispose()
on those objects are you are done with them (way many paths here with UI event handlers), or put them into using blocks. Same goes for OpenFileDialog
.
As per my comments, some using
usage (and try..finally
usage, incorporating Guffa's answer):
private Bitmap image1;
private Bitmap image2;
public Form1()
{
this.InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
using (var openDialog = new OpenFileDialog())
{
if (openDialog.ShowDialog() != DialogResult.OK)
{
return;
}
this.DisposeImage1();
this.image1 = new Bitmap(openDialog.FileName);
}
this.pictureBox1.Image = this.image1;
}
private void button2_Click(object sender, EventArgs e)
{
using (var openDialog = new OpenFileDialog())
{
if (openDialog.ShowDialog() != DialogResult.OK)
{
return;
}
this.DisposeImage2();
this.image2 = new Bitmap(openDialog.FileName);
}
this.pictureBox2.Image = this.image2;
}
private void button3_Click(object sender, EventArgs e)
{
MessageBox.Show(Compare(this.image1, this.image2) ? "Same Image." : "Different Image.");
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
this.DisposeImage2();
this.DisposeImage1();
}
private static bool Compare(Bitmap bmp1, Bitmap bmp2)
{
// Test to see if we have the same size of image
if (bmp1.Size != bmp2.Size)
{
return false;
}
var rect = new Rectangle(0, 0, bmp1.Width, bmp1.Height);
var bmpData1 = bmp1.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat);
try
{
var bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat);
try
{
unsafe
{
var ptr1 = (byte*)bmpData1.Scan0.ToPointer();
var ptr2 = (byte*)bmpData2.Scan0.ToPointer();
var width = 3 * rect.Width; // for 24bpp pixel data
for (var y = 0; y < rect.Height; y++)
{
for (var x = 0; x < width; x++)
{
if (*ptr1 != *ptr2)
{
return false;
}
ptr1++;
ptr2++;
}
ptr1 += bmpData1.Stride - width;
ptr2 += bmpData2.Stride - width;
}
}
}
finally
{
bmp2.UnlockBits(bmpData2);
}
}
finally
{
bmp1.UnlockBits(bmpData1);
}
return true;
}
private void DisposeImage1()
{
if (this.image1 == null)
{
return;
}
this.pictureBox1.Image = null;
this.image1.Dispose();
this.image1 = null;
}
private void DisposeImage2()
{
if (this.image2 == null)
{
return;
}
this.pictureBox2.Image = null;
this.image2.Dispose();
this.image2 = null;
}
Note that Bitmap inherits from Image, which implements IDisposable
. This means you very much better call Dispose()
on those objects are you are done with them (way many paths here with UI event handlers), or put them into using blocks. Same goes for OpenFileDialog
.
As per my comments, some using
usage (and try..finally
usage, incorporating Guffa's answer):
private Bitmap image1;
private Bitmap image2;
public Form1()
{
this.InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
using (var openDialog = new OpenFileDialog())
{
if (openDialog.ShowDialog() != DialogResult.OK)
{
return;
}
this.DisposeImage1();
this.image1 = new Bitmap(openDialog.FileName);
}
this.pictureBox1.Image = this.image1;
}
private void button2_Click(object sender, EventArgs e)
{
using (var openDialog = new OpenFileDialog())
{
if (openDialog.ShowDialog() != DialogResult.OK)
{
return;
}
this.DisposeImage2();
this.image2 = new Bitmap(openDialog.FileName);
}
this.pictureBox2.Image = this.image2;
}
private void button3_Click(object sender, EventArgs e)
{
MessageBox.Show(Compare(this.image1, this.image2) ? "Same Image." : "Different Image.");
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
this.DisposeImage2();
this.DisposeImage1();
}
private static bool Compare(Bitmap bmp1, Bitmap bmp2)
{
// Test to see if we have the same size of image
if (bmp1.Size != bmp2.Size)
{
return false;
}
var rect = new Rectangle(0, 0, bmp1.Width, bmp1.Height);
var bmpData1 = bmp1.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat);
try
{
var bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat);
try
{
unsafe
{
var ptr1 = (byte*)bmpData1.Scan0.ToPointer();
var ptr2 = (byte*)bmpData2.Scan0.ToPointer();
var width = 3 * rect.Width; // for 24bpp pixel data
for (var y = 0; y < rect.Height; y++)
{
for (var x = 0; x < width; x++)
{
if (*ptr1 != *ptr2)
{
return false;
}
ptr1++;
ptr2++;
}
ptr1 += bmpData1.Stride - width;
ptr2 += bmpData2.Stride - width;
}
}
}
finally
{
bmp2.UnlockBits(bmpData2);
}
}
finally
{
bmp1.UnlockBits(bmpData1);
}
return true;
}
private void DisposeImage1()
{
if (this.image1 == null)
{
return;
}
this.pictureBox1.Image = null;
this.image1.Dispose();
this.image1 = null;
}
private void DisposeImage2()
{
if (this.image2 == null)
{
return;
}
this.pictureBox2.Image = null;
this.image2.Dispose();
this.image2 = null;
}
edited Apr 13 '17 at 12:40
Community♦
1
1
answered Jan 24 '14 at 19:05
Jesse C. Slicer
11.3k2740
11.3k2740
ImageLockMode
doesn't exist? Also, the unsafe I'm getting an error
– puretppc
Jan 24 '14 at 19:17
1
You'll need to checkenable unsafe code
on the Build page of your project's options. Also, addusing System.Drawing.Imaging
to yourusing
directives at the top of the file to get access toImageLockMode
.
– Jesse C. Slicer
Jan 24 '14 at 20:53
in "var bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat)" last parameter bmp1.PixelFormat or bmp2.PixelFormat?
– Sajitha Rathnayake
Aug 15 '14 at 5:26
I got error "Bitmap region is already locked." in code "var bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat)"
– Sajitha Rathnayake
Aug 15 '14 at 5:30
add a comment |
ImageLockMode
doesn't exist? Also, the unsafe I'm getting an error
– puretppc
Jan 24 '14 at 19:17
1
You'll need to checkenable unsafe code
on the Build page of your project's options. Also, addusing System.Drawing.Imaging
to yourusing
directives at the top of the file to get access toImageLockMode
.
– Jesse C. Slicer
Jan 24 '14 at 20:53
in "var bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat)" last parameter bmp1.PixelFormat or bmp2.PixelFormat?
– Sajitha Rathnayake
Aug 15 '14 at 5:26
I got error "Bitmap region is already locked." in code "var bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat)"
– Sajitha Rathnayake
Aug 15 '14 at 5:30
ImageLockMode
doesn't exist? Also, the unsafe I'm getting an error– puretppc
Jan 24 '14 at 19:17
ImageLockMode
doesn't exist? Also, the unsafe I'm getting an error– puretppc
Jan 24 '14 at 19:17
1
1
You'll need to check
enable unsafe code
on the Build page of your project's options. Also, add using System.Drawing.Imaging
to your using
directives at the top of the file to get access to ImageLockMode
.– Jesse C. Slicer
Jan 24 '14 at 20:53
You'll need to check
enable unsafe code
on the Build page of your project's options. Also, add using System.Drawing.Imaging
to your using
directives at the top of the file to get access to ImageLockMode
.– Jesse C. Slicer
Jan 24 '14 at 20:53
in "var bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat)" last parameter bmp1.PixelFormat or bmp2.PixelFormat?
– Sajitha Rathnayake
Aug 15 '14 at 5:26
in "var bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat)" last parameter bmp1.PixelFormat or bmp2.PixelFormat?
– Sajitha Rathnayake
Aug 15 '14 at 5:26
I got error "Bitmap region is already locked." in code "var bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat)"
– Sajitha Rathnayake
Aug 15 '14 at 5:30
I got error "Bitmap region is already locked." in code "var bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat)"
– Sajitha Rathnayake
Aug 15 '14 at 5:30
add a comment |
up vote
0
down vote
Why convert in base64 or compare every pixel if there's hash comparison?
Do something like this:
byte fileData = File.ReadAllBytes(filePath);
byte hash = MD5.Create().ComputeHash(fileData);
And simply compare the hashes.
You'll need MD5CryptoServiceProvider
for that.
New contributor
add a comment |
up vote
0
down vote
Why convert in base64 or compare every pixel if there's hash comparison?
Do something like this:
byte fileData = File.ReadAllBytes(filePath);
byte hash = MD5.Create().ComputeHash(fileData);
And simply compare the hashes.
You'll need MD5CryptoServiceProvider
for that.
New contributor
add a comment |
up vote
0
down vote
up vote
0
down vote
Why convert in base64 or compare every pixel if there's hash comparison?
Do something like this:
byte fileData = File.ReadAllBytes(filePath);
byte hash = MD5.Create().ComputeHash(fileData);
And simply compare the hashes.
You'll need MD5CryptoServiceProvider
for that.
New contributor
Why convert in base64 or compare every pixel if there's hash comparison?
Do something like this:
byte fileData = File.ReadAllBytes(filePath);
byte hash = MD5.Create().ComputeHash(fileData);
And simply compare the hashes.
You'll need MD5CryptoServiceProvider
for that.
New contributor
New contributor
answered 7 hours ago
F.H.
11
11
New contributor
New contributor
add a comment |
add a comment |
up vote
-1
down vote
Have a look at this SO question.
https://stackoverflow.com/q/35151067/4062881
It decreases the size of image, turns it B&W, and then uses GetPixel() to generate hash.
It is much faster, efficient, and works! It is able to find equal images with:
- different file formats (e.g. jpg, png, bmp)
- rotation (90, 180, 270) - by changing the iteration order of i and j
- different dimensions (same aspect is required)
- different compression (tolerance is required in case of quality loss like jpeg artifacts) - you can accept a 99% equality to be the same image and 50% to be a different one.
Cheers..!! ;)
add a comment |
up vote
-1
down vote
Have a look at this SO question.
https://stackoverflow.com/q/35151067/4062881
It decreases the size of image, turns it B&W, and then uses GetPixel() to generate hash.
It is much faster, efficient, and works! It is able to find equal images with:
- different file formats (e.g. jpg, png, bmp)
- rotation (90, 180, 270) - by changing the iteration order of i and j
- different dimensions (same aspect is required)
- different compression (tolerance is required in case of quality loss like jpeg artifacts) - you can accept a 99% equality to be the same image and 50% to be a different one.
Cheers..!! ;)
add a comment |
up vote
-1
down vote
up vote
-1
down vote
Have a look at this SO question.
https://stackoverflow.com/q/35151067/4062881
It decreases the size of image, turns it B&W, and then uses GetPixel() to generate hash.
It is much faster, efficient, and works! It is able to find equal images with:
- different file formats (e.g. jpg, png, bmp)
- rotation (90, 180, 270) - by changing the iteration order of i and j
- different dimensions (same aspect is required)
- different compression (tolerance is required in case of quality loss like jpeg artifacts) - you can accept a 99% equality to be the same image and 50% to be a different one.
Cheers..!! ;)
Have a look at this SO question.
https://stackoverflow.com/q/35151067/4062881
It decreases the size of image, turns it B&W, and then uses GetPixel() to generate hash.
It is much faster, efficient, and works! It is able to find equal images with:
- different file formats (e.g. jpg, png, bmp)
- rotation (90, 180, 270) - by changing the iteration order of i and j
- different dimensions (same aspect is required)
- different compression (tolerance is required in case of quality loss like jpeg artifacts) - you can accept a 99% equality to be the same image and 50% to be a different one.
Cheers..!! ;)
answered May 30 '17 at 9:43
Vijay Chavda
992
992
add a comment |
add a comment |
protected by Jamal♦ 5 hours ago
Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).
Would you like to answer one of these unanswered questions instead?
1
Note that
Bitmap
inherits fromImage
, which implementsIDisposable
. This means you very much better callDispose()
on those objects are you are done with them (way many paths here with UI event handlers), or put them intousing
blocks.– Jesse C. Slicer
Jan 24 '14 at 18:45
1
Oh, and same goes for
OpenFileDialog
. I'll probably post an answer to show some of this.– Jesse C. Slicer
Jan 24 '14 at 18:48
1
See ImageComparer.Compare method. Has overloads to specify tolerance. It is available since VS2102. msdn.microsoft.com/en-us/library/…
– user3285954
Jul 2 '15 at 20:06