I have a picture:
size of 1000x1000 white with random black dots. (It may contain a black square (size 50x50))
Is there an easy way to know if the picture contains a black square (size 50x50)? I thought of scanning every pixel of the picture and if a black pixel was found, scan the one next to him till I get a 50x50 square or till I get a white pixel and keep scanning. but it will have to scan over a million pixel (if he hasn't found the square).
Thats the basically the code (no need to complete it, as I said before, it will take way too much time to scan it. million times if the whole picture is white and a lot more according to the number of black pixels.)
for (int i = 0; i < pic.Width; i++)
{
for (int j = 0; j < pic.Height; j++)
{
if (pic.GetPixel(i, j) == Color.Black)
{
//Search for the entire square at that area
}
}
}
And yes, time is important (thats why I don't want to get pixel over a million times). Any ideas?
Like the Boyer-Moore string searching algorithm, if the item you are looking at is not part of what you are looking for, you can skip the whole size of the what you are looking for. In your case, you can check to see if a given pixel is black. If it's not, you can skip forward 50 pixels. If it is, you have a small box to look for your black square in.
In this case, though, you may not need anything so complicated. I'm guessing that if your algorithm is too slow it's because you're calling the GetPixel function a million times, and that is the slow part. If you can get your pixels into a 2D array, your algorithm will probably go fast enough to not need to be rewritten.
Assuming that you're using a System.Drawing.Bitmap check out the LockBits documentation to see a small sample that includes copying a bitmap to a 1D array for super-fast access.
If you are only looking for a square of a specific size, then you can optimise this by only scanning every 50th row (or column) of pixels, thereby cutting your workload dramatically.
Theoretically, you only need to check for a black/white in 1 pixel from every 50x50 block. If it's black, then you try spreading from there, if it's white then just skip to the next block: clearly there is a white pixel in this block so there isn't a black box here. Following this, you've already cut your work to 1 / 2500th of what it was originally, you are now only checking 400 pixels initially.
Usually the best optimisations, especially when first designing an algorithm, are around reducing work done rather than doing it more efficiently. Try to think of creative ways to reducing the input to a more manageable size.
check out AForge.net framework suite. It has imaging library with Blob and pattern searching. You can search shapes too. Its free.
You can find it here http://www.aforgenet.com/framework/
Here is the link that lists features
http://www.aforgenet.com/framework/features
Edit
Here is the sample for shape checking. I have used Aforge in a prototype and it worked for me.
http://www.aforgenet.com/articles/shape_checker/
Related
I saw a lot a topic about this, I understood the theory but I'm not able to code this.
I have some pictures and I want to determine if they are blurred or not. I found a library (aforge.dll) and I used it to compte a FFT for an image.
As an example, there is two images i'm working on :
My code is in c# :
public Bitmap PerformFFT(Bitmap Picture)
{
//Loade Image
ComplexImage output = ComplexImage.FromBitmap(Picture);
// Perform FFT
output.ForwardFourierTransform();
// return image
return = output.ToBitmap();
}
How can I determine if the image is blurred ? I am not very comfortable with the theory, I need concret example. I saw this post, but I have no idea how to do that.
EDIT:
I'll clarify my question. When I have a 2D array of complex ComplexImage output (image FFT), what is the C# code (or pseudo code) I can use to determine if image is blurred ?
The concept of "blurred" is subjective. How much power at high frequencies indicates it's not blurry? Note that a blurry image of a complex scene has more power at high frequencies than a sharp image of a very simple scene. For example a sharp picture of a completely uniform scene has no high frequencies whatsoever. Thus it is impossible to define a unique blurriness measure.
What is possible is to compare two images of the same scene, and determine which one is more blurry (or identically, which one is sharper). This is what is used in automatic focussing. I don't know how exactly what process commercial cameras use, but in microscopy, images are taken at a series of focal depths, and compared.
One of the classical comparison methods doesn't involve Fourier transforms at all. One computes the local variance (for each pixel, take a small window around it and compute the variance for those values), and averages it across the image. The image with the highest variance has the best focus.
Comparing high vs low frequencies as in MBo's answer would be comparable to computing the Laplace filtered image, and averaging its absolute values (because it can return negative values). The Laplace filter is a high-pass filter, meaning that low frequencies are removed. Since the power in the high frequencies gives a relative measure of sharpness, this statistic does too (again relative, it is to be compared only to images of the same scene, taken under identical circumstances).
Blurred image has FFT result with smaller magnitude in high-frequency regions. Array elements with low indexes (near Result[0][0]) represent low-frequency region.
So divide resulting array by some criteria, sum magnitudes in both regions and compare them. For example, select a quarter of result array (of size M) with index<M/2 and indexy<M/2
For series of more and more blurred image (for the same initial image) you should see higher and higher ratio Sum(Low)/Sum(High)
Result is square array NxN. It has central symmetry (F(x,y)=F(-x,-y) because source is pure real), so it is enough to treat top half of array with y<N/2.
Low-frequency components are located near top-left and top-right corners of array (smallest values of y, smallest and highest values of x). So sum magnitudes of array elements in ranges
for y in range 0..N/2
for x in range 0..N
amp = magnitude(y,x)
if (y<N/4) and ((x<N/4)or (x>=3*N/4))
low = low + amp
else
high = high + amp
Note that your picture shows jumbled array pieces - this is standard practice to show zero component in the center.
I have an RGB image.Suppose say I have two circles in it.I want to know which one is filled and which one is not.I followed the following steps:
-imported the image as Bitmap
-converted into grayscale and used CannyEdgeDetector filter to find the edges. I get the following image
circle containing the letter "D" gives two edges, where as I need only one circle edge. Secondly, how do I find out which circle is filled and which one is not.
For the MCQ answers sheet, it might be easier to go by positions of the circles.
Just compare stock images of the clear, circled A, B, C and D's to the scanned images and see which differ the most. A simple darkness summation might be enough.
Also: Comparing the circles against each other might be useful too to compensate for a bad/dark/light scan or smudgy paper.
For special cases if the test isn't absolutely sure I'd probably pass it to a human being for further investigation. E.g., when you allow students to undo an answer by circling their second guess or when a student decides to make a real mess by using a bad eraser.
Final tip: make sure you do not accept answers that have the correct circle filled; make sure the other circles are clear at the same time so students can't cheat by filling all circles. (Some professors use a paper mask that overlays all bad answers so they can quickly spot unmarked correct answers. But if the student just marks all answers this fails big time.)
I would not know any "formal" algorithm matching your criteria. I would also doubt that you would find any.
When you say the circles are "darkened", this can be interpreted as this: "Many pixels (above a population threshold) would be black, or at least dark (above a colour threshold).". Based on known circle and radius, I would follow this approach (written in pseudocode but I suppose you get the meaning):
//define thresholds
colourThreshold=...
populationThreshold=...
centerPoint = getCircleCenter();
radius = getCircleRadius();
darkPixelsCount = 0;
for(x=centerPoint.X-radius;x<centerPoint.X+radius;x++){
for(y=centerPoint.Y-sqrt(abs(radius^2-(x - centerPoint.X)^2));centerPoint.Y+sqrt(abs(radius^2-(x - centerPoint.X)^2));y++){
if (image(x, y) > colourThreshold){
darkPixelsCounter++;
if(darkPixelsCounter > populationThreshold){
//If you reach this point, circle has been darkened
return;
}
}
}
}
//If you reach this point, circle has not been darkened
return;
I don't know if it is efficient, or if there is a more elegant way to do it. I suppose you could play with performance and accuracy by moderating the thresholds.
Hope I helped!
Perform blob detection, with a pixel count
or even simpler count the black pixels
or even simpler and faster, take middle line and count how often it switches from white to black
I have 2 bmp images.
ImageA is a screenshot (example)
ImageB is a subset of that. Say for example, an icon.
I want to find the X,Y coordinates of ImageB within ImageA (if it exists).
Any idea how I would do that?
Here's a quick sample but it is slow take around 4-6 seconds, but it does exactly what you looking for and i know this post is old but if anyone else visiting this post recently
you can look this thing
you need .NET AForge namespace or framework google it and install it
include AForge name space in your project and that's it
it finds the pictiure with another and gives out the coordinates.
System.Drawing.Bitmap sourceImage = (Bitmap)Bitmap.FromFile(#"C:\SavedBMPs\1.jpg");
System.Drawing.Bitmap template = (Bitmap)Bitmap.FromFile(#"C:\SavedBMPs\2.jpg");
// create template matching algorithm's instance
// (set similarity threshold to 92.1%)
ExhaustiveTemplateMatching tm = new ExhaustiveTemplateMatching(0.921f);
// find all matchings with specified above similarity
TemplateMatch[] matchings = tm.ProcessImage(sourceImage, template);
// highlight found matchings
BitmapData data = sourceImage.LockBits(
new Rectangle(0, 0, sourceImage.Width, sourceImage.Height),
ImageLockMode.ReadWrite, sourceImage.PixelFormat);
foreach (TemplateMatch m in matchings)
{
Drawing.Rectangle(data, m.Rectangle, Color.White);
MessageBox.Show(m.Rectangle.Location.ToString());
// do something else with matching
}
sourceImage.UnlockBits(data);
So is there any warping of ImageB in ImageA?
How "exact" are the images, as in, pixel-for-pixel they will be the same?
How much computational power do you have for this?
If the answers to the first two questions are No and Yes, then you have a simple problem. It also helps to know the answer to Q3.
Update:
The basic idea's this: instead of matching a window around every pixel in imageB with every pixel in imageA and checking the correlation, let's identify points of interest (or features) in both images which will be trackable. So it looks like corners are really trackable since the area around it is kinda similar (not going into details) - hence, let's find some really strong corners in both images and search for corners which look most similar.
This reduces the problem of searching every pixel in B with A to searching for, say, 500 corners in B with a 1000 corners in A (or something like that) - much faster.
And the awesome thing is you have several such corner detectors at your disposal in OpenCV. If you don't feel using emguCV (C# varriant), then use the FAST detector to find matching corners and thus locate multiple features between your images. Once you have that, you can find the location of the top-left corner of the image.
If image B is an exact subset of image A (meaning, the pixel values are exactly the same), this is not an image processing problem, it's just string matching in 2D. In 99% of the cases, taking a line form the middle of B and matching it against each line of A will do what you want, and super fast &mdhas; I guess C# has a function for that. After you get your matches (normally, a few of them), just check the whole of B against the appropriate part of A.
The only problem I can see with this is that in some cases you can get too many matches. E.g. if A is your desktop, B is an icon, and you are unlucky enough to pick a line in B consisting of background only. This problem is easy to solve (you have to choose lines from B a bit more carefully), but this depends on the specifics of your problem.
Finding sub images in an imageFind an image in an ImageCheck if an image exists within another image
I am using webcamera in C# (using AForge). I also have some default background. I need to extract the difference between current image and background and create a new image which contains only the objects which are not present on the default background. For example, if I move my hand in front of webcamera, I need to output only that hand (with the rest of backgound white). If I just compare pixel by pixel it gets ugly, since there is a lot of noise. I have tried using threshold value for difference, but the result is still very bad. I think that maybe there is some filter or a known algorithm how to do that? Any help would be very much appreciated.
You can always try to compare the grayscale images of the two. Assuming that your webcam is stationary (because if not, then you would have to do much more adjusting to pixel shifts), then you can convert the images to grayscale, and have a threshold by which you think the images differ:
int threshold = 30;
PixAvg1[i,j] = (Pix1.R + Pix1.G + Pix1.B)/3
PixAvg2[i,j] = (Pix2.R + Pix2.G + Pix2.B)/3
if (Math.Abs(PixAvg1[i,j] - PixAvg2[i,j+1])>threshold)
difPixel == true;
The threshold is how much tolerance between the pixels you want to get. That value can come from the difference in brightness of the images.
With this you won't get the crispiest results, because some pixels you cover will match, however, you can then run an extra scan (if you want), and doing some kind of an area fill.
I am looking for an EASY way to check if an image is a scaled version of another image. It does not have to be very fast, it just should be "fairly" accurate. And written in .NET. And for free.
I know, wishful thinking :-)
I am pretty sure, even without having tried it, that converting the bigger image to the smaller scale and comparing checksums is not working (especially if the smaller version was done with another software then .NET).
The next approach would be to scale down and compare pixels. But first of all, it seems like a really bad idea running a loop over all pixels with a bool comparison results, I am sure there will be some pixels off by a bit or so...
Any library coming to mind? Way back in the university we had some MPEG7 classes, so I am thinking about using a combination of "statistics" like tone distribution, brightness, etc..
Any ideas or links for that topic?
Thanks,
Chris
I think this is going to be your best solution. First check the aspect ratio. Then scale the images to the smaller of the 2 if they're not the same size. Finally, do a hash comparison of the 2 images. This is a lot faster than doing a pixel compare. I found the hash compare method in a post from someone else and just adapted the answer here to fit. I was trying to think of the best way to do this myself for a project where I'm going to have to compare over 5200 images. After I read a few of the posts here I realized I already had everything I needed for it and figured I'd share.
public class CompareImages2
{
public enum CompareResult
{
ciCompareOk,
ciPixelMismatch,
ciAspectMismatch
};
public static CompareResult Compare(Bitmap bmp1, Bitmap bmp2)
{
CompareResult cr = CompareResult.ciCompareOk;
//Test to see if we have the same size of image
if (bmp1.Size.Height / bmp1.Size.Width == bmp2.Size.Height / bmp2.Size.Width)
{
if (bmp1.Size != bmp2.Size)
{
if (bmp1.Size.Height > bmp2.Size.Height)
{
bmp1 = (new Bitmap(bmp1, bmp2.Size));
}
else if (bmp1.Size.Height < bmp2.Size.Height)
{
bmp2 = (new Bitmap(bmp2, bmp1.Size));
}
}
//Convert each image to a byte array
System.Drawing.ImageConverter ic = new System.Drawing.ImageConverter();
byte[] btImage1 = new byte[1];
btImage1 = (byte[])ic.ConvertTo(bmp1, btImage1.GetType());
byte[] btImage2 = new byte[1];
btImage2 = (byte[])ic.ConvertTo(bmp2, btImage2.GetType());
//Compute a hash for each image
SHA256Managed shaM = new SHA256Managed();
byte[] hash1 = shaM.ComputeHash(btImage1);
byte[] hash2 = shaM.ComputeHash(btImage2);
//Compare the hash values
for (int i = 0; i < hash1.Length && i < hash2.Length && cr == CompareResult.ciCompareOk; i++)
{
if (hash1[i] != hash2[i])
cr = CompareResult.ciPixelMismatch;
}
}
else cr = CompareResult.ciAspectMismatch;
return cr;
}
}
One idea to achieve this:
If the image is 10x10, and your original is 40x40
Loop each pixel in the 10x10, then retrieve the 4 pixels representative of that looped pixel.
So for each pixel in the smaller image, find the corresponding scaled amount of pixels in the larger image.
You can then take the average colour of the 4 pixels, and compare with the pixel in the smaller image. You can specify error bounds, IE -10% or +10% bounds are considered a match, others are considered a failure.
Build up a count of matches and failures and use the bounds to determine if it is considered a match or not.
I think this might perform better than scaling the image to the same size and doing a 1pixel:1pixel comparison as I'm not sure how resizing algorithms necesserially work and you might lose some detail which will give less accurate results. Or if there might be different ways and methods of resizing images. But, again I don't know how the resize might work depends on how you go about doing it.
Just scale the larger image back to the size of the smaller one, then compare each pixel by taking the absolute value of the difference in each of the red, green and blue components.
You can then set a threshold for deciding how close you need to be to count it as a match, e.g. if 95%+ of the pixels are within 5% of the colour value, you have a match.
The fuzzy match is necessary because you may have scaling artefacts / anti-aliasing effects.
You'll have to loop over the pixels at some point or another.
Something that is easy to implement yet quite powerful is to calculate the difference between individual color components (RGB) for each pixel, find the average, and see if it crosses a certain threshold. It's certainly not the best method, but for a quick check it should do.
I'd have said roughly what Tom Gullen except I'd just scale down the bigger image to the smaller before comparing (otherwise you're just going to have hard maths if you are comparing a 25x25 with a 30x30 or something).
The other thing I might consider depending on image sizes is to scale them both down to a smaller image. ie if you have one that is 4000x4000 and another that is 3000x3000 then you can scale them both down to 200x200 and compare them at that size.
As others have said you would then need to do a check with a threshold (preferably on colour components) and decide what tolerances work best. I'd suggest this is probably best done by trial and error.
The easiest way is just to scale the biggest image to the smaller images size and compare color difference. Since you don't know if the scaling is cubic or linear (or something else) you have to accept a small difference.
Don't forget to take the absolute value of each pixel difference. ;)
Having absolutely no authority or experience in this area I'm going to make a stab at helping you.
I'd start with the aspect ratio matching by some tolerance, unless you're comparing cropped sections of images, which will makes things a bit harder.
I'd then scan the pixels for regions of similarity, no exactness, again a tolerance level is needed. Then when an area is similar, run along in a straight line comparing one to the other, and find another similarly coloured area. Black & white's gonna be harder.
If you get a hit, you'll have two areas in a line with patches of likeness. With two points you have a reference of length between them and so now you can see what the scaling might be. You could also scale the images first, but this doesn't account for cropped sections where aspects don't match.
Now choose a random point in the source image and get the colour info. Then using the scale factor, find that same random point on the other image and see if the colour checks out. Do it a few times with random points. If many turn up similar it's likely a copy.
You might then want to mark it for further, more CPU intensive, inspection. Either a pixel by pixel comparison or something else.
I know Microsoft (Photosynth) use filters like "outline" (the sort of stuff in Photoshop) to remove the image colours and leave just squrly lines which leave just the 'components' of the picture for matching (they match boundaries and overlap).
For speed, I'd break the problem down into chunks and really think about how humans decide two photos are similar. For non-speed, exhaustively comparing colour will probably get you there.
The process in short:
If you hole punched a sheet of paper randomly 4 times, then put it over two photos, just by seeing the colours coming through you could tell if they were likely a copy and need further inspection.