Поиск шаблона на скриншоте

Недавно я начал писать бота для игры World of Warcraft(3.3.5) и для этого мне пришлось постигнуть cv2 но я его так и не постиг, ниже код:

import cv2
import numpy as np
import os
     
screenshot = cv2.imread('scren.png')
     
template_folder = 'tem_1'
templates = [cv2.imread(os.path.join(template_folder, f))
                for f in os.listdir(template_folder) if f.endswith('.png')]
        
threshold = 0.8   
coordinates = []
        
def are_points_close(pt1, pt2, threshold_distance=40):
    return np.linalg.norm(np.array(pt1) - np.array(pt2)) < threshold_distance
        
for template in templates:
    result = cv2.matchTemplate(
        screenshot, template, cv2.TM_CCOEFF_NORMED)
    loc = np.where(result >= threshold)
    
    # Отметьте найденные шаблоны
    for pt in zip(*loc[::-1]):  # Переворот координат
        cv2.rectangle(
            screenshot, pt, (pt[0] + template.shape[1], pt[1] + template.shape[0]), (0, 255, 255), 2)
        coordinates.append((pt))
       
print(coordinates)
      
cv2.imwrite('output.png', screenshot)     
cv2.imshow('Detected Templates', screenshot) 
cv2.waitKey(0)  
cv2.destroyAllWindows()

Который обводит шаблон на скрине, и выявляет его координаты для дальнейшей итерации, но код возвращает мне:

np.int64(575)), (np.int64(1427), np.int64(575)), (np.int64(1428), np.int64(575)), (np.int64(1427), np.int64(576)), (np.int64(1654), np.int64(689)), (np.int64(1655), np.int64(689)), (np.int64(1656), np.int64(689)), (np.int64(1655), np.int64(690)), (np.int64(1655), np.int64(404....

Вроде всё норм, но суть в том что на скрине вещи всего 4, а кординат много, и они отличаются 1-3 значениями, бот находит вещи, и выделяет, но как то слишком много у него этого получается.

Вот шаблоны и скрины: введите сюда описание изображения введите сюда описание изображения введите сюда описание изображения введите сюда описание изображения

введите сюда описание изображения

Первые три это шаблоны, потом скрин, и что находит бот.


Ответы (1 шт):

Автор решения: Alex Alex

Дело в том, что loc у вас содержит не максимум функции корреляции, а некоторую область около него (чем меньше порог, тем больше эта область).

Вариант первый: как-то объединять координаты близких точек в кластеры.

Вариант второй: просто найти центроиды связных областей:

import cv2
import numpy as np
import os
     
screenshot = cv2.imread('screen.png')
     
template_folder = 'tem_1'
templates = [cv2.imread(os.path.join(template_folder, f))
                for f in os.listdir(template_folder) if f.endswith('.png')]
        
threshold = 0.65   
coordinates = []

for template in templates:
    result = cv2.matchTemplate(
        screenshot, template, cv2.TM_CCOEFF_NORMED)
    max_bw=np.where(result>=threshold, 255, 0, ).astype('uint8')
    _,_,_,centroids=cv2.connectedComponentsWithStats(max_bw)
    centroids=np.int64(centroids)

    # Отметьте найденные шаблоны
    for pt in centroids[1:,:]:  
        cv2.rectangle(
            screenshot, pt, (pt[0] + template.shape[1], pt[1] + template.shape[0]), (0, 255, 255), 2)
        coordinates.append((pt))
       
print(coordinates)
      
cv2.imwrite('output.png', screenshot)     
cv2.imshow('Detected Templates', screenshot) 
cv2.waitKey(0)  
cv2.destroyAllWindows()

Результат:

[array([1290,  519], dtype=int64), array([1497,  623], dtype=int64), array([1497,  365], dtype=int64)]

введите сюда описание изображения

→ Ссылка