Dawid
Dawid

Reputation: 1555

Search for all templates using scikit-image

I am trying to follow the tutorial from scikit-image regarding Template Matching (check it here). Themplate matching

Using just this example, I would like to find all matching coins (maxima) in the image, not only this one which gave the highest score. I was thinking about using:

maxima = argrelextrema(result, np.greater)

but the problem is that it finds also very small local maxima, which are just a noise. Is there any way to screen numpy array and find the strongest maxima? Thanks!

Upvotes: 2

Views: 4246

Answers (2)

draco_alpine
draco_alpine

Reputation: 785

To find all the coins the documentation suggests "...you should use a proper peak-finding function." The easiest of these is probably peak_local_max (as suggested in the comments) which is also from skimage, and has a manual page here. Using some reasonable numbers in the *args gets the peaks out of the response image.

The second comment about the peaks being displaced is also discussed in the documentation

"Note that the peaks in the output of match_template correspond to the origin (i.e. top-left corner) of the template."

One can manually correct for this (by translating the peaks by the side lengths of the template), or you can set the pad_input bool to True (source), which as a by-product means that the peaks in the response function line up with the center of the template at the point of maximal overlap.

Combining these two bits into a script we get something like:

import numpy as np
import matplotlib.pyplot as plt

from skimage import data
from skimage.feature import match_template
from skimage.feature import peak_local_max # new import!

image = data.coins()
coin = image[170:220, 75:130]

result = match_template(image, coin,pad_input=True) #added the pad_input bool

peaks = peak_local_max(result,min_distance=10,threshold_rel=0.5) # find our peaks

# produce a plot equivalent to the one in the docs
plt.imshow(result)
# highlight matched regions (plural)
plt.plot(peaks[:,1], peaks[:,0], 'o', markeredgecolor='r', markerfacecolor='none', markersize=10)

Outputted image of the code snippet above

Upvotes: 6

Dawid
Dawid

Reputation: 1555

I have been digging and found some solution but unfortunately I am not sure if I know what exactly is done in the script. I have slightly modified script found here:

neighborhood_size = 20   #how many pixels
threshold = 0.01  #threshold of maxima?

data_max = filters.maximum_filter(result, neighborhood_size)
maxima = (result == data_max)
data_min = filters.minimum_filter(result, neighborhood_size)
diff = ((data_max - data_min) > threshold)
maxima[diff == 0] = 0

x_image,y_image = [], []
temp_size = coin.shape[0]

labeled, num_objects = ndimage.label(maxima)
slices = ndimage.find_objects(labeled)
x, y = [], []
for dy,dx in slices:
    x_center = (dx.start + dx.stop - 1)/2
    x.append(x_center)
    y_center = (dy.start + dy.stop - 1)/2
    y.append(y_center)

fig, (raw,found) = plt.subplots(1,2)
raw.imshow(image,cmap=plt.cm.gray)
raw.set_axis_off()
found.imshow(result)
found.autoscale(False)
found.set_axis_off()
plt.plot(x,y, 'ro')
plt.show()

and does this: Found all maxima

I also realized, that coordinates of found peaks are shifted in comparison to raw image. I think the difference comes from the template size. I will update when I will find out more.

EDIT: with slight code modification I was able also to find places on the input image:

x_image_center = (dx.start + dx.stop - 1 + temp_size) / 2
x_image.append(x_image_center)
y_image_center = (dy.start + dy.stop - 1 + temp_size) / 2
y_image.append(y_image_center)

Find all patterns in the image with python

Upvotes: 0

Related Questions