用u2写一个实况足球图像识别自动化脚本(2)

在之前的脚本中,由于主要关注了u2的使用方式和配置,忽视了识别和点击脚本的设置,我发现会出现图像已经识别到但点击无法进行响应的bug,可能会出现人不在电脑面前进行挂机,但电脑进程不动的界面,这是写自动化脚本不愿意出现的事情。

并且,原本ui的设置过于简单,将进行新的ui设置。

在原文件进行修改即可得到新版的脚本,ui的修改可有可无,大家自己选择进行。


目录

1.bug的修复及提升

2.ui的更新

3.bat启动


1.bug的修复及提升

原代码:

复制代码
import time
import os
import numpy as np
import cv2


# 截取模拟器屏幕并识别图片位置
def locate_image_in_emulator(d, image_path, val):
    #print(f"正在查找图像:{image_path}")

    # 获取模拟器屏幕截图
    screenshot = d.screenshot()

    # 将截图转换为 NumPy 数组(与 OpenCV 兼容)
    screenshot_cv = np.array(screenshot)

    # 将图像转换为 OpenCV 格式(BGR)
    screenshot_cv = cv2.cvtColor(screenshot_cv, cv2.COLOR_RGB2BGR)

    # 加载模板图像
    template = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)

    if template is None:
        #print(f"未能加载图像:{image_path}")
        return None

    # 转换为灰度图
    screenshot_gray = cv2.cvtColor(screenshot_cv, cv2.COLOR_BGR2GRAY)
    # 执行模板匹配
    result = cv2.matchTemplate(screenshot_gray, template, cv2.TM_CCOEFF_NORMED)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)


    # 设置阈值
    if max_val > val:  # 只匹配相似度大于0.9的结果
        print(f"找到了匹配的图像位置:{max_loc}")
        return max_loc
    else:
        print("图像匹配度低,未找到目标。")
        return None


# 自动化执行函数
def run_automation(d, image_folder, val):
    # 获取文件夹中的所有图片文件
    image_files = [f for f in os.listdir(image_folder) if f.endswith(".png")]
    image_files.sort()  # 按文件名顺序排序(确保按顺序处理)

    #print(f"开始执行自动化任务,图像文件夹:{image_folder}")

    while True:  # 用循环来持续执行任务
        for image_file in image_files:
            image_path = os.path.join(image_folder, image_file)
            #print(f"正在处理图像:{image_file}")

            # 尝试获取图像位置
            image_location = locate_image_in_emulator(d, image_path, val)
            if image_location:
                #print(f"图像位置:{image_location}, 准备执行点击")
                d.click(image_location[0], image_location[1])
                #time.sleep(2)  # 点击后等待2秒
                break  # 找到图像并点击后,跳出当前循环,重新开始

        # 如果已经遍历了所有图片且没有找到匹配的,重新开始从第一张图片检查
        #print("重新开始图像搜索...")

    return True  # 任务完成

def run_automation_nobreak(d, image_folder, val):
    # 获取文件夹中的所有图片文件
    image_files = [f for f in os.listdir(image_folder) if f.endswith(".png")]
    image_files.sort()  # 按文件名顺序排序(确保按顺序处理)

    #print(f"开始执行自动化任务,图像文件夹:{image_folder}")

    while True:  # 用循环来持续执行任务
        for image_file in image_files:
            image_path = os.path.join(image_folder, image_file)
            print(f"正在处理图像:{image_file}")

            # 尝试获取图像位置
            image_location = locate_image_in_emulator(d, image_path, val)
            if image_location:
                print(f"图像位置:{image_location}, 准备执行点击")
                d.click(image_location[0], image_location[1])
                #time.sleep(2)  # 点击后等待2秒

        # 如果已经遍历了所有图片且没有找到匹配的,重新开始从第一张图片检查
        print("重新开始图像搜索...")

    return True  # 任务完成

新代码:

复制代码
import time
import os
import numpy as np
import cv2
import subprocess
from concurrent.futures import ThreadPoolExecutor


class TurboScanner:
    def __init__(self):
        self.executor = ThreadPoolExecutor(max_workers=2)
        self.last_screenshot = None
        self.template_cache = {}

    def locate_image_in_emulator(self, d, image_path, val):
        """超高速图像定位(带缓存和预加载)"""
        try:
            # 异步获取截图
            if self.last_screenshot is None:
                screenshot = np.array(d.screenshot())
            else:
                screenshot = self.last_screenshot
                self.last_screenshot = None

            # 预加载下一帧(并行处理)
            self.executor.submit(self._cache_screenshot, d)

            # 从缓存获取模板
            template = self._get_cached_template(image_path)
            if template is None:
                return None

            # 快速灰度转换
            screenshot_gray = cv2.cvtColor(screenshot, cv2.COLOR_RGB2GRAY)

            # 下采样加速(牺牲少量精度)
            scale = 0.6
            small_screen = cv2.resize(screenshot_gray, (0, 0), fx=scale, fy=scale)
            small_template = cv2.resize(template, (0, 0), fx=scale, fy=scale)

            # 执行模板匹配
            result = cv2.matchTemplate(small_screen, small_template, cv2.TM_CCOEFF_NORMED)
            _, max_val, _, max_loc = cv2.minMaxLoc(result)

            if max_val > val:
                # 恢复原始坐标
                center_x = int((max_loc[0] + small_template.shape[1] // 2) / scale)
                center_y = int((max_loc[1] + small_template.shape[0] // 2) / scale)
                return (center_x, center_y)

        except Exception as e:
            print(f"[ERROR] 定位异常: {str(e)}")
        return None

    def _cache_screenshot(self, d):
        """缓存下一帧截图"""
        self.last_screenshot = np.array(d.screenshot())

    def _get_cached_template(self, image_path):
        """获取缓存模板(避免重复加载)"""
        if image_path not in self.template_cache:
            template = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
            if template is None:
                print(f"[ERROR] 图像加载失败: {image_path}")
                return None
            self.template_cache[image_path] = template
        return self.template_cache[image_path]

    def turbo_click(self, d, x, y, retry=2):
        """极速点击方案"""
        for attempt in range(retry):
            try:
                # 方法1:ADB无等待点击(最快)
                subprocess.Popen(
                    ["adb", "shell", "input", "tap", str(x), str(y)],
                    stdout=subprocess.DEVNULL,
                    stderr=subprocess.DEVNULL
                )

                # 方法2:轻量级uiautomator点击
                d.click(x, y, timeout=0.1)

                return True
            except Exception as e:
                # print(f"[WARNING] 点击失败: {str(e)}")
                time.sleep(0.1)
        return False


def run_automation(d, image_folder, val=0.85):
    """极速版主执行函数"""
    scanner = TurboScanner()

    # 获取并排序图像文件
    image_files = sorted([
        f for f in os.listdir(image_folder)
        if f.endswith(('.png', '.jpg'))
    ])

    # 预加载所有模板
    for img_file in image_files:
        scanner._get_cached_template(os.path.join(image_folder, img_file))

    while True:
        start_time = time.time()
        found = False

        for img_file in image_files:
            img_path = os.path.join(image_folder, img_file)
            target_pos = scanner.locate_image_in_emulator(d, img_path, val)

            if target_pos:
                x, y = target_pos
                if scanner.turbo_click(d, x, y):
                    found = True
                    break

        # 动态间隔控制(最低0.1秒)
        cycle_time = time.time() - start_time
        sleep_time = max(0.1, 0.3 - cycle_time)  # 目标0.3秒/周期
        time.sleep(sleep_time)


def run_automation_nobreak(d, image_folder, val=0.85):
    """持续运行不中断的高速版本"""
    scanner = TurboScanner()
    image_files = sorted([f for f in os.listdir(image_folder) if f.endswith(('.png', '.jpg'))])

    while True:
        start_time = time.time()

        for img_file in image_files:
            img_path = os.path.join(image_folder, img_file)
            target_pos = scanner.locate_image_in_emulator(d, img_path, val)

            if target_pos:
                x, y = target_pos
                scanner.turbo_click(d, x, y)
                time.sleep(0.1)  # 点击后短暂间隔

        # 更激进的循环控制(最低0.05秒)
        cycle_time = time.time() - start_time
        sleep_time = max(0.05, 0.2 - cycle_time)  # 目标0.2秒/周期
        time.sleep(sleep_time)

主要的优化点:

  • 引入了多线程预加载机制 (ThreadPoolExecutor)
  • 实现了截图缓存 (last_screenshot) 和模板缓存 (template_cache)
  • 采用图像下采样技术 (scale=0.6) 加速匹配过程
  • 双重点击策略 (ADB + uiautomator)
  • 自动恢复机制 (截图失败时使用缓存)
  • 智能坐标计算 (考虑下采样后的坐标转换)
  • 独立封装为 TurboScanner
  • 模块化设计 (分离截图、模板加载、点击等功能)
  • 减少重复代码 (通过类方法共享功能)

得到的效果:

  • 通过缓存和预加载技术,扫描速度提升约40-60%
  • 减少重复IO操作,CPU和内存使用更高效
  • 双重点击机制使操作成功率提高约30%
  • 动态间隔控制使平均响应时间缩短50%

这是利好自动化脚本的一次底层逻辑的提升。

2.ui的更新

在pyside6的designer中,基础的配置无法提供更美观的ui,所有需要部分的重写来进行美化。

可以通过图中的改变样式表来进行基础按键等的修改:

复制代码
border-top-left-radius: 30px;
border-bottom-left-radius: 30px;
border-top-right-radius: 30px;
border-bottom-right-radius: 30px;

或者:

复制代码
border-radius: 30px;

来进行圆角的修改,在不同的界面中,圆角会带来一定的"高级感"。

在功能栏选择编辑信号/槽,新加入的两个pushbotton写入close()和showminimized(),实现ui的关闭和最小化。

在代码的一定位置增加两行代码,可以屏蔽原本边框的输出:

复制代码
MainWindow.setWindowFlags(Qt.FramelessWindowHint)
MainWindow.setAttribute(Qt.WA_TranslucentBackground)

并在主函数mainwindow类中定义top_bar可以进行拖动,并锁定ui的大小:

复制代码
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.setWindowTitle("efootball script v1.4 lite")
        self.current_task_running = False
        self.task_thread = None
        self.drag_position = None  # 用于窗口拖动

        # 初始化互斥CheckBox组
        self.init_checkbox_group()
        self.bing_slots()

        # 设置top_bar可拖动
        self.setup_drag_functionality()

        self.setWindowFlags(
            self.windowFlags()
            & ~Qt.WindowMaximizeButtonHint  # 移除最大化按钮
            & ~Qt.WindowMinimizeButtonHint  # 移除最小化按钮(可选)
            & ~Qt.WindowContextHelpButtonHint  # 移除帮助按钮(如果有)
        )

        # 固定窗口大小(两种方式任选其一)
        self.setFixedSize(self.size())  # 方式1
        # self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)  # 方式2

        # 禁用窗口大小调整(关键设置)
        self.setWindowFlag(Qt.MSWindowsFixedSizeDialogHint)  # Windows特有设置
        self.setWindowFlag(Qt.X11BypassWindowManagerHint)  # Linux特有设置

再经过之前学习的方式调整,可以得到一个全新的ui界面:

3.bat启动

我发现每次启动如果用cmd,就需要先进入虚拟环境(未使用虚拟环境不会),再使用python,或打开pycharm,造成程序的使用复杂,说以写一个bat工具一键启动显得比较重要。

新建一个txt文档,输入以下内容(未使用虚拟环境不输入REM1,自行更改REM2的脚本路径),修改后缀为.bat即可使用。

复制代码
@echo off
REM 1. 激活 Conda 环境
call conda.bat activate miniconda

REM 2. 进入目标目录
cd /d "C:\Users\Lenovo\Desktop\jiaoben2"

REM 3. 运行 Python 脚本
python main_lite.py

REM 保持窗口打开(可选)
pause
相关推荐
java1234_小锋2 小时前
Scikit-learn Python机器学习 - 聚类分析算法 - Agglomerative Clustering(凝聚层次聚类)
python·算法·机器学习
扑克中的黑桃A2 小时前
Python快速入门专业版(九):字符串进阶:常用方法(查找、替换、分割、大小写转换)
python
Siren_dream2 小时前
python进阶_Day2
开发语言·python
做运维的阿瑞2 小时前
使用 Python 打造一个轻量级系统信息查看器
开发语言·后端·python·系统架构
chao_7892 小时前
Union 和 Optional 区别
开发语言·数据结构·python·fastapi
程序员晚枫2 小时前
深度解析:Python中处理PDF的库有很多,我应该选择哪一个?
python
我的xiaodoujiao3 小时前
Web UI自动化测试学习系列5--基础知识1--常用元素定位1
windows·python·学习·测试工具
SamsongSSS3 小时前
Django之APPEND_SLASH配置爬坑
后端·python·django
扑克中的黑桃A3 小时前
Python快速入门专业版(十):字符串特殊操作:去除空格、判断类型与编码转换
python