According to the answer by Neeraj Komuravalli to this question, matchTemplate
supports the mask
argument as a way of excluding certain pixels in the template from being considered in the matching (docs).
To generate a mask based on the red pixels, a simple solution is to use a Boolean expression to select those pixels that are 0
in blue and green but 255
in red:
mask = (template[:,:,0]==0) & (template[:,:,1]==0) & (template[:,:,2]==255)
mask = ~mask
mask = mask.astype(np.uint8)
Note that the conversion to uint8
is necessary since the mask must be of the same datatype as the template.
Edit: ~mask
inverts the mask (0
becomes 1
and vice versa), which is necessary since 0
indicates the pixels to be masked, at least when using the method cv2.TM_CCORR_NORMED
.
Whilst this addresses your question in principle, it will not yield a working solution in this case.
This is because of the Canny edge filter that is being applied to the images. Since there is no way of masking the red pixels in the template when applying Canny, the boundaries of the red pixel regions will affect the result of the edge detection and thus change the template to look quite different from the original.
In this example the matching fails as a consequence, returning a position that is completely wrong.
Removing the Canny steps solves this problem... but it also makes the approach a little less robust/precise. In this case, the matching actually seems to end up a few pixels off from the 100% correct match. Unfortunately, I can't think of any means of improving this.
Here's the complete code that works for me (with the aforementioned caveat in terms of precision):
import cv2
import numpy as np
template = cv2.imread("masked_template.png")
mask = (template[:,:,0]==0) & (template[:,:,1]==0) & (template[:,:,2]==255)
mask = mask.astype(np.uint8)
template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
#template = cv2.Canny(template, 50, 200)
edged = cv2.imread("edged.png")
edged = cv2.cvtColor(edged, cv2.COLOR_BGR2GRAY)
#edged = cv2.Canny(edged, 50, 200)
result = cv2.matchTemplate(edged, template, cv2.TM_CCORR_NORMED, mask=mask)
(_, maxVal, _, maxLoc) = cv2.minMaxLoc(result)