Как заставить pg.moveTo() двигать курсор лишь к одному, ближайшему объекту, найденному yolov4, а не ко всем сразу?

Я пытаюсь сделать своеобразного бота авто-наводчика для шутера с помощью yolov4, обучил свою модель и на основе этого переноса yolov4 в питон сделал скрипт непрерывно делающий снимок экрана и сканирующий его на предмет нужных объектов(в нашем случаи игроков), затем я используя координаты из списка box, по которому рисовались прямоугольники, изменил их и направил по ним курсор.

classes, scores, boxes = model.detect(frame, Conf_threshold, NMS_threshold)
for (classid, score, box) in zip(classes, scores, boxes):
    color = COLORS[int(classid) % len(COLORS)]
    label = "%s : %f" % (class_name[classid[0]], score)
    cv.rectangle(frame, box, color, 1)

    # это
    pg.moveTo(box[0]+box[2]/2, box[1]+box[3]/3)
    

Когда был один объект, всё было замечательно, но когда я в кадр добавил второй, курсор начал каждую итерацию проходить по всем объектам, что сделало моего почти готового бота нерабочим, ибо метаясь по всем противникам сразу он банально ни по кому не попадёт, а как это решить я понятия не имею. Вот весь код:

import mss
import mss.tools
import cv2 as cv
import time
import pyautogui as pg


Conf_threshold = 0.4
NMS_threshold = 0.4
COLORS = [(0, 255, 0), (0, 0, 255), (255, 0, 0),
          (255, 255, 0), (255, 0, 255), (0, 255, 255)]

class_name = []
with open('CSv2.names', 'r') as f:
    class_name = [cname.strip() for cname in f.readlines()]

net = cv.dnn.readNet('CSv2_6000.weights', 'CSv2.cfg')
net.setPreferableBackend(cv.dnn.DNN_BACKEND_CUDA)
net.setPreferableTarget(cv.dnn.DNN_TARGET_CUDA_FP16)

model = cv.dnn_DetectionModel(net)
model.setInputParams(size=(416, 416), scale=1/255, swapRB=True)


with mss.mss() as sct:
   
    monitor = {"top": 0, "left": 0, "width": 1920, "height": 1080}
    output = "sct-{top}x{left}_{width}x{height}.png".format(**monitor)

    starting_time = time.time()
    frame_counter = 0

while True:
    cap = cv.imread('sct-0x0_1920x1080.png')

    frame = cap
    frame_counter += 1
    classes, scores, boxes = model.detect(frame, Conf_threshold, NMS_threshold)
    for (classid, score, box) in zip(classes, scores, boxes):
        color = COLORS[int(classid) % len(COLORS)]
        label = "%s : %f" % (class_name[classid[0]], score)
        cv.rectangle(frame, box, color, 1)

        
        pg.moveTo(box[0]+box[2]/2, box[1]+box[3]/3)

        cv.putText(frame, label, (box[0], box[1]-10),
                   cv.FONT_HERSHEY_COMPLEX, 0.3, color, 1)
    endingTime = time.time() - starting_time
    fps = frame_counter/endingTime

    cv.putText(frame, f'FPS: {fps}', (20, 50),
               cv.FONT_HERSHEY_COMPLEX, 0.7, (0, 255, 0), 2)
    cv.imshow('frame', frame)

    sct_img = sct.grab(monitor)

    mss.tools.to_png(sct_img.rgb, sct_img.size, output=output)
    print(output)

    key = cv.waitKey(1)
    if key == ord('q'):
        break


cap.release()
cv.destroyAllWindows()

Как это можно решить?

upd: Я совсем запутался с этим боксом: это НЕ многомерный массив, он одномерен и содержит лишь 4 координаты:

Пишу:

print (box)
print (box.shape)

Вывожу на экран три картинки и вот что он выдаёт:

sct-0x0_900x900.png
[461 258 152 298]
(4,)
[119 280 161 214]
(4,)
[132 697 169 202]
(4,)

тобеш он показывается по разу на один обьект, будто несколько разных массивов подряд открываешь... или он перезаписывается? Я совсем запутался.


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

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

Я нашёл решение! Массив одномерный и просто перезаписывался, а всё что нужно было сделать, это всего-лишь вне цикла for движение мыши прописывать, а не внутри.

for (classid, score, box) in zip(classes, scores, boxes):
    color = COLORS[int(classid) % len(COLORS)]
    label = "%s : %f" % (class_name[classid[0]], score)
    cv.rectangle(frame, box, color, 1)

    x1, x2, x3, x4 = box[0], box[2], box[1], box[3]

    cv.putText(frame, label, (box[0], box[1]-10),
        cv.FONT_HERSHEY_COMPLEX, 0.3, color, 1)


print (x1, x2, x3, x4)
pg.moveTo(x1+x2/2, x3+x4/3)

была небольшая проблема, что курсор заедало на одном месте, когда целей нету, из-за того что переменная не обновлялась и он продолжал идти в то место где в последний раз был объект, но я решил это просто обнуляя её:

print(x1, x2, x3, x4)

if x1 > 0:
    pg.moveTo(x1+x2/2, x3+x4/3)
else:
    pass

x1, x2, x3, x4 = 0, 0, 0, 0

Выводит как и задумано!:

sct-0x0_900x900.png
455 176 614 199

Курсор липнет лишь к одному изображению, и если его убрать переключается на другое!

→ Ссылка