views:

193

answers:

5

Hello everyone,

I need to get the coordinates of a small image location residing in a big image (let say I need to search for a specific tree inside a forest photograph. If the sub-image is found then the result would be something like: x=120 y=354 by example).

Is there a fast algorithm that I could use ?

I'm using Delphi (can also use Java if needed)

Thanks in advance

+3  A: 

Edit: A few things about the theory:

In a nutshell, there are two "spaces" to apply filters on an image: in color spare or in frequency space. If you decided the space(freq here, there are two sorts of filters: applied as convolution and correlation(here). To keep it simple, we assume that appling correlation simple means "we multiplicate two things". With using the correlation in frequency space of an image you can measure how similar images are. Two images are similar, if the grayscale gradients are. This is measured by the covariance. (Maybe someone can help me with inserting formulars here.) The crosscorrelationcoefficent is the normalised covariance (insert formular here:( ) If you put this into a algorithm for searching affinities between a "model" and a "reference image" (model is a small section that you search within the ref. img.), you get the matlab code, which I commented too. The formular that the code uses is this one: FT([f°g] (m,n))=F(u,v)*G°(u,v). Where F is the fft and G° is the complex conjugated of G (G is the fft of the model)

Please define fast. :) The solution I have in mind will need the fft, which is fast, but maybe not as fast as you want. It searches for the small "I_ausschnitt" image inside the I image and gives the position with the highes "possibility".

In matlab, this one will work. I hope you can put it into delphi. :)

I = im2double(imread('Textiltextur.tif')); // This is our reference image
I_model = imcrop( I, [49 36 42 28] ); // Our model - what we want so search in I

[X Y] = size( I ); // Get the size of the reference image. 
f = fft2(I); // Perform the fast fourier transform->put the image into frequency space. 
f_model = fft2(I_model ,X,Y); // Perform the fft of the model but do this in the size of the original image. matlab will center I_model and set other pixel to zero
w = conj(model ); // Complex conjugated
g = real( ifft2(w.*f)); // .* will perform a komponent wise multiplicaion e.g. [0][0]*[0][0], [0][1]*[0][1] and not a matrix mul. 
gs =im2uint8(mat2gray(g)); // Convert the resulting correlation into an grayscale image with larger values->higher correlation

// Rest of the code is for displaying only
figure(1);
imshow(gs);
colormap hsv

figure;
[ XX YY] = meshgrid(1:Y,1:X );
colormap hsv 
surfc(XX,YY,double(gs)), title('3D Korrelation') 
min_corr = min(min(gs))
max_corr = max(max(gs))
%axis([1 X 1 Y min_corr max_corr])
colorbar

Edit: This will only work for grayscale images.

InsertNickHere
Now, now, that's just a tease...
pst
I've looked at the boyer-moore algorithm, it looks that's the one for the job, but what complicates the problem is that I need to search in 2D instead of linear.
Blizzy
No, you do not need the Boyer-Moore algorithm.
kigurai
I think you should comment what your code is doing. Not everyone is familiar with the connection between convolution, fourier transforms and correlation, or why you might want to use them. :)
kigurai
@kigurai Your right, i'm sorry. I will add Comments as soon as I can.
InsertNickHere
+3  A: 

One possibility is a Boyer-Moore string search: http://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm

You'll have to adapt it to your image search problem, of course. Supposing the large image has N pixels and the small one M pixels, you'd be looking at an average case performance of N/M, which is rather good.

Mathiasdm
I've looked at the boyer-moore algorithm, it looks that's the one for the job, but what complicates the problem is that I need to search in 2D instead of linear.
Blizzy
One easy thing you could do is walk through the image row by row (so considering the image as one row).As the substring in the Boyer-Moore algorithm, you could use the first row of the subimage. It'll be slower than being able to use the entire subimage, but it should be simple to implement.
Mathiasdm
Unless the images are both uncompressed, unmodified images, this will very likely fail (because it needs to find identical pixel values). If the images the OP needs to work with are photographs (most likely JPGs) than this is guaranteed to fail: JPEG compression works at block level, not at row or pixel level. Opening up a jpeg, cropping a peace out of it and saving it to a new jpeg file will generate slightly different pixel values.
Cosmin Prund
No, no, no, no, no. This will only work under very, very special circumstances, as Cosmin Prund noticed.This kind of problem is common in computer vision and there are a number of algorithms that will do the job.No one with any CV or image processing experience would upvote this.
kigurai
+1  A: 

If you're searching for an exact match (i.e. not a single pixel is different between the pattern you're looking for and the area in the image you want to find), you can actually use the Boyer Moore algorithm. It should be quite straight-forward to adapt it for looking for a 2D pattern.

Let's say the pattern you look for is 20x20 pixels big. You build a table mapping greyvalues (or colors) to positions in the pattern image. Now can go through the search image in large strides, starting at pixel 19/19: If this pixel contains a greyvalue that's not contained in the pattern, you can skip this position and all the positions in a 20x20 area around it. So the next pixel you would check would be at 39/19 in the search image. If it contains a pixel that appeard e.g. in 3 positions in the pattern image, you can test these three positions relative to your current position in the search image (39/19).

Note that this algorithm makes two assumptions:

  • you can only find exact matches. This is practically impossible for real-world images, unless the pattern image was extracted directly from the search image. It's even unlikely to work if source and pattern images are e.g. scanned from the same photograph with the same scanner. It won't work if the pattern or source image were compressed using a lossy compression (like jpeg) after the pattern was extracted.
  • The speedup depends on the number of greyvalues used. If you're looking for a binary pattern in a binary image, this algorithm won't run in O(n/m) time.
nikie
Yes, the sub-image will be an exact match. I'll try to implement your algorithm. Thanks for your answer.
Blizzy
As noted ni other answers: The Boyer-Moore algorithm is not a good choice in this context.
kigurai
@kigurai: You seem to know more about the context than I do. Could you post some sample images maybe?
nikie
A: 

I would take a practical approach to this problem for 2D position matching: They are probably going to be bitmaps...

Scan each line in the larger bitmap from 0 to Larger.height - Smaller.Height and from 0 to Larger.Width - Smaller.Width to find Smaller.TopLeft matching Pixels. When found:

IF Smaller.TopRight and smaller.bottomLeft and smaller.bottomRight are all equal to the corresponding pixels in the Larger bitmap (all the corners match) then initiate a full compare of that section.

Make sure that all comparisons fail early (do not continue comparing after any mismatch).

On average you will only need to scan less that 50% of the larger bitmap and will not start many full comparisons that fail.

Despatcher
A: 

There are a number of different techniques to find a sub image in an image.

The most straightforward is to use 2D correlation of your small image on the larger image. This will be quite slow but easy to implement. It also only works well if the sub image is aligned with the original (no rotation) and of the same scale.

If that is not the case (you have rotation and/or scale variations) then you need something more advanced. My choice would be to use a feature detection algorithm such as SIFT or SURF.

And just to reiterate what I have put in most of the previous answers: Using algorithms that are designed for 1D strings (Boyer-Moore) for image processing is just wrong. If you do you will most likely end up spending hours implementing and adapting something that does not work in the current context while there are other better algorithms that you could use.

kigurai
It seems from the comments that @Blizzy means _exact_ matches, so it is really a pattern matching problem, not pattern recognition one. Quite a rarity in vision, indeed.
overrider
Given the image compression used I would say that it is a high risk that the data is not exactly the same. Unless 100% sure that it won't matter I would never assume pixel perfect matching.Also, testing all possible positions of a blob in the image could be slower than a feature extraction method.
kigurai
Well, a pattern matching algorithm should be faster as long as it is appropriate for the task. It is linear in number of pixels (if the pattern has a constant size). In practice, we need to do more than one comparison per pixel quite seldom (unless the pattern is filled by the texture popular in the image). If you run feature extraction, you need to detect corners first, which is likely not simpler than pattern matching. Then, feature extraction and feature matching will take even more time. So I don't think it is the reason to use it, but...
overrider
It is interesting question whether feature extraction is faster than the cross-correlation method. X-corr allows a certain difference (e.g. caused by compression), but does not allow rotation, scaling or simple warping, only translation (right?). Intuitively, since the search space is much smaller, it should be faster, but who knows. It probably depends on the FFT implementation.
overrider