How to count the number of objects detected with T

2019-04-16 04:01发布

问题:

I was reading the docs about template matching with opencv and python and in the last part about template matching with multiple objects, the code detect the 19 coins on the mario image but, is it possible to count the number of objects detected with some function on python like len() or any opencv method?

Here is the code showed on the tutorial: http://docs.opencv.org/3.1.0/d4/dc6/tutorial_py_template_matching.html

Template Matching Code:

import cv2
import numpy as np
from matplotlib import pyplot as plt

img_rgb = cv2.imread('mario.png')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('mario_coin.png',0)
w, h = template.shape[::-1]

res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where( res >= threshold)
for pt in zip(*loc[::-1]):
    cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)

cv2.imwrite('res.png',img_rgb)

And the result is: Mario Bros & Coins

So, is there any way to count the coins detected on the image and print the number on the terminal? Something like:

The Template Matching code showed before...

print "Function that detect number of coins with template matching"
>>> 19

回答1:

I found a suitable solution (for my application) in counting unique matches as Ulrich suggested. It's not ideal, but playing with the "sensitivity" normally yields results within +/- 2% for my application.

import cv2
import numpy as np
from matplotlib import pyplot as plt

img_rgb = cv2.imread('mario.png')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('mario_coin.png',0)
w, h = template.shape[::-1]

res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where( res >= threshold)

f = set()

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

    sensitivity = 100
    f.add((round(pt[0]/sensitivity), round(pt[1]/sensitivity)))

cv2.imwrite('res.png',img_rgb)

found_count = len(f)


回答2:

I used a list to store the very first (x,y) of many same object detections. Then for every (x,y) in the found detections(there must be many detections on the one same object), I calculate the distance between the new (x,y) and every points in the list. If the distance is large enough, it must be the first found of a new detection. Then I put the new (x,y)to the list. It is stupid but really works.

The purpose is to remove the points nearby the (x,y) of the first detection of an object and keep only one point of that 'group', then iterate all the points in loc to locate more 'groups' and find one and the only one point in every group.

import cv2
import numpy as np
import matplotlib.pyplot as plt
import math

def notInList(newObject):
    for detectedObject in detectedObjects:
        if math.hypot(newObject[0]-detectedObject[0],newObject[1]-detectedObject[1]) < thresholdDist:
        return False
    return True

img_rgb = cv2.imread("7.jpg")
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread("face.jpg",0)
w, h = template.shape[::-1]
res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
threshold = 0.85
loc = np.where( res >= threshold)

detectedObjects=[]
thresholdDist=30

for pt in zip(*loc[::-1]):
    if len(detectedObjects) == 0 or notInList(pt):
        detectedObjects.append(pt)
        cellImage=img_rgb[pt[1]:pt[1]+h, pt[0]:pt[0]+w]
        cv2.imwrite("results/"+str(pt[1])+"_"+str(pt[0])+".jpg",cellImage, 
        [int(cv2.IMWRITE_JPEG_QUALITY), 50])    


回答3:

import time import cv2 import numpy as np from PIL import ImageGrab

while True:

count = 0
stop = 0

img = ImageGrab.grab()
img_np = np.array(img)

gray = cv2.cvtColor(img_np, cv2.COLOR_BGR2GRAY)

frame = cv2.cvtColor(img_np, cv2.COLOR_BGR2RGB)

Template = cv2.imread('image.png' ,0)
w, h = Template.shape[::-1]

res = cv2.matchTemplate(gray, Template, cv2.TM_CCOEFF_NORMED)
threshold = 0.90
loc = np.where(res >= threshold)

font = cv2.FONT_HERSHEY_SIMPLEX

for pt in zip(*loc[::-1]):

    cv2.rectangle(frame, pt, (pt[0] + w, pt[1] + h), (0,0,255) ,2)

    count = count + 1

    print(count)

    stop = 1

cv2.imshow('frame',frame)

if (stop == 1):

    break