opencv 如何计算模板匹配检测到的对象数量?

70gysomp  于 2023-11-22  发布在  其他
关注(0)|答案(7)|浏览(132)

我在阅读关于opencv和python模板匹配的文档,在最后一部分关于多个对象的模板匹配,代码检测马里奥图像上的19个硬币,但是,是否有可能用python上的一些函数(如len()或任何opencv方法)来计算检测到的对象数量?
下面是教程中显示的代码:http://docs.opencv.org/3.1.0/d4/dc6/tutorial_py_template_matching.html
模板匹配代码:

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)

字符串
结果是:Mario Bros & Coins
那么,有没有办法计算图像上检测到的硬币并在终端上打印数字呢?比如:

The Template Matching code showed before...

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

7jmck4yq

7jmck4yq1#

我找到了一个合适的解决方案(对于我的应用程序),按照Ulrich的建议计算唯一匹配。这并不理想,但对我的应用程序来说,使用“灵敏度”通常会产生+/- 2%的结果。

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)

字符串

w6lpcovy

w6lpcovy2#

我做了一个所有匹配的列表,对于每一个新的匹配,我检查是否有一个与边界框相交的列表中的任何匹配:

res = cv.matchTemplate(image,template,cv.TM_CCOEFF_NORMED)
threshold = 0.5
loc = np.where(res >= threshold)
matches = []
for pt in zip(*loc[::-1]):
    intersection = 0
    for match in matches:
        if intersected(match, (match[0] + w, match[1] + h), pt, (pt[0] + w, pt[1] + h)):
            intersection = 1
            break
    if intersection == 0:
        matches.append(pt)
        rect = cv.rectangle(image, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 2)

字符串
这是检查交叉点的代码:

def intersected(bottom_left1, top_right1, bottom_left2, top_right2):
    if top_right1[0] < bottom_left2[0] or bottom_left1[0] > top_right2[0]:
        return 0

    if top_right1[1] < bottom_left2[1] or bottom_left1[1] > top_right2[1]:
        return 0

    return 1

dm7nw8vv

dm7nw8vv3#

我也遇到过类似的问题。以下是我的解决方案:

import cv2
import numpy as np
import os
from os import listdir
from os.path import isfile, join
from matplotlib import pyplot as plt
from imutils.object_detection import non_max_suppression

def count_similar_objects(main_image_path, template_image_path, times_of_run):
    # Load the main image and the template image
    main_image = cv2.imread(main_image_path)
    template_image = cv2.imread(template_image_path)
    H, W = template_image.shape[:2]

    # Convert the images to grayscale
    main_gray = cv2.cvtColor(main_image, cv2.COLOR_BGR2GRAY)
    template_gray = cv2.cvtColor(template_image, cv2.COLOR_BGR2GRAY)

    # Perform template matching
    result = cv2.matchTemplate(main_gray, template_gray, cv2.TM_CCOEFF_NORMED)
    threshold = 0.6
    count = 0
    (y_points, x_points) = np.where(result >= threshold) 

    # Draw rectangles around the matched objects with a thicker outline
    thickness = 6  # Adjust the thickness as desired
    # initialize our list of rectangles 
    boxes = list() 
  
    # loop over the starting (x, y)-coordinates again 
    for (x, y) in zip(x_points, y_points): 
    
        # update our list of rectangles 
        boxes.append((x, y, x + W, y + H)) 
  
    # apply non-maxima suppression to the rectangles 
    # this will create a single bounding box 
    boxes = non_max_suppression(np.array(boxes)) 
  
    # loop over the final bounding boxes 
    for (x1, y1, x2, y2) in boxes: 
    
        # draw the bounding box on the image 
        cv2.rectangle(main_image, (x1, y1), (x2, y2), 
                      (0, 255, 0), thickness)
        count += 1

   
    cv2.imwrite('result'+str(times_of_run)+'.png',main_image)

    return count

字符串
我不明白它是如何工作的。我只是从GeeksforGeeks复制了这个。所以不要指望我能回答你的问题。但我会尽我所能回答它。我希望这对你有帮助。

k3bvogb1

k3bvogb14#

我使用一个列表来存储许多相同对象检测的第一个(x,y)。然后对于找到的检测中的每个(x,y)(同一个物体上必须有许多检测),我计算新的(x,y)和列表中每个点之间的距离。如果距离足够大,它必须是新检测的第一个发现。然后我把新的(x,y),y)的名单。这是愚蠢的,但真的有效。
其目的是删除第一次检测对象的(x,y)附近的点,只保留该“组”中的一个点,然后将所有点都放入loc中以定位更多的“组”,并在每个组中找到一个且唯一的一个点。

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])

字符串

gudnpqoy

gudnpqoy5#

对于任何仍然想知道的人:首先对列表“zip(*loc[::-1})”进行排序要容易得多。
因为我的脚本返回的结果是这样的:

(580, 822)
(871, 822)
(1017, 822)
(434, 823)
(726, 823)
(871, 823)
(1017, 823)
7

字符串
你会注意到,有多个重复,但不仅仅是按顺序。现在只需使用“sorted(zip(*loc[::-1]))”进行排序,就可以轻松获得距离,只需计算相邻的2个点并检查每个循环的距离。
通过在循环中添加条件并检查当前点的距离是否小于期望值,可以很好地完成工作。我从未正确学习过python,所以我不确定这是不是有效的方法..至少这对我的用例有效。你可以在下面检查它。
Source code (Github) / Test Result (Imgur)
示例代码:

img = np.array( *YOUR_SCREENSHOT_HERE* )
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    template = cv2.imread( *TARGET_IMAGE_HERE* , 0)
    w, h = template.shape[::-1]

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

    count = 0
    last_pt = [0, 0]   # Set this negative if target image is at top-left corner.

    for pt in sorted(zip(*loc[::-1])):
        if sqrt(abs(last_pt[0]-pt[0])**2 + abs(last_pt[0]-pt[0])**2) < threshold*min([h, w]):
            continue
        else:
            last_pt = pt
            print(pt)
            count = count + 1
            cv2.rectangle(img, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 2)

    cv2.imwrite('res.png', img)
    return count

35g0bw71

35g0bw716#

我就是这么做的:

loc = np.where( res >= threshhold)
print(len(loc[0])) #match occurences count

字符串
loc是2D数组。

9o685dep

9o685dep7#

导入时间导入cv2从PIL导入numpy作为np导入ImageGrab
为真时:

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

字符串

相关问题