Search code examples
pythonopencvimage-processingcropcontour

Saving Template Matches Individually OpenCV Python


Using cv2.matchTemplate I am using a reference image (stampRef.jpg) and finding multiple matches in a larger image(stamps). I'd like to save each of these found matches as their own image. Rotation is important to me but not scale. I am concerned that it may save the same image multiple times because of overlapping matches. I do not want this. I only want 1 picture for each unique match. I'm just not sure how to save them in the first place. Any help would be amazing, Thank you.

*Update, I found a way to reduce the number of overlapping found matches by using Masks, so now I need to just save these matches individually. I've updated the code.

enter image description here enter image description here enter image description here

import cv2
import numpy as np

img = cv2.imread("stamps.jpg")
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
template = cv2.imread('stampRef.jpg',0)
w, h = template.shape[::-1]
res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where( res >= threshold)

#Counts the number of found matches, which are currently overlapping
number = np.sum(res >= threshold)
print(number)

count = 0
mask = np.zeros(img.shape[:2], np.uint8)
for pt in zip(*loc[::-1]):
    if mask[pt[1] + h//2, pt[0] + w//2] != 255:
        mask[pt[1]:pt[1]+h, pt[0]:pt[0]+w] = 255
        count += 1
        cv2.rectangle(img, pt, (pt[0] + w, pt[1] + h), (0,255,0), 3)

print ("Number of found matches:", count)
small = cv2.resize(img, (0,0), fx=0.3, fy=0.3)

cv2.imshow('Matches',small)
cv2.waitKey(0) & 0xFF== ord('q')
cv2.destroyAllWindows()

Solution

  • This answer explains how to save each match as an individual image. You have already done the hard work by finding the coordinates of the match. You can use those coordinates to crop out a match and save it as a .png:

    roi = img[pt[1]:pt[1]+h, pt[0]:pt[0]+w]
    cv2.imwrite(+ str(count) + '.png', roi)
    

    This code should go inside the loop that iterates through the matches:

    count = 0
    
    mask = np.zeros(img.shape[:2], np.uint8)
    for pt in zip(*loc[::-1]):
        if mask[pt[1] + h//2, pt[0] + w//2] != 255:
            mask[pt[1]:pt[1]+h, pt[0]:pt[0]+w] = 255
            count += 1
            cv2.rectangle(img, pt, (pt[0] + w, pt[1] + h), (0,255,0), 3)
            roi = img[pt[1]:pt[1]+h, pt[0]:pt[0]+w]
            cv2.imwrite(+ str(count) + '.png', roi)
            cv2.imshow('roi', roi)
            cv2.waitKey()