【YoloV5】如何利用相对位置移动移动到某个位置?

说明:

  • 最外面1920*1080的大框是屏幕的长宽
  • 第二个框是YOLO要在屏幕截取的位置
  • 第三个人的框是对目标进行的位置标记(也就是model将目标标记了出来)

The main idea is as shown above:

The core code is as follows:

import math
from ctypes import *
import cv2
import numpy as np
import numpy.ctypeslib as npct
import pyautogui


SCREEN_W = 1920  # 屏幕长 : 3840
SCREEN_H = 1080  # 屏幕高 :2160
SCREEN_CX = SCREEN_W // 2  # 屏幕中心x
SCREEN_CY = SCREEN_H // 2  # 屏幕中心y
SCREEN_C = [SCREEN_CX, SCREEN_CY]  # 屏幕中心坐标
SCREENSHOT_W = 260  # 截图区域长
SCREENSHOT_H = 260  # 截图区域高
LEFT = SCREEN_CX - SCREENSHOT_W // 2  # 检测框左上角x : 845
TOP = SCREEN_CY - SCREENSHOT_H // 2   # 检测框左上角y : 425


def ScreenShout():
    """
    截取游戏中要检测区域的图片
    :return: (h,w,c)
    """
    img = pyautogui.screenshot(region=[LEFT, TOP, SCREENSHOT_W, SCREENSHOT_H])
    return np.array(img)


class Detector:
    def __init__(self, model_path, dll_path):
        self.bbox_array = None
        self.yolov5 = CDLL(dll_path)
        self.yolov5.Detect.argtypes = [c_void_p, c_int, c_int, POINTER(c_ubyte), npct.ndpointer(dtype=np.float32, ndim=2, shape=(50, 6), flags="C_CONTIGUOUS")]
        self.yolov5.Init.restype = c_void_p
        self.yolov5.Init.argtypes = [c_void_p]
        self.yolov5.cuda_free.argtypes = [c_void_p]
        self.c_point = self.yolov5.Init(model_path)

    def predict(self, img):
        try:
            rows, cols = img.shape[0], img.shape[1]
            res_arr = np.zeros((50, 6), dtype=np.float32)
            self.yolov5.Detect(self.c_point, c_int(rows), c_int(cols), img.ctypes.data_as(POINTER(c_ubyte)), res_arr)
            self.bbox_array = res_arr[~(res_arr == 0).all(1)]
            detections = []
            for temp in self.bbox_array:
                bbox = [temp[0], temp[1], temp[2], temp[3]]  # xywh
                clas = int(temp[4])
                score = temp[5]
                detections.append({'class': clas, 'conf': score, 'position': bbox})
            return detections
        except:
            return None

    def free(self):
        self.yolov5.cuda_free(self.c_point)


def visualize(img, bbox_array):
    for temp in bbox_array:
        bbox = [temp[0], temp[1], temp[2], temp[3]]  # xywh
        clas = int(temp[4])
        score = temp[5]
        cv2.rectangle(img, (int(temp[0]), int(temp[1])), (int(temp[0] + temp[2]), int(temp[1] + temp[3])), (105, 237, 249), 2)
        img = cv2.putText(img, "class:" + str(clas) + " " + str(round(score, 2)), (int(temp[0]), int(temp[1]) - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (105, 237, 249), 1)
    return img


def Center(p):
    """
    返回中心坐标;
    :param p: [lx,ly,w,h]->[左上x坐标,左上y坐标]
    :return: [x,y]
    """
    return [p[0] + p[2] // 2, p[1] + p[3] // 2]


def Distence(a, b):
    """
    两点间距离(欧氏距离)
    :param a:a点 (xa,ya)
    :param b: b点(xb,yb)
    :return: sqrt((xa-xb)**2 + (yb-ya)**2)
    """
    return math.sqrt(((a[0] - b[0]) ** 2) + ((a[1] - b[1]) ** 2))


def FindBestCenter(detections):
    """
    根据检测的结果,寻找最佳射击坐标
    :param detections: 检测结果
    :return:
    :btp: 目标框的位置信息
    :btc: 需要移动的X和Y的距离
    """
    ch = {'p': [0, 0, 0, 0], 'd': float('inf'), 'c': 0.0}  # 离枪口最近的头 p位置 d距离中心距离 c可信度
    for dt in detections:
        """
        遍历检测到的目标,找最近的头和身子
        """
        if dt['conf'] > 0.6:        # 只寻找置信度达到70%的头和身子
            dt_p = dt['position']   # 检测出来的目标位置, 'position': [66.0, 109.0, 114.0, 118.0] 【左上角的坐标x, 左上角的坐标y, 目标框的宽, 目标框的高】
            dt_c = Center(dt_p)     # The center coordinates of the target position: (w,h)

            if dt['class'] == 0:    # 判断是不是最优头
                dt_d = Distence(dt_c, SCREEN_C) # computer the distance of (enemy center and screen center).
                if dt_d < ch['d']:
                    ch['p'] = dt['position']
                    ch['d'] = dt_d
                    ch['c'] = dt['conf']
                    pass


    if ch['d'] < float('inf'):              # 自动选择瞄准部位
        btp = ch['p']                       # target position coordinates
        btc = Center(btp)                   # target center coordinates
        btc[0] = int(LEFT + btc[0] - SCREEN_CX)

        # 模式1、这样是瞄准人物的正中心
        # btc[1] = int(TOP + btc[1] - SCREEN_CY)

        # 模式2、这样是瞄准人物的头部正中心,就相当于在1的基础上减去半个目标框的y距离,这样就到了人物头部的最上面,然后在cftool中“btc[1] + tt”
        # y中心距离加了tt,意思就是向下移动一点,这样可以命中头部了就
        btc[1] = int(TOP + btc[1] - SCREEN_CY) - int(btp[3] / 2)

        if btp[2] < 8:
            return None, None
        return btc, btp
    return None, None

How can I move the mouse to that position like the code below:(move with relative position)

# 截图返回
import threading
import time
import warnings

import win32api
import win32con
from FpsDetect import ScreenShout, Detector, FindBestCenter


LAST_TIME = time.time()
tempX_val = 0

def clickLeft():
    global LAST_TIME
    LAST_TIME = time.time()
    win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)   # The left button is down.
    win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0)     # The left button is up.


def work():
    global LAST_TIME
    global tempX_val
    det = Detector(model_path= b"./cfModel.engine", dll_path= "./yolov5.dll")  # b'' is needed
    while True:
        img = ScreenShout()                         # Capture an image of the area to be examined in the game
        # Output class, confidence, aim position
        # for example: [{'class': 0, 'conf': 0.89293504, 'position': [60.0, 109.0, 82.0, 119.0]}]
        detections = det.predict(img)
        if detections is not None:
            btc, btp = FindBestCenter(detections)   # Get Optimum shooting coordinates.
            print(detections)
            if btc is not None:
                print("The move distance is(btp) :", btp, "The target position coordinates is(btc):", btc)
                tt = 0
                if btp[2] < 25:
                    tt = 4
                else:
                    tt = 5

                win32api.mouse_event(win32con.MOUSEEVENTF_MOVE, int(btc[0]), btc[1] + tt, 0, 0)

                if 8 > btc[0] > -8 and 12 > btc[1]+tt > -12:
                    print("时间", time.time() - LAST_TIME)
                    if time.time() - LAST_TIME > 0.1:
                        threading.Thread(target=clickLeft, args=()).start()


if __name__ == '__main__':
    warnings.filterwarnings("ignore")
    # 开始截图线程
    a1 = threading.Thread(target=work, args=())
    a1.start()

Why use a relative position move instead of moving directly to that position?

因为在某些场景下,直接鼠标位置移动是实现不了的,只能使用如下相对位置鼠标移动:

win32api.mouse_event(win32con.MOUSEEVENTF_MOVE, int(btc[0]), btc[1] + tt, 0, 0)

其中tt的含义看第一段代码,其中有解释.

猜你喜欢

转载自blog.csdn.net/weixin_43135178/article/details/124653487