Simple template matching with python-openCv
I am trying to detect some simple 'red patterns' in an image. Here is the algorithm I follow: 1) filter out all other colors rather than 'red' and creating a balck&white image. I used 'cvtColor' with appropriate masking then I applied 'GaussianBlur' to reduce the noise. So far everthing is fine.
2) I used function 'matchTemplate' as follows to detect the 'arrow' templete in image.
Problem: when 'arrow' template is in photo , it is detected correctly. But when it is not in photo, algorithm detect some other shapes which is mistake. Can somebody modify code, so that when arrow template is not in picture, nothing get detected. Here is my code:
template = cv2.imread(address,0) w, h = template.shape[::-1] res = cv2.matchTemplate(self.image['blured'], template, cv2.TM_CCOEFF_NORMED) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) top_left = max_loc bottom_right = (top_left + w, top_left + h) cv2.rectangle(self.image['blured'],top_left, bottom_right, 255, 2) cv2.rectangle(self.image['normal'], top_left, bottom_right, 255,2)
My template image , which I cropped exactly from main photo:
Anybody can detect my mistake? I am new in image processing. Thanks in advance.
You have to look at your max_val and put a threshold on it.
Let's say max_val is x1 when the image contains the arrow and is x2 when the image does not contain the arrow, it should be that x1 > x2. As a first tentative value you can choose threshold=(x1+x2)/2 and then if max_val > threshold then the pattern is found in the image else the pattern is not found.
The reason is that matchTemplate
slides through image , compares the overlapped patches of size w \times hagainst templ using the specified method and stores the comparison results in result.
and so your image res will always have a maximum value disregarding the presence of the arrow in the image.
Thanks a lot Alessandro Jacopson. I modified the code and solved the problem in this way. It is almost what you proposed:
template = cv2.imread(address,0) w, h = template.shape[::-1] res = cv2.matchTemplate(self.image['blured'], template,cv2.TM_CCOEFF_NORMED) threshold = 0.9 loc = np.where( res >= threshold) for pt in zip(*loc[::-1]): cv2.rectangle(self.image['blured'], pt, (pt + w, pt + h), (0,0,255), 2) cv2.rectangle(self.image['normal'], pt, (pt + w, pt + h), (0,0,255), 2)
In this way patterns are detected quite accurate. New problem: It is sensitive about direction and rotation. It doesn't detect the pattern if it is rotated.for example around 45 degree. Is there any parameter I can set, and make the algorithm to find the pattern, although it is rotated or scaled?