I am trying to match a pattern with a binary image (black and white only) by moving the pattern along the image. And return the minimum distance between the template and the image with the corresponding position at which this minimum distance actually occurred. For instance:
IMG:
0 1 0 0 0 1 0 1 1
template:
0 1 1 1
This pattern matches the best image in position (1,1), and then it will be 0. Now everything is not so complicated, and I already have code that does the trick.
def match_template(img, template): mindist = float('inf') idx = (-1,-1) for y in xrange(img.shape[1]-template.shape[1]+1): for x in xrange(img.shape[0]-template.shape[0]+1): #calculate Euclidean distance dist = np.sqrt(np.sum(np.square(template - img[x:x+template.shape[0],y:y+template.shape[1]]))) if dist < mindist: mindist = dist idx = (x,y) return [mindist, idx]
But for images of the required size (an image between 500 x 200 pixels and a template of 250 x 100) it takes about 4.5 seconds, which is too slow. And I know that the same thing can be done much faster using matrix multiplications (in Matlab, I believe that this can be done with im2col and repmat). Can someone explain me how to do this in python / numpy?
by the way. I know that there is an opencv matchTemplate function that does exactly what I need, but since I may need to change the code a bit later, I would prefer a solution that I fully understand and can change.
Thanks!
edit: If anyone can explain to me how opencv does this in less than 0.2 seconds, that would also be great. I looked briefly at the source code, but these things somehow always look quite complicated for me.
edit2: Cython code
import numpy as np cimport numpy as np DTYPE = np.int ctypedef np.int_t DTYPE_t def match_template(np.ndarray img, np.ndarray template): cdef float mindist = float('inf') cdef int x_coord = -1 cdef int y_coord = -1 cdef float dist cdef unsigned int x, y cdef int img_width = img.shape[0] cdef int img_height = img.shape[1] cdef int template_width = template.shape[0] cdef int template_height = template.shape[1] cdef int range_x = img_width-template_width+1 cdef int range_y = img_height-template_height+1 for y from 0 <= y < range_y: for x from 0 <= x < range_x: dist = np.sqrt(np.sum(np.square(template - img[ x:<unsigned int>(x+template_width), y:<unsigned int>(y+template_height) ]))) #calculate euclidean distance if dist < mindist: mindist = dist x_coord = x y_coord = y return [mindist, (x_coord,y_coord)] img = np.asarray(img, dtype=DTYPE) template = np.asarray(template, dtype=DTYPE) match_template(img, template)