pythonopencvimage-processingcomputer-visiontemplate-matching

Template matching with multiple objects in OpenCV Python


I'm trying to find multiple templates in an image using opencv python, according to this link.

But the problem is that multiple points returned for a single object with a slightly difference in position. Something like this:

enter image description here

I dont want to use cv2.minMaxLoc() because there is multiple templates in image. I wrote a function that delete the close positions, but I want to know is there any straightforward solution for this problem? thanks.


Solution

  • One way to find multiple matches is to write over the found matches and run the match again. Edit: A better way to find multiple matches is to write over the results. In the first example we fill the matched part of results with zeroes (use ones for SQDIFF or CCORR_NORMED) , and then look for the next match in a loop.

    import cv2
    import numpy as np
    import time
    
    image = cv2.imread('smiley.png', cv2.IMREAD_COLOR )
    template = cv2.imread('template.png', cv2.IMREAD_COLOR)
    
    h, w = template.shape[:2]
    
    method = cv2.TM_CCOEFF_NORMED
    
    threshold = 0.90
    
    start_time = time.time()
    
    res = cv2.matchTemplate(image, template, method)
    
    # fake out max_val for first run through loop
    max_val = 1
    while max_val > threshold:
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
    
        if max_val > threshold:
            res[max_loc[1]-h//2:max_loc[1]+h//2+1, max_loc[0]-w//2:max_loc[0]+w//2+1] = 0   
            image = cv2.rectangle(image,(max_loc[0],max_loc[1]), (max_loc[0]+w+1, max_loc[1]+h+1), (0,255,0) )
    
    cv2.imwrite('output.png', image)
    

    input image:

    enter image description here

    use the eyes as template images (since there is more than one eye!)

    enter image description here

    output:

    enter image description here

    And here is the original way I did it by writing over the image. This way is way is much slower because we do n+1 matchTemplate operations for n matches. By one measurement, this technique is 1000 times slower.

    import cv2
    import numpy as np
    
    image = cv2.imread('smiley.png', cv2.IMREAD_COLOR )
    template = cv2.imread('template.png', cv2.IMREAD_COLOR)
    
    h, w = template.shape[:2]
    
    method = cv2.TM_CCOEFF_NORMED
    
    threshold = 0.95
    
    # fake out max_val for first run through loop
    max_val = 1
    while max_val > threshold:
        res = cv2.matchTemplate(image, template, method)
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
    
        # using top ranked score, fill in that area with green
        image[max_loc[1]:max_loc[1]+h+1:, max_loc[0]:max_loc[0]+w+1, 0] = 0    # blue channel
        image[max_loc[1]:max_loc[1]+h+1:, max_loc[0]:max_loc[0]+w+1, 1] = 255  # green channel
        image[max_loc[1]:max_loc[1]+h+1:, max_loc[0]:max_loc[0]+w+1, 2] = 0    # red channel
    
    
    cv2.imwrite('output.png', image)
    

    output image:

    enter image description here