Comparing two images using ImageMagick and C# - c#

I want to compare two images and then generate and save an image that will show all the differences that has been found,
for example:
I am using ImageMagick: https://magick.codeplex.com/
But they don't have full documentation for C#.
I found only: http://www.imagemagick.org/Usage/compare/
This code for example show value from 0-1 that represent how similar the pictures are:
MagickImage img1 = new MagickImage(#"C:\test\Image1.jpg");
MagickImage img2 = new MagickImage(#"C:\test\Image2.jpg");
double diff = img1.Compare(img2,new ErrorMetric());
But how can I compare the images using ImageMagick and then save the result as shown in the example above and in their website?
Update:
With the help of dlemstra I wrote the following code and I generate images that suppose to show the difference as in the example above.
MagickImage img1 = new MagickImage(#"C:\test\Image1.jpg");
MagickImage img2 = new MagickImage(#"C:\test\Image2.jpg");
MagickImage img3 = new MagickImage(#"C:\test\Image3.jpg");
MagickImage img4 = new MagickImage(#"C:\test\DiffImage.jpg");
MagickImage img5 = new MagickImage(#"C:\test\DiffImage.jpg");
var imgDiff = new MagickImage();
img1.Compare(img2, new ErrorMetric(), imgDiff);
imgDiff.Write(#"C:\test\Diff4.jpg");
img1.Compare(img3, new ErrorMetric(), imgDiff);
imgDiff.Write(#"C:\test\Diff5.jpg");
img1.Compare(img4, new ErrorMetric(), imgDiff);
imgDiff.Write(#"C:\test\Diff6.jpg");
img5.Compare(img4, new ErrorMetric(), imgDiff);
imgDiff.Write(#"C:\test\Diff7.jpg");
The Strange results are: When I compare the following two images with the marked only difference:
This is the result that I get (And not as the example above from "imageMagick"

You will need to use one of the other overloads of the Compare method for this. The example below demonstrates how to do this:
using (var img1 = new MagickImage(#"C:\test\Image1.jpg"))
{
using (var img2 = new MagickImage(#"C:\test\Image2.jpg"))
{
using (var imgDiff = new MagickImage())
{
double diff = img1.Compare(img2, new ErrorMetric(), imgDiff);
imgDiff.Write(#"C:\test\Diff-Image1-Image2.jpg");
}
}
}
But when you are working with jpeg images (they are lossy) you probably also want to set the ColorFuzz on the first image:
img1.ColorFuzz = new Percentage(5); // adjust this value for your situation
This will make it so that pixels that are almost the same will also match.

Lessons Learned:
Wanted to add some important notes so others hopefully avoid the pitfalls which I ran into when testing out ImageMagick (or any compare tool) for the first time.
Beware of editing in Windows Paint in general.
Don’t edit a *.png with a transparent background in Windows paint and expect a good compare. Windows Paint doesn’t handle transparent background and the png you edited in Paint will now have a white background. The Image will look exactly the same to the naked eye but the image comparers know better.
If you have SnagIt, this is a better tool for making edits to an image when you want to put a image compare tool to the test.
Conclusion:
The code written by #dlemstra does work as expected. Just make sure that when you are testing out the first time that the second image (which you modified) didn’t get unintentionally modified by the image editor that you use. This is a general warning for when you are testing out any image compare tool for the first time to see if you want to use it or not.
Examples:
Example 1: Transparent png + Windows Paint
Downloading a transparent image, making and edit to it in Paint which unintentionally also changes background to white instead of transparent.
Just by opening, then saving the second image in Paint without making any edits to the image will cause the diff to look like this:
I couldn’t figure out what was going on until I compared with Beyond Compare:
Example 2: Complex *.jpg + Windows Paint
Windows Paint was also not good at keeping complex images identical between saves:
The big red areas were changes I had made, but the thin outlines of the roses were changes that Windows Paint made to the picture
Even when I made no changes at all and just open, saved and closed the second image in Paint (and the original image was an image which had also been saved in Paint), Paint still made undesired edits to the picture (dark red dots in image):
I then had an original image which had been saved in Paint and copied this image, opened the second image in snagIt, saved the second image in snagit, and then closed the image and compared the two images (which should have been identical). However, it seemed that snagIt made it’s own modifications to the original ‘Paint saved’ image:
Lastly, I copied the ‘Snagit saved’ image, opened this second image also in SnagIt, made an edit to the second image, saved the image in SnagIt and then closed the image. SnagIt did not make any modifications to this image and the compare showed exactly what I expected:
Lastly:
Most information you find about ImageMagick pertains to using it via the command line. You can add the Magick.Net nuget to your C# project in Visual Studio by installing it via the NuGet Package Manager

Related

Bitmap.Save(...) generates different image than actual

I've parsed an image with the following code
Bitmap img = (Bitmap)Bitmap.FromFile("file.jpg");
And after saved so
img.Save("file2.jpg");
I did not modify anything, but looking on diff of the both images, I see that the new one is different. How I can fix that? I want to keep the colors

Winforms: Capture part of PDF image to OCR

This is a C# winforms question.
The process I am trying to achieve is the following:
Using AxAcroPDFLib I'm loading a pdf file to the form
I want the user to be able to specify a square on that PDF and create a bmp from it
That bmp will then be loaded to a OCR to become text
What is my issue:
Step 1 and 3 are easy to do, the problem is how to allow the user to draw a square on top of the AxAcroPDFLib for a screenshot.
I already got different ways to draw squares on native winform components, but AxAcroPDFLib does not support mouse down, up, move, etc and paint events.
There is the option to convert the PDF to bitmap and display it on a picturebox and deal with events for drawing the square. Problem with that approach is that my PDF's are usually more than two pages, and I would like to avoid the conversion pdf to bmp due to changes to image quality that will impact on OCR.
I came to think that maybe something that works as the windows snippingtool would do the the job. My application would get the screenshot, temporarily save the image on disk (must be a file for OCR), I would then pass it to the OCR and done. Hard part, I could not think on how to take the screenshot of part of the PDF.
Do anyone here have any suggestion to different components or workarounds to deal with the requirement above? I am using Adobe just because it is simple, but maybe there are other components better suited to handle my requirements? I googled but haven't found any free ones, trying to avoid paid options.
Thanks
At some point in this process, the PDF is going to have to be rasterized in order to be passed to the OCR, so I don't totally understand your objection to converting it to a bitmap. If you're okay with Snipping Tool's behavior, then you must be OK with the quality of the PDF control's PDF->screen rasterization. If that resolution is acceptable, why not just capture the control's content to a Bitmap and let the user draw the selection marquee over that Bitmap?
Here is code I'm using to capture a control's contents to a Bitmap in Windows Forms. One caveat is that this is really a screen capture, so any windows or controls that overlap the control's visible area will be captured in the image.
using (Bitmap b = new Bitmap(width, height))
{
using (Graphics g = Graphics.FromImage(b))
{
Point p1 = myControl.PointToScreen(new Point(0, 0));
g.CopyFromScreen(p1.X, p1.Y, 0, 0, size);
}
// do stuff here with your Bitmap
}

Remove Black Border From Scanned Image c#

I have an application that scan Images from scanner but some scanners put a black border around the saved image.
How can I remove that black border?
Thanks so much for your participation.
I’ve had good luck in the past process images using the Magick.NET library. It’s available on Codeplex or you can install it using NuGet in Visual Studio. Documentation for the library is a little sparse, but it’s served me well in the past.
Depending upon the exact nature of the images you’re dealing with, you might be able to do something as simple as crop off the edges where the border is and then add a white (or whatever color; I just assumed that you were scanning text documents or something) border to bring the image back up to a standardized size. If having a standardized size doesn’t matter, then of course you can just leave the image cropped. If that sounds like a viable solution, here’s some code that should accomplish what you need:
using (MagickImage image = new MagickImage(#"path_to_original"))
{
int width = image.Width, height = image.Height;
image.Crop(width - 800, height - 800);
//if the image needs to be brought back up to a standarized size
image.BorderColor = new ColorRGB(System.Drawing.Color.White);
image.Border(100, 100);
image.Write(#"path_to_cropped_image_with_no_more_black_border_around_it");
}
You will, of course need to add your own values for just how much width you need to crop off/add back in.

Stopping effects from repeating on one another

I posted this question earlier but I have modified my code to a simple algorithm and I still have the same issue as before:
I created a picturebox which, when an effect is selected, it will then change the image in the picturebox using the color matrix.
The issues I'm having is if I choose another effect when one is selected the old effect will not disappear, instead it will just stay there and be underneath the new effect selected. The effects I'm using is sepia and greyscale for now, but can anyone help me so that once one effect is selected, the old effect is cleared rather than them just stacking up on one another. "
The key here is to cache the originalImage in a non-volatile area. For example, load it up into a hidden pictureBox that you don't touch.
When you want to apply an effect, copy the originalImage over into a displayImage picturebox and then apply the effect.
It also looks like you are setting your image to the image that is there. I am not sure but this may be taking into account what you have already set. For example when you set
Image originalImage = pictureBox.Image;
This may be taking the image you have displayed along with any effects you have already applied and setting that as your image to be modified. Like I said I am unsure of this since I can't test it at the moment.
EDIT
The following works for me:
Replace
Bitmap originalImage = (Bitmap)displayPictureBox.Image;
originalImage = (Bitmap)pictureBox.Image.Clone();
With
Image therealoriginalimage = Image.FromFile(#"C:\Users\Me\Desktop\testimg.png");
Bitmap originalImage = (Bitmap)therealoriginalimage;
As both answers mention it looks like you are setting your original image = what is currently in the picture box.
The above code is a quick fix so you can see exactly what was happening. You should modify this and have the originalimage saved as a varible as soon as your app starts. It will be much cleaner than the example above that sets the image each time you call the method

overlay images on top of an existing image (web)

My goal is to display a large rectangular image in a section of a webpage that will act as a background for other, smaller images to be laid on top of. The smaller rectangular images will be dynamically selected based upon database entries. I was able to create a java applet that drew the larger base rectangular image and then drew the smaller images over the base image. This worked very well.
I am attempting to recreate the functionality using C# in Microsoft Visual Web Developer 2010. I have found system.drawing functionally that may work, but haven’t found a web based solution yet. Any help would be appreciated.
If I understand correctly, you want to overlay smaller images on top of another image. At the end you'll end up with one image to display. This is easy to do in C#:
string image1 = #"c:\image.jpg";
string image2 = #"c:\image2.jpg";
System.Drawing.Image canvas = Bitmap.FromFile( image1 );
Graphics gra = Graphics.FromImage( canvas );
Bitmap smallImg = new Bitmap(image2);
gra.DrawImage( smallImg, new Point( 70, 70 ) );
canvas.Save( #"c:\newimage.jpg", System.Drawing.Imaging.ImageFormat.Jpeg );
My two cents here... Another thing which helped me on .NET 2.0 and 3.0 was explicitly deleting the Image, Graphics and Bitmap objects after you are done, specially when you would be accessing any of the image sources (image1, image2 and smallImg above) within the same routine.
Deleting these objects will instantly release the file locks. I experienced that the garbage collector wouldn't necessarily clean these up for me at the desired time, even if I made a separate sub-routine for my image manipulation.

Categories

Resources