简体   繁体   中英

opencv - how to do a template match without scale?

I am trying to match playing cards. I assumed since the cards are all unique a template match might be the right way to go.

I have the templates (images) in a folder, these are just the card.

Now when I try to match them with several cards and table in the picture I get 0 matches at threshold = 0.8 .

I read up and it seems to be a problem of scale. ie if I understood it correctly if the card picture(template) is not on the same scale as the one where I want to detect the card then it will not get detected.

I am not sure how to proceed from here.

Here is the code I am using.

mport pyautogui
import cv2
import numpy as np
import time
import pyscreenshot as grabimage
import os


img_de = cv2.imread('/media/xxx/cards/match2.jpg')
img_gray = cv2.cvtColor(img_de,cv2.COLOR_BGR2GRAY)

os.chdir('/media/xxx/cards/template-for-matching/')
templates = os.listdir()
# templates = ['9s.jpg']
for template in templates:
    print('checking: ' + str(template))
    t = cv2.imread(template,0)
    w,h = t.shape[::-1]
    res = cv2.matchTemplate(img_gray,t,cv2.TM_CCOEFF_NORMED)
    threshold = 0.8
    loc = np.where(res >= threshold)

    for pt in zip(*loc[::-1]):
        cv2.rectangle(img_de, pt, (pt[0]+w, pt[1]+h),(0,255,255),1)

    cv2.imshow('detected',img_de)
    cv2.waitKey(0)
    input('Wait')
    cv2.destroyAllWindows()

EDIT:

The accepted answer does the job.

I have gone with a different approach as my use case is specific and I can change the scale of where I am getting the template images and the test image

I am using the following command to make sure the scale remains the same. (Ubuntu, terminal command)

# Install wmctrl
sudo apt-get install wmctrl
# Command to resize the window
wmctrl -r string -e 0,left,up,width,height

This is from an answer: here

You should create a pyramid of your reference image, see this official opencv tutorial . Then you add an outer loop to your code that loops over all image sizes. In this pyramid you take the template with the strongest match and threshold this match.

See the code taken from this tutorial :

# loop over the images to find the template in
for imagePath in glob.glob(args["images"] + "/*.jpg"):
    # load the image, convert it to grayscale, and initialize the
    # bookkeeping variable to keep track of the matched region
    image = cv2.imread(imagePath)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    found = None

    # loop over the scales of the image
    for scale in np.linspace(0.2, 1.0, 20)[::-1]:
        # resize the image according to the scale, and keep track
        # of the ratio of the resizing
        resized = imutils.resize(gray, width = int(gray.shape[1] * scale))
        r = gray.shape[1] / float(resized.shape[1])

        # if the resized image is smaller than the template, then break
        # from the loop
        if resized.shape[0] < tH or resized.shape[1] < tW:
            break
        # detect edges in the resized, grayscale image and apply template
        # matching to find the template in the image
        edged = cv2.Canny(resized, 50, 200)
        result = cv2.matchTemplate(edged, template, cv2.TM_CCOEFF)
        (_, maxVal, _, maxLoc) = cv2.minMaxLoc(result)

        # check to see if the iteration should be visualized
        if args.get("visualize", False):
            # draw a bounding box around the detected region
            clone = np.dstack([edged, edged, edged])
            cv2.rectangle(clone, (maxLoc[0], maxLoc[1]),
                (maxLoc[0] + tW, maxLoc[1] + tH), (0, 0, 255), 2)
            cv2.imshow("Visualize", clone)
            cv2.waitKey(0)

        # if we have found a new maximum correlation value, then update
        # the bookkeeping variable
        if found is None or maxVal > found[0]:
            found = (maxVal, maxLoc, r)

    # unpack the bookkeeping variable and compute the (x, y) coordinates
    # of the bounding box based on the resized ratio
    (_, maxLoc, r) = found
    (startX, startY) = (int(maxLoc[0] * r), int(maxLoc[1] * r))
    (endX, endY) = (int((maxLoc[0] + tW) * r), int((maxLoc[1] + tH) * r))

    # draw a bounding box around the detected result and display the image
    cv2.rectangle(image, (startX, startY), (endX, endY), (0, 0, 255), 2)
    cv2.imshow("Image", image)
    cv2.waitKey(0)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM