-1

I have tried to use the code provided in this answer to detect symbols using template matching with the FFT (via fft2)

However, the code only detects one symbol but it doesn't detect all similar symbols.

The code has been adapted from the linked post and is shown below.

template=im2bw(imread(http://www.clipartkid.com/images/543/floor-plan-symb-aT0MYg-clipart.png)); 
background=im2bw(imread(http://www.the-house-plans-guide.com/images/blueprints/draw-floor-plan-step-6.png));

bx = size(background, 2); 
by = size(background, 1);
tx = size(template, 2); % used for bbox placement
ty = size(template, 1);
pos=[];
%// Change - Compute the cross power spectrum
Ga = fft2(background);
Gb = fft2(template, by, bx);
c = real(ifft2((Ga.*conj(Gb))./abs(Ga.*conj(Gb))));

%% find peak correlation
[max_c, imax]   = max(abs(c(:)));
[ypeak, xpeak] = find(c == max(c(:))); % Added to make code work
if ~isempty(ypeak) || ~isempty(xpeak)
 pos=position;

plot(xpeak,ypeak,'x','LineWidth',1,'Color','g');
rectangle('position',position,'edgecolor','b','linewidth',1, 'LineStyle', '-  ');
end

How may I use the above code to detect multiple symbols as opposed to just one?

Community
  • 1
  • 1
Rajnikant Sharma
  • 536
  • 11
  • 27
  • 2
    You take only the maximum value in c which gives you only one point. Instead take all the points that are in some epsilon distance from the maximum. – Amitay Nachmani Aug 22 '16 at 07:37
  • how to find epsilon distance from maximum – Rajnikant Sharma Aug 22 '16 at 07:49
  • 1
    Try to divide the unique values in c to two groups (maybe use kmeans). A simper way is just taking a one STD away from the maximum. Or take the histogram of the unique values in c and try to see if you can easily find a point were the correlation values drop. – Amitay Nachmani Aug 22 '16 at 08:09
  • 1
    FYI, this user took this code from the following post: http://stackoverflow.com/questions/32664481/matlab-template-matching-using-fft/32664730#32664730. It would be nice to give credit where you took the code from so people don't have the interpretation that you wrote that code yourself. This code also doesn't run because you are missing the `find` statement that gives you where the maximum is located which are stored in `xpeak` and `ypeak` respectively. – rayryeng Aug 22 '16 at 17:23
  • I have allredy mentioned question reference in my first line , and have allready used 'find' in the code. – Rajnikant Sharma Sep 26 '16 at 11:15

1 Answers1

1

Amitay is correct in his assessment. BTW, the code that you took comes from the following post: Matlab Template Matching Using FFT.

The code is only designed to detect one match from the template you specify. If you wish to detect multiple templates, there are various methodologies you can try each with their own advantages and disadvantages:

  1. Use a global threshold and from the cross power spectrum, any values that surpass this threshold deem that there is a match.
  2. Find the largest similarity in the cross power spectrum, and anything that is some distance away from this maximum would be deemed that there is a match. Perhaps a percentage away, or one standard deviation away may work.
  3. Try to make a histogram of the unique values in the cross power spectrum and find the point where there is a clear separation between values that are clearly uncorrelated with the template and values that are correlated. I won't implement this for you here because it requires that we look at your image then find the threshold by examining the histogram so I won't do that for you. Instead you can try the first two cases and see where that goes.

You will have to loop over multiple matches should they arise, so you'll need to loop over the code that draws the rectangles in the image.


Case #1

The first case is very simple. All you have to do is modify the find statement so that instead of searching for the location with the maximum, simply find locations that exceed the threshold.

Therefore:

%% find peak correlation
thresh = 0.1; % For example
[ypeak, xpeak] = find(c >= thresh);

Case #2

This is very similar to the first case but instead of finding values that exceed the threshold, determine what the largest similarity value is (already done), and threshold anything that is above (1 - x)*max_val where x is a value between 0 and 1 and denotes the percentage you'd like away from the maximum value to be considered as match. Therefore, if you wanted at most 5% away from the maximum, x = 0.05 and so the threshold now becomes 0.95*max_val. Similarly for the standard deviation, just find what it is using the std function and ensuring that you convert it into one single vector so that you can compute the value for the entire image, then the threshold becomes max_val - std_val where std_val is the standard deviation of the similarity values.

Therefore, do something like this for the percentage comparison:

%% find peak correlation
x = 0.05; % For example
[max_c, imax] = max(abs(c(:)));
[ypeak, xpeak] = find(c >= (1-x)*max_c);

... and do this for the standard deviation comparison:

std_dev = std(abs(c(:)));
[max_c, imax] = max(abs(c(:)));
[ypeak, xpeak] = find(c >= (max_c - std_dev));

Once you finally establish this, you'll see that there are multiple matches. It's now a point of drawing all of the detected templates on top of the image. Using the post that you "borrowed" the code from, the code to draw the detected templates can be modified to draw multiple templates.

You can do that below:

%% display best matches
tx = size(template, 2);
ty = size(template, 1);
hFig = figure;
hAx  = axes;
imshow(background, 'Parent', hAx);
hold on;

for ii = 1 : numel(xpeak)
    position = [xpeak(ii), ypeak(ii), tx, ty]; % Draw match on figure
    imrect(hAx, position);
end
Community
  • 1
  • 1
rayryeng
  • 102,964
  • 22
  • 184
  • 193