ui界面版本
This commit is contained in:
99
CHANGELOG.md
Normal file
99
CHANGELOG.md
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
# 更新日志
|
||||||
|
|
||||||
|
## 最新更新 - 多组配置系统
|
||||||
|
|
||||||
|
### 主要变更
|
||||||
|
|
||||||
|
#### 1. 新增文件
|
||||||
|
|
||||||
|
- **config.py** - 配置管理器,支持多组配置
|
||||||
|
- **gui_config.py** - 可视化配置界面(tkinter)
|
||||||
|
- **preview.py** - 采集卡预览窗口系统
|
||||||
|
- **launcher.py** - 统一启动器
|
||||||
|
- **README.md** - 使用文档
|
||||||
|
- **config.json** - 配置文件(自动生成)
|
||||||
|
|
||||||
|
#### 2. 修改的文件
|
||||||
|
|
||||||
|
- **main.py** - 完全重写,支持配置系统
|
||||||
|
- 从配置文件加载参数
|
||||||
|
- 支持动态读取v值
|
||||||
|
- 移除硬编码配置
|
||||||
|
- **utils/mouse.py** - 移除硬编码串口
|
||||||
|
- 新增 `init_mouse_keyboard()` 函数
|
||||||
|
- 支持从配置初始化
|
||||||
|
- **utils/get_image.py** - 支持从配置初始化
|
||||||
|
- GetImage改为延迟初始化
|
||||||
|
|
||||||
|
### 核心功能
|
||||||
|
|
||||||
|
1. **多组配置管理**
|
||||||
|
- 支持创建多个配置组
|
||||||
|
- 每个配置组独立的串口、采集卡、速度设置
|
||||||
|
- 可视化切换活动配置
|
||||||
|
|
||||||
|
2. **可视化配置界面**
|
||||||
|
- GUI界面管理所有配置
|
||||||
|
- 实时编辑和保存
|
||||||
|
- 支持添加/删除配置组
|
||||||
|
|
||||||
|
3. **采集卡预览系统**
|
||||||
|
- 网格方式预览多个采集卡
|
||||||
|
- 点击放大查看
|
||||||
|
- 实时画面更新
|
||||||
|
|
||||||
|
4. **灵活的参数配置**
|
||||||
|
- 串口配置(端口、波特率)
|
||||||
|
- 采集卡配置(索引、分辨率)
|
||||||
|
- 移动速度(v值)配置
|
||||||
|
- 预览窗口配置
|
||||||
|
|
||||||
|
### 使用方式
|
||||||
|
|
||||||
|
#### 旧版本(已保留 main_old.py)
|
||||||
|
```bash
|
||||||
|
python main_old.py # 直接运行,使用硬编码配置
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 新版本
|
||||||
|
```bash
|
||||||
|
# 方式1: 使用启动器(推荐)
|
||||||
|
python launcher.py
|
||||||
|
|
||||||
|
# 方式2: 直接运行
|
||||||
|
python main.py # 读取config.json的active配置
|
||||||
|
```
|
||||||
|
|
||||||
|
### 配置示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"name": "配置组1",
|
||||||
|
"serial_port": "COM6",
|
||||||
|
"serial_baudrate": 9600,
|
||||||
|
"camera_index": 0,
|
||||||
|
"camera_width": 1920,
|
||||||
|
"camera_height": 1080,
|
||||||
|
"move_velocity": 470, // ← move_to函数中的v值
|
||||||
|
"active": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 兼容性
|
||||||
|
|
||||||
|
- ✅ 保留所有原有功能
|
||||||
|
- ✅ YOLO模型无需修改
|
||||||
|
- ✅ 游戏逻辑完全兼容
|
||||||
|
- ⚠️ 旧代码会使用默认配置
|
||||||
|
|
||||||
|
### 下一步
|
||||||
|
|
||||||
|
如需添加更多配置:
|
||||||
|
1. 在 `config.py` 的 `default_config` 中添加新字段
|
||||||
|
2. 在 `gui_config.py` 中添加对应的输入框
|
||||||
|
3. 在 `main.py` 中读取并使用新配置
|
||||||
|
|
||||||
141
README.md
Normal file
141
README.md
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
# 火炬之光自动化脚本
|
||||||
|
|
||||||
|
## 功能特点
|
||||||
|
|
||||||
|
- ✅ **多配置组管理** - 支持多组配置,可同时管理多套采集卡和串口设置
|
||||||
|
- 🖥️ **可视化配置** - 提供图形化界面管理所有配置
|
||||||
|
- 👁️ **采集卡预览** - 多窗口网格预览,点击可放大查看
|
||||||
|
- ⚙️ **灵活配置** - 所有参数(串口、采集卡、移动速度等)均可配置
|
||||||
|
- 🤖 **智能自动化** - 基于YOLO目标检测的游戏自动化
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### 1. 安装依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install opencv-python ultralytics ddddocr ch9329Comm serial PIL numpy
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 启动程序
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python launcher.py
|
||||||
|
```
|
||||||
|
|
||||||
|
启动器提供三个选项:
|
||||||
|
- **⚙️ 配置管理** - 配置串口、采集卡等参数
|
||||||
|
- **👁️ 采集卡预览** - 实时预览采集卡画面
|
||||||
|
- **🚀 启动自动化** - 启动游戏自动化脚本
|
||||||
|
|
||||||
|
### 3. 配置设置
|
||||||
|
|
||||||
|
首次使用请先点击"配置管理":
|
||||||
|
|
||||||
|
1. **添加配置组** - 点击"添加组"创建新配置
|
||||||
|
2. **设置参数**:
|
||||||
|
- 串口:选择设备串口号(如 COM6)
|
||||||
|
- 波特率:设置串口波特率(默认9600)
|
||||||
|
- 采集卡索引:选择采集卡设备号
|
||||||
|
- 采集宽度/高度:设置采集分辨率
|
||||||
|
- 移动速度:设置角色移动速度(v值)
|
||||||
|
3. **设为活动** - 选择要使用的配置组并设为活动
|
||||||
|
4. **保存配置** - 点击"保存配置"
|
||||||
|
|
||||||
|
### 4. 预览采集卡
|
||||||
|
|
||||||
|
点击"采集卡预览"可以:
|
||||||
|
- 网格方式查看所有活动的采集卡
|
||||||
|
- 点击任意窗口可放大查看
|
||||||
|
- 实时显示采集卡画面
|
||||||
|
|
||||||
|
### 5. 启动自动化
|
||||||
|
|
||||||
|
配置完成后,点击"启动自动化"开始游戏自动化。
|
||||||
|
|
||||||
|
## 配置说明
|
||||||
|
|
||||||
|
### 配置组结构
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"name": "配置组1",
|
||||||
|
"serial_port": "COM6",
|
||||||
|
"serial_baudrate": 9600,
|
||||||
|
"camera_index": 0,
|
||||||
|
"camera_width": 1920,
|
||||||
|
"camera_height": 1080,
|
||||||
|
"move_velocity": 470,
|
||||||
|
"active": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"display": {
|
||||||
|
"preview_window_width": 640,
|
||||||
|
"preview_window_height": 360,
|
||||||
|
"preview_columns": 2,
|
||||||
|
"preview_rows": 2,
|
||||||
|
"show_preview": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 关键参数说明
|
||||||
|
|
||||||
|
- **serial_port**: 串口号,如 COM1, COM6
|
||||||
|
- **serial_baudrate**: 波特率,通常为 9600
|
||||||
|
- **camera_index**: 采集卡索引,0/1/2...
|
||||||
|
- **camera_width/height**: 采集分辨率
|
||||||
|
- **move_velocity**: 角色移动速度(v值),数值越大移动越快
|
||||||
|
|
||||||
|
## 文件结构
|
||||||
|
|
||||||
|
```
|
||||||
|
huojv/
|
||||||
|
├── launcher.py # 启动器
|
||||||
|
├── main.py # 主程序(自动游戏)
|
||||||
|
├── config.py # 配置管理器
|
||||||
|
├── gui_config.py # 配置GUI界面
|
||||||
|
├── preview.py # 预览窗口
|
||||||
|
├── utils/
|
||||||
|
│ ├── get_image.py # 采集卡管理
|
||||||
|
│ ├── mouse.py # 鼠标控制
|
||||||
|
│ ├── shizi.py # OCR识别
|
||||||
|
│ └── ...
|
||||||
|
├── best.pt # YOLO模型(战斗)
|
||||||
|
├── best0.pt # YOLO模型(城镇)
|
||||||
|
└── config.json # 配置文件(自动生成)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用流程
|
||||||
|
|
||||||
|
1. 运行 `python launcher.py`
|
||||||
|
2. 点击"配置管理"设置参数
|
||||||
|
3. 点击"采集卡预览"测试采集
|
||||||
|
4. 点击"启动自动化"开始游戏
|
||||||
|
5. 享受自动化!
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
- 确保采集卡和串口设备已正确连接
|
||||||
|
- 串口号和采集卡索引需要根据实际情况设置
|
||||||
|
- 移动速度(v值)需要根据游戏角色属性调整
|
||||||
|
- 配置文件保存在 `config.json`
|
||||||
|
|
||||||
|
## 问题排查
|
||||||
|
|
||||||
|
### 无法打开串口
|
||||||
|
- 检查串口号是否正确
|
||||||
|
- 确认串口设备已连接
|
||||||
|
- 检查其他程序是否占用串口
|
||||||
|
|
||||||
|
### 无法打开采集卡
|
||||||
|
- 检查采集卡索引是否正确(0, 1, 2...)
|
||||||
|
- 确认采集卡驱动已安装
|
||||||
|
- 尝试不同的采集卡索引
|
||||||
|
|
||||||
|
### 识别不准确
|
||||||
|
- 调整移动速度(v值)
|
||||||
|
- 检查采集卡画面是否清晰
|
||||||
|
- 确认游戏窗口位置正确
|
||||||
|
|
||||||
22
config.json
Normal file
22
config.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"name": "配置组1",
|
||||||
|
"serial_port": "COM6",
|
||||||
|
"serial_baudrate": 9600,
|
||||||
|
"camera_index": 0,
|
||||||
|
"camera_width": 1920,
|
||||||
|
"camera_height": 1080,
|
||||||
|
"move_velocity": 470,
|
||||||
|
"active": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"display": {
|
||||||
|
"preview_window_width": 640,
|
||||||
|
"preview_window_height": 360,
|
||||||
|
"preview_columns": 2,
|
||||||
|
"preview_rows": 2,
|
||||||
|
"show_preview": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
111
config.py
Normal file
111
config.py
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
class ConfigManager:
|
||||||
|
"""配置管理器"""
|
||||||
|
def __init__(self, config_file='config.json'):
|
||||||
|
self.config_file = config_file
|
||||||
|
self.default_config = {
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"name": "配置组1",
|
||||||
|
"serial_port": "COM6",
|
||||||
|
"serial_baudrate": 9600,
|
||||||
|
"camera_index": 0,
|
||||||
|
"camera_width": 1920,
|
||||||
|
"camera_height": 1080,
|
||||||
|
"move_velocity": 470,
|
||||||
|
"active": False
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"display": {
|
||||||
|
"preview_window_width": 640,
|
||||||
|
"preview_window_height": 360,
|
||||||
|
"preview_columns": 2,
|
||||||
|
"preview_rows": 2,
|
||||||
|
"show_preview": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.config = self.load_config()
|
||||||
|
|
||||||
|
def load_config(self):
|
||||||
|
"""加载配置文件"""
|
||||||
|
if os.path.exists(self.config_file):
|
||||||
|
try:
|
||||||
|
with open(self.config_file, 'r', encoding='utf-8') as f:
|
||||||
|
config = json.load(f)
|
||||||
|
# 确保有默认结构
|
||||||
|
if 'groups' not in config:
|
||||||
|
config['groups'] = self.default_config['groups']
|
||||||
|
if 'display' not in config:
|
||||||
|
config['display'] = self.default_config['display']
|
||||||
|
return config
|
||||||
|
except Exception as e:
|
||||||
|
print(f"加载配置文件失败: {e}")
|
||||||
|
return self.default_config.copy()
|
||||||
|
return self.default_config.copy()
|
||||||
|
|
||||||
|
def save_config(self):
|
||||||
|
"""保存配置文件"""
|
||||||
|
try:
|
||||||
|
with open(self.config_file, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(self.config, f, ensure_ascii=False, indent=4)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"保存配置文件失败: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def add_group(self, name=None):
|
||||||
|
"""添加配置组"""
|
||||||
|
if name is None:
|
||||||
|
name = f"配置组{len(self.config['groups']) + 1}"
|
||||||
|
|
||||||
|
new_group = {
|
||||||
|
"name": name,
|
||||||
|
"serial_port": "COM6",
|
||||||
|
"serial_baudrate": 9600,
|
||||||
|
"camera_index": len(self.config['groups']),
|
||||||
|
"camera_width": 1920,
|
||||||
|
"camera_height": 1080,
|
||||||
|
"move_velocity": 470,
|
||||||
|
"active": False
|
||||||
|
}
|
||||||
|
self.config['groups'].append(new_group)
|
||||||
|
return new_group
|
||||||
|
|
||||||
|
def delete_group(self, index):
|
||||||
|
"""删除配置组"""
|
||||||
|
if 0 <= index < len(self.config['groups']):
|
||||||
|
del self.config['groups'][index]
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def update_group(self, index, **kwargs):
|
||||||
|
"""更新配置组"""
|
||||||
|
if 0 <= index < len(self.config['groups']):
|
||||||
|
self.config['groups'][index].update(kwargs)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_active_group(self):
|
||||||
|
"""获取当前活动的配置组"""
|
||||||
|
for group in self.config['groups']:
|
||||||
|
if group.get('active', False):
|
||||||
|
return group
|
||||||
|
return None
|
||||||
|
|
||||||
|
def set_active_group(self, index):
|
||||||
|
"""设置活动的配置组"""
|
||||||
|
for i, group in enumerate(self.config['groups']):
|
||||||
|
group['active'] = (i == index)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_group_by_index(self, index):
|
||||||
|
"""根据索引获取配置组"""
|
||||||
|
if 0 <= index < len(self.config['groups']):
|
||||||
|
return self.config['groups'][index]
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 全局配置管理器实例
|
||||||
|
config_manager = ConfigManager()
|
||||||
|
|
||||||
223
gui_config.py
Normal file
223
gui_config.py
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
import tkinter as tk
|
||||||
|
from tkinter import ttk, messagebox, simpledialog
|
||||||
|
from config import config_manager
|
||||||
|
import threading
|
||||||
|
|
||||||
|
class ConfigGUI:
|
||||||
|
"""配置GUI界面"""
|
||||||
|
def __init__(self):
|
||||||
|
self.root = tk.Tk()
|
||||||
|
self.root.title("配置管理 - 火炬之光自动化")
|
||||||
|
self.root.geometry("800x600")
|
||||||
|
|
||||||
|
self.selected_index = 0
|
||||||
|
self.setup_ui()
|
||||||
|
self.load_current_config()
|
||||||
|
|
||||||
|
def setup_ui(self):
|
||||||
|
"""设置UI界面"""
|
||||||
|
# 左侧:配置组列表
|
||||||
|
left_frame = ttk.Frame(self.root, padding="10")
|
||||||
|
left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=False)
|
||||||
|
|
||||||
|
ttk.Label(left_frame, text="配置组列表", font=('Arial', 12, 'bold')).pack()
|
||||||
|
|
||||||
|
# 配置组列表
|
||||||
|
self.group_listbox = tk.Listbox(left_frame, width=20, height=25)
|
||||||
|
self.group_listbox.pack(fill=tk.BOTH, expand=True, pady=5)
|
||||||
|
self.group_listbox.bind('<<ListboxSelect>>', self.on_group_select)
|
||||||
|
|
||||||
|
# 按钮
|
||||||
|
btn_frame = ttk.Frame(left_frame)
|
||||||
|
btn_frame.pack(fill=tk.X)
|
||||||
|
|
||||||
|
ttk.Button(btn_frame, text="添加组", command=self.add_group).pack(fill=tk.X, pady=2)
|
||||||
|
ttk.Button(btn_frame, text="删除组", command=self.delete_group).pack(fill=tk.X, pady=2)
|
||||||
|
ttk.Button(btn_frame, text="设为活动", command=self.set_active).pack(fill=tk.X, pady=2)
|
||||||
|
|
||||||
|
# 右侧:配置详情
|
||||||
|
right_frame = ttk.Frame(self.root, padding="10")
|
||||||
|
right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
ttk.Label(right_frame, text="配置详情", font=('Arial', 12, 'bold')).pack()
|
||||||
|
|
||||||
|
# 配置项
|
||||||
|
self.config_vars = {}
|
||||||
|
|
||||||
|
# 基本配置
|
||||||
|
basic_frame = ttk.LabelFrame(right_frame, text="基本配置", padding="10")
|
||||||
|
basic_frame.pack(fill=tk.X, pady=5)
|
||||||
|
|
||||||
|
self.create_entry(basic_frame, "name", "配置组名称:")
|
||||||
|
self.create_entry(basic_frame, "camera_index", "采集卡索引:")
|
||||||
|
self.create_entry(basic_frame, "camera_width", "采集宽度:")
|
||||||
|
self.create_entry(basic_frame, "camera_height", "采集高度:")
|
||||||
|
|
||||||
|
# 串口配置
|
||||||
|
serial_frame = ttk.LabelFrame(right_frame, text="串口配置", padding="10")
|
||||||
|
serial_frame.pack(fill=tk.X, pady=5)
|
||||||
|
|
||||||
|
self.create_entry(serial_frame, "serial_port", "串口:")
|
||||||
|
self.create_entry(serial_frame, "serial_baudrate", "波特率:")
|
||||||
|
|
||||||
|
# 游戏配置
|
||||||
|
game_frame = ttk.LabelFrame(right_frame, text="游戏配置", padding="10")
|
||||||
|
game_frame.pack(fill=tk.X, pady=5)
|
||||||
|
|
||||||
|
self.create_entry(game_frame, "move_velocity", "移动速度(v值):")
|
||||||
|
|
||||||
|
# 预览配置
|
||||||
|
preview_frame = ttk.LabelFrame(right_frame, text="预览配置", padding="10")
|
||||||
|
preview_frame.pack(fill=tk.X, pady=5)
|
||||||
|
|
||||||
|
self.create_entry(preview_frame, "preview_width", "预览宽度:", prefix="display")
|
||||||
|
self.create_entry(preview_frame, "preview_height", "预览高度:", prefix="display")
|
||||||
|
self.create_entry(preview_frame, "preview_columns", "预览列数:", prefix="display")
|
||||||
|
self.create_entry(preview_frame, "preview_rows", "预览行数:", prefix="display")
|
||||||
|
|
||||||
|
# 保存按钮
|
||||||
|
save_frame = ttk.Frame(right_frame)
|
||||||
|
save_frame.pack(fill=tk.X, pady=10)
|
||||||
|
|
||||||
|
ttk.Button(save_frame, text="保存配置", command=self.save_config).pack(side=tk.LEFT, padx=5)
|
||||||
|
ttk.Button(save_frame, text="启动预览", command=self.start_preview).pack(side=tk.LEFT, padx=5)
|
||||||
|
ttk.Button(save_frame, text="启动程序", command=self.start_program).pack(side=tk.LEFT, padx=5)
|
||||||
|
|
||||||
|
def create_entry(self, parent, key, label, prefix=None):
|
||||||
|
"""创建输入框"""
|
||||||
|
frame = ttk.Frame(parent)
|
||||||
|
frame.pack(fill=tk.X, pady=3)
|
||||||
|
|
||||||
|
ttk.Label(frame, text=label, width=15).pack(side=tk.LEFT)
|
||||||
|
|
||||||
|
var = tk.StringVar()
|
||||||
|
entry = ttk.Entry(frame, textvariable=var, width=25)
|
||||||
|
entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
|
||||||
|
|
||||||
|
# 保存变量引用
|
||||||
|
if prefix:
|
||||||
|
full_key = f"{prefix}_{key}"
|
||||||
|
else:
|
||||||
|
full_key = key
|
||||||
|
self.config_vars[full_key] = var
|
||||||
|
|
||||||
|
def load_current_config(self):
|
||||||
|
"""加载当前配置到界面"""
|
||||||
|
# 加载配置组列表
|
||||||
|
self.update_group_list()
|
||||||
|
|
||||||
|
# 加载预览配置
|
||||||
|
display = config_manager.config.get('display', {})
|
||||||
|
for key in ['preview_width', 'preview_height', 'preview_columns', 'preview_rows']:
|
||||||
|
if key in display:
|
||||||
|
self.config_vars[f"display_{key}"].set(str(display[key]))
|
||||||
|
|
||||||
|
def update_group_list(self):
|
||||||
|
"""更新配置组列表"""
|
||||||
|
self.group_listbox.delete(0, tk.END)
|
||||||
|
for i, group in enumerate(config_manager.config['groups']):
|
||||||
|
status = "✓" if group.get('active', False) else " "
|
||||||
|
self.group_listbox.insert(tk.END, f"{status} {group['name']}")
|
||||||
|
|
||||||
|
def on_group_select(self, event):
|
||||||
|
"""选择配置组"""
|
||||||
|
selection = self.group_listbox.curselection()
|
||||||
|
if selection:
|
||||||
|
self.selected_index = selection[0]
|
||||||
|
self.load_group_config(self.selected_index)
|
||||||
|
|
||||||
|
def load_group_config(self, index):
|
||||||
|
"""加载配置组详情"""
|
||||||
|
group = config_manager.get_group_by_index(index)
|
||||||
|
if group:
|
||||||
|
for key, var in self.config_vars.items():
|
||||||
|
if not key.startswith('display_'):
|
||||||
|
if key in group:
|
||||||
|
var.set(str(group[key]))
|
||||||
|
|
||||||
|
def add_group(self):
|
||||||
|
"""添加配置组"""
|
||||||
|
name = simpledialog.askstring("添加配置组", "请输入配置组名称:", initialvalue=f"配置组{len(config_manager.config['groups'])+1}")
|
||||||
|
if name:
|
||||||
|
config_manager.add_group(name)
|
||||||
|
self.update_group_list()
|
||||||
|
messagebox.showinfo("成功", f"已添加配置组: {name}")
|
||||||
|
|
||||||
|
def delete_group(self):
|
||||||
|
"""删除配置组"""
|
||||||
|
selection = self.group_listbox.curselection()
|
||||||
|
if not selection:
|
||||||
|
messagebox.showwarning("警告", "请先选择要删除的配置组")
|
||||||
|
return
|
||||||
|
|
||||||
|
if messagebox.askyesno("确认", "确定要删除选中的配置组吗?"):
|
||||||
|
config_manager.delete_group(selection[0])
|
||||||
|
self.update_group_list()
|
||||||
|
messagebox.showinfo("成功", "配置组已删除")
|
||||||
|
|
||||||
|
def set_active(self):
|
||||||
|
"""设置为活动配置组"""
|
||||||
|
selection = self.group_listbox.curselection()
|
||||||
|
if not selection:
|
||||||
|
messagebox.showwarning("警告", "请先选择要设为活动的配置组")
|
||||||
|
return
|
||||||
|
|
||||||
|
config_manager.set_active_group(selection[0])
|
||||||
|
self.update_group_list()
|
||||||
|
messagebox.showinfo("成功", "已设置为活动配置组")
|
||||||
|
|
||||||
|
def save_config(self):
|
||||||
|
"""保存当前编辑的配置"""
|
||||||
|
# 保存当前组的配置
|
||||||
|
group = config_manager.get_group_by_index(self.selected_index)
|
||||||
|
if group:
|
||||||
|
for key, var in self.config_vars.items():
|
||||||
|
if not key.startswith('display_'):
|
||||||
|
try:
|
||||||
|
value = int(var.get()) if var.get().isdigit() else var.get()
|
||||||
|
group[key] = value
|
||||||
|
except:
|
||||||
|
group[key] = var.get()
|
||||||
|
|
||||||
|
# 保存预览配置
|
||||||
|
display = config_manager.config.get('display', {})
|
||||||
|
for key in ['preview_width', 'preview_height', 'preview_columns', 'preview_rows']:
|
||||||
|
var = self.config_vars.get(f"display_{key}")
|
||||||
|
if var:
|
||||||
|
try:
|
||||||
|
display[key] = int(var.get())
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
config_manager.config['display'] = display
|
||||||
|
|
||||||
|
if config_manager.save_config():
|
||||||
|
messagebox.showinfo("成功", "配置已保存")
|
||||||
|
else:
|
||||||
|
messagebox.showerror("错误", "配置保存失败")
|
||||||
|
|
||||||
|
def start_preview(self):
|
||||||
|
"""启动预览窗口"""
|
||||||
|
# 保存配置
|
||||||
|
self.save_config()
|
||||||
|
|
||||||
|
# 启动预览窗口
|
||||||
|
from preview import PreviewWindow
|
||||||
|
preview_thread = threading.Thread(target=lambda: PreviewWindow().run())
|
||||||
|
preview_thread.daemon = True
|
||||||
|
preview_thread.start()
|
||||||
|
|
||||||
|
def start_program(self):
|
||||||
|
"""启动主程序"""
|
||||||
|
# 保存配置
|
||||||
|
self.save_config()
|
||||||
|
|
||||||
|
messagebox.showinfo("提示", "配置已保存,请运行主程序")
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""运行GUI"""
|
||||||
|
self.root.mainloop()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = ConfigGUI()
|
||||||
|
app.run()
|
||||||
|
|
||||||
68
launcher.py
Normal file
68
launcher.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
"""
|
||||||
|
启动器 - 选择启动配置界面或主程序
|
||||||
|
"""
|
||||||
|
import tkinter as tk
|
||||||
|
from tkinter import ttk
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def start_config_gui():
|
||||||
|
"""启动配置界面"""
|
||||||
|
subprocess.Popen([sys.executable, "gui_config.py"])
|
||||||
|
|
||||||
|
def start_preview():
|
||||||
|
"""启动预览窗口"""
|
||||||
|
subprocess.Popen([sys.executable, "preview.py"])
|
||||||
|
|
||||||
|
def start_main_program():
|
||||||
|
"""启动主程序"""
|
||||||
|
subprocess.Popen([sys.executable, "main.py"])
|
||||||
|
|
||||||
|
def create_launcher():
|
||||||
|
"""创建启动器界面"""
|
||||||
|
root = tk.Tk()
|
||||||
|
root.title("火炬之光自动化 - 启动器")
|
||||||
|
root.geometry("400x300")
|
||||||
|
root.resizable(False, False)
|
||||||
|
|
||||||
|
# 标题
|
||||||
|
title_frame = tk.Frame(root)
|
||||||
|
title_frame.pack(fill=tk.X, pady=20)
|
||||||
|
|
||||||
|
tk.Label(title_frame, text="火炬之光自动化脚本", font=('Arial', 16, 'bold')).pack()
|
||||||
|
tk.Label(title_frame, text="请选择要启动的功能", font=('Arial', 10)).pack()
|
||||||
|
|
||||||
|
# 按钮区域
|
||||||
|
button_frame = tk.Frame(root)
|
||||||
|
button_frame.pack(fill=tk.BOTH, expand=True, padx=40, pady=20)
|
||||||
|
|
||||||
|
# 配置界面按钮
|
||||||
|
config_btn = tk.Button(button_frame, text="⚙️ 配置管理",
|
||||||
|
command=start_config_gui,
|
||||||
|
width=30, height=3, font=('Arial', 12))
|
||||||
|
config_btn.pack(pady=10)
|
||||||
|
|
||||||
|
# 预览窗口按钮
|
||||||
|
preview_btn = tk.Button(button_frame, text="👁️ 采集卡预览",
|
||||||
|
command=start_preview,
|
||||||
|
width=30, height=3, font=('Arial', 12))
|
||||||
|
preview_btn.pack(pady=10)
|
||||||
|
|
||||||
|
# 主程序按钮
|
||||||
|
main_btn = tk.Button(button_frame, text="🚀 启动自动化",
|
||||||
|
command=start_main_program,
|
||||||
|
width=30, height=3, font=('Arial', 12))
|
||||||
|
main_btn.pack(pady=10)
|
||||||
|
|
||||||
|
# 说明
|
||||||
|
info_label = tk.Label(root,
|
||||||
|
text="提示:首次使用请先点击"配置管理"设置参数",
|
||||||
|
font=('Arial', 9),
|
||||||
|
fg='gray')
|
||||||
|
info_label.pack(side=tk.BOTTOM, pady=10)
|
||||||
|
|
||||||
|
root.mainloop()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
create_launcher()
|
||||||
|
|
||||||
193
main.py
193
main.py
@@ -1,64 +1,86 @@
|
|||||||
import cv2
|
import cv2
|
||||||
from utils.get_image import get_image
|
from utils.get_image import GetImage
|
||||||
from utils.mouse import mouse_gui
|
from utils.mouse import init_mouse_keyboard, Mouse_guiji
|
||||||
from ultralytics import YOLO
|
from ultralytics import YOLO
|
||||||
import time
|
import time
|
||||||
import serial
|
import serial
|
||||||
import ch9329Comm
|
import ch9329Comm
|
||||||
import time
|
|
||||||
import random
|
import random
|
||||||
import math
|
import math
|
||||||
from utils import shizi
|
from utils import shizi
|
||||||
|
from config import config_manager
|
||||||
|
|
||||||
|
# 加载YOLO模型
|
||||||
model = YOLO(r"best.pt").to('cuda')
|
model = YOLO(r"best.pt").to('cuda')
|
||||||
model0 = YOLO(r"best0.pt").to('cuda')
|
model0 = YOLO(r"best0.pt").to('cuda')
|
||||||
|
|
||||||
|
# 从配置加载
|
||||||
|
active_group = config_manager.get_active_group()
|
||||||
|
if active_group is None:
|
||||||
|
print("❌ 没有活动的配置组,请在gui_config.py中设置")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
print(f"📋 使用配置组: {active_group['name']}")
|
||||||
|
|
||||||
|
# 初始化串口和鼠标
|
||||||
|
init_mouse_keyboard(active_group)
|
||||||
|
|
||||||
|
# 初始化键盘和鼠标
|
||||||
keyboard = ch9329Comm.keyboard.DataComm()
|
keyboard = ch9329Comm.keyboard.DataComm()
|
||||||
mouse = ch9329Comm.mouse.DataComm(1920, 1080)
|
from utils.mouse import mouse, mouse_gui # 导入已初始化的mouse和mouse_gui
|
||||||
kong_detections = {
|
|
||||||
'center': None,
|
# 创建全局的mouse_gui实例
|
||||||
'next': None,
|
mouse_gui = Mouse_guiji()
|
||||||
'npc1': None,
|
|
||||||
'npc2': None,
|
# 初始化采集卡
|
||||||
'npc3': None,
|
get_image = GetImage(
|
||||||
'npc4': None,
|
cam_index=active_group['camera_index'],
|
||||||
'boss': None,
|
width=active_group['camera_width'],
|
||||||
'daojv': [],
|
height=active_group['camera_height']
|
||||||
'gw': [],
|
)
|
||||||
'zhaozi': None
|
|
||||||
}
|
print(f"✅ 初始化完成 - 串口:{active_group['serial_port']} 采集卡:{active_group['camera_index']}")
|
||||||
left=0
|
|
||||||
top=30
|
# 全局变量
|
||||||
k=0#控制转圈的方向
|
left = 0
|
||||||
panduan=False#是否在图内
|
top = 30
|
||||||
boss_pd=False#是否到boss关卡
|
k = 0 # 控制转圈的方向
|
||||||
rw=(632,378)
|
panduan = False # 是否在图内
|
||||||
def yolo_shibie(im_PIL,detections,model):
|
boss_pd = False # 是否到boss关卡
|
||||||
results = model(im_PIL)#目标检测
|
rw = (632, 378)
|
||||||
|
|
||||||
|
# 从配置读取移动速度
|
||||||
|
v = active_group['move_velocity']
|
||||||
|
|
||||||
|
def yolo_shibie(im_PIL, detections, model):
|
||||||
|
results = model(im_PIL) # 目标检测
|
||||||
for result in results:
|
for result in results:
|
||||||
for i in range(len(result.boxes.xyxy)):
|
for i in range(len(result.boxes.xyxy)):
|
||||||
left, top, right, bottom = result.boxes.xyxy[i]
|
left, top, right, bottom = result.boxes.xyxy[i]
|
||||||
scalar_tensor = result.boxes.cls[i]
|
scalar_tensor = result.boxes.cls[i]
|
||||||
value = scalar_tensor.item()
|
value = scalar_tensor.item()
|
||||||
label = result.names[int(value)]
|
label = result.names[int(value)]
|
||||||
if label=='center'or label=='next' or label=='boss' or label=='zhaozi':
|
if label == 'center' or label == 'next' or label == 'boss' or label == 'zhaozi':
|
||||||
player_x = int(left+(right-left)/2)
|
player_x = int(left + (right - left) / 2)
|
||||||
player_y = int(top+(bottom-top)/2)+30
|
player_y = int(top + (bottom - top) / 2) + 30
|
||||||
RW = [player_x, player_y]
|
RW = [player_x, player_y]
|
||||||
detections[label] = RW
|
detections[label] = RW
|
||||||
elif label=='daojv' or label=='gw':
|
elif label == 'daojv' or label == 'gw':
|
||||||
player_x = int(left + (right - left) / 2)
|
player_x = int(left + (right - left) / 2)
|
||||||
player_y = int(top + (bottom - top) / 2) + 30
|
player_y = int(top + (bottom - top) / 2) + 30
|
||||||
RW = [player_x, player_y]
|
RW = [player_x, player_y]
|
||||||
detections[label].append(RW)
|
detections[label].append(RW)
|
||||||
elif label=='npc1' or label=='npc2' or label=='npc3' or label=='npc4':
|
elif label == 'npc1' or label == 'npc2' or label == 'npc3' or label == 'npc4':
|
||||||
player_x = int(left+(right-left)/2)
|
player_x = int(left + (right - left) / 2)
|
||||||
player_y = int(bottom)+30
|
player_y = int(bottom) + 30
|
||||||
RW = [player_x, player_y]
|
RW = [player_x, player_y]
|
||||||
detections[label] = RW
|
detections[label] = RW
|
||||||
return detections
|
return detections
|
||||||
|
|
||||||
def sq(p1, p2):
|
def sq(p1, p2):
|
||||||
"""计算两点之间的欧式距离"""
|
"""计算两点之间的欧式距离"""
|
||||||
return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
|
return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
|
||||||
|
|
||||||
def process_points(points):
|
def process_points(points):
|
||||||
if not points:
|
if not points:
|
||||||
return None # 空列表情况
|
return None # 空列表情况
|
||||||
@@ -89,9 +111,10 @@ def process_points(points):
|
|||||||
best_point = p
|
best_point = p
|
||||||
|
|
||||||
return best_point
|
return best_point
|
||||||
|
|
||||||
def move_randomly(rw, k):
|
def move_randomly(rw, k):
|
||||||
k = k % 4
|
k = k % 4
|
||||||
suiji_t=float(random.randint(10,13)/10)
|
suiji_t = float(random.randint(10, 13) / 10)
|
||||||
if k == 0:
|
if k == 0:
|
||||||
keyboard.send_data("66")
|
keyboard.send_data("66")
|
||||||
time.sleep(suiji_t)
|
time.sleep(suiji_t)
|
||||||
@@ -109,18 +132,21 @@ def move_randomly(rw, k):
|
|||||||
time.sleep(suiji_t)
|
time.sleep(suiji_t)
|
||||||
keyboard.release() # Release
|
keyboard.release() # Release
|
||||||
return k + 1
|
return k + 1
|
||||||
def move_to(rw,mb):
|
|
||||||
v=470
|
def move_to(rw, mb):
|
||||||
if rw[0]>=mb[0]:
|
"""使用配置的v值"""
|
||||||
|
global v
|
||||||
|
v = active_group['move_velocity'] # 每次都从配置读取最新值
|
||||||
|
if rw[0] >= mb[0]:
|
||||||
keyboard.send_data("44")
|
keyboard.send_data("44")
|
||||||
time.sleep(float(abs(rw[0]-mb[0])/v))
|
time.sleep(float(abs(rw[0] - mb[0]) / v))
|
||||||
keyboard.release() # Release
|
keyboard.release() # Release
|
||||||
else:
|
else:
|
||||||
keyboard.send_data("66")
|
keyboard.send_data("66")
|
||||||
time.sleep(float(abs(rw[0] - mb[0]) / v))
|
time.sleep(float(abs(rw[0] - mb[0]) / v))
|
||||||
keyboard.release() # Release
|
keyboard.release() # Release
|
||||||
|
|
||||||
if rw[1]>=mb[1]:
|
if rw[1] >= mb[1]:
|
||||||
keyboard.send_data("88")
|
keyboard.send_data("88")
|
||||||
time.sleep(float(abs(rw[1] - mb[1]) / v))
|
time.sleep(float(abs(rw[1] - mb[1]) / v))
|
||||||
keyboard.release() # Release
|
keyboard.release() # Release
|
||||||
@@ -128,7 +154,9 @@ def move_to(rw,mb):
|
|||||||
keyboard.send_data("22")
|
keyboard.send_data("22")
|
||||||
time.sleep(float(abs(rw[1] - mb[1]) / v))
|
time.sleep(float(abs(rw[1] - mb[1]) / v))
|
||||||
keyboard.release()
|
keyboard.release()
|
||||||
i=0
|
|
||||||
|
i = 0
|
||||||
|
print("🚀 开始自动化...")
|
||||||
while True:
|
while True:
|
||||||
detections = {
|
detections = {
|
||||||
'center': None,
|
'center': None,
|
||||||
@@ -140,11 +168,11 @@ while True:
|
|||||||
'boss': None,
|
'boss': None,
|
||||||
'daojv': [],
|
'daojv': [],
|
||||||
'gw': [],
|
'gw': [],
|
||||||
'zhaozi':None
|
'zhaozi': None
|
||||||
|
|
||||||
}
|
}
|
||||||
im_opencv = get_image.get_frame()#[RGB,PIL]
|
im_opencv = get_image.get_frame() # [RGB,PIL]
|
||||||
detections=yolo_shibie(im_opencv[1],detections,model)
|
detections = yolo_shibie(im_opencv[1], detections, model)
|
||||||
|
|
||||||
if shizi.tuwai(im_opencv[0]): # 进图算法
|
if shizi.tuwai(im_opencv[0]): # 进图算法
|
||||||
im_opencv = get_image.get_frame() # [RGB,PIL]
|
im_opencv = get_image.get_frame() # [RGB,PIL]
|
||||||
detections = yolo_shibie(im_opencv[1], detections, model0)
|
detections = yolo_shibie(im_opencv[1], detections, model0)
|
||||||
@@ -162,7 +190,7 @@ while True:
|
|||||||
continue
|
continue
|
||||||
elif detections['npc3'] is not None and detections['npc4'] is None:
|
elif detections['npc3'] is not None and detections['npc4'] is None:
|
||||||
print("在npc3旁边,向右走")
|
print("在npc3旁边,向右走")
|
||||||
mb = (rw[0], detections['npc3'][1]-50)
|
mb = (rw[0], detections['npc3'][1] - 50)
|
||||||
move_to(rw, mb)
|
move_to(rw, mb)
|
||||||
mb = (rw[0] + 700, rw[1])
|
mb = (rw[0] + 700, rw[1])
|
||||||
move_to(rw, mb)
|
move_to(rw, mb)
|
||||||
@@ -181,7 +209,6 @@ while True:
|
|||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
print("离npc4有点远 点击进入")
|
print("离npc4有点远 点击进入")
|
||||||
|
|
||||||
move_to(rw, detections['npc4'])
|
move_to(rw, detections['npc4'])
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
im_opencv = get_image.get_frame() # [RGB,PIL]
|
im_opencv = get_image.get_frame() # [RGB,PIL]
|
||||||
@@ -189,22 +216,22 @@ while True:
|
|||||||
mouse_gui.send_data_absolute(rw[0], rw[1] - 110, may=1)
|
mouse_gui.send_data_absolute(rw[0], rw[1] - 110, may=1)
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
continue
|
continue
|
||||||
elif shizi.tiaozhan(im_opencv[0]):#开启挑战
|
elif shizi.tiaozhan(im_opencv[0]): # 开启挑战
|
||||||
print('进入塔4')
|
print('进入塔4')
|
||||||
mouse_gui.send_data_absolute(left+1100,top+600,may=1)
|
mouse_gui.send_data_absolute(left + 1100, top + 600, may=1)
|
||||||
time.sleep(0.3)
|
time.sleep(0.3)
|
||||||
mouse_gui.send_data_absolute(left + 433, top + 455,may=1)
|
mouse_gui.send_data_absolute(left + 433, top + 455, may=1)
|
||||||
panduan = True
|
panduan = True
|
||||||
continue
|
continue
|
||||||
elif shizi.jieshu(im_opencv[0]):#结束挑战
|
elif shizi.jieshu(im_opencv[0]): # 结束挑战
|
||||||
print('结束挑战')
|
print('结束挑战')
|
||||||
mouse_gui.send_data_absolute(left+542,top+644,may=1)
|
mouse_gui.send_data_absolute(left + 542, top + 644, may=1)
|
||||||
time.sleep(0.8)
|
time.sleep(0.8)
|
||||||
mouse_gui.send_data_absolute(left + 706, top + 454,may=1)
|
mouse_gui.send_data_absolute(left + 706, top + 454, may=1)
|
||||||
continue
|
continue
|
||||||
elif panduan :#图内情况
|
elif panduan: # 图内情况
|
||||||
print("在图内")
|
print("在图内")
|
||||||
if shizi.shuzi(im_opencv[0]) :
|
if shizi.shuzi(im_opencv[0]):
|
||||||
boss_pd = True
|
boss_pd = True
|
||||||
print("进入到boss!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
|
print("进入到boss!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
|
||||||
if shizi.fuhuo(im_opencv[0]):
|
if shizi.fuhuo(im_opencv[0]):
|
||||||
@@ -213,21 +240,21 @@ while True:
|
|||||||
mouse_gui.send_data_absolute(rw[0], rw[1], may=0)
|
mouse_gui.send_data_absolute(rw[0], rw[1], may=0)
|
||||||
continue
|
continue
|
||||||
if detections['zhaozi'] is not None:
|
if detections['zhaozi'] is not None:
|
||||||
move_to(rw,detections['zhaozi'])
|
move_to(rw, detections['zhaozi'])
|
||||||
continue
|
continue
|
||||||
if len(detections['daojv'])!=0:
|
if len(detections['daojv']) != 0:
|
||||||
move_to(rw,process_points(detections['daojv']))
|
move_to(rw, process_points(detections['daojv']))
|
||||||
for i in range(3+len(detections['daojv'])):
|
for i in range(3 + len(detections['daojv'])):
|
||||||
keyboard.send_data("AA")
|
keyboard.send_data("AA")
|
||||||
time.sleep(0.15)
|
time.sleep(0.15)
|
||||||
keyboard.release()
|
keyboard.release()
|
||||||
continue
|
continue
|
||||||
if shizi.tuichu(im_opencv[0]) and detections['next'] is None and len(detections['daojv'])==0 and len(detections['gw'])==0 and boss_pd:
|
if shizi.tuichu(im_opencv[0]) and detections['next'] is None and len(detections['daojv']) == 0 and len(detections['gw']) == 0 and boss_pd:
|
||||||
print("识别到可以退出挑战!!!!!!!!!!!!!!!!!!")
|
print("识别到可以退出挑战!!!!!!!!!!!!!!!!!!")
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
|
||||||
im_opencv = get_image.get_frame()#[RGB,PIL]
|
im_opencv = get_image.get_frame() # [RGB,PIL]
|
||||||
detections = {
|
detections = {
|
||||||
'center': None,
|
'center': None,
|
||||||
'next': None,
|
'next': None,
|
||||||
@@ -239,52 +266,49 @@ while True:
|
|||||||
'daojv': [],
|
'daojv': [],
|
||||||
'gw': [],
|
'gw': [],
|
||||||
'zhaozi': None
|
'zhaozi': None
|
||||||
|
|
||||||
}
|
}
|
||||||
detections = yolo_shibie(im_opencv[1], detections,model)
|
detections = yolo_shibie(im_opencv[1], detections, model)
|
||||||
if detections['next'] is not None or len(detections['daojv'])!=0 or len(detections['gw'])!=0 or detections['boss'] is not None:
|
if detections['next'] is not None or len(detections['daojv']) != 0 or len(detections['gw']) != 0 or detections['boss'] is not None:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
mouse_gui.send_data_absolute(left + 640, top + 40,may=1)#点击退出
|
mouse_gui.send_data_absolute(left + 640, top + 40, may=1) # 点击退出
|
||||||
panduan = False#退出挑战
|
panduan = False # 退出挑战
|
||||||
boss_pd = False
|
boss_pd = False
|
||||||
time.sleep(2.0)
|
time.sleep(2.0)
|
||||||
continue
|
continue
|
||||||
if detections['center'] is None and detections['next'] is None and (len(detections['gw'])!=0 or detections["boss"] is not None):#识别不到中心情况 但是有怪物
|
if detections['center'] is None and detections['next'] is None and (len(detections['gw']) != 0 or detections["boss"] is not None): # 识别不到中心情况 但是有怪物
|
||||||
print("未检测到中心点,但是有怪物")
|
print("未检测到中心点,但是有怪物")
|
||||||
if len(detections['gw'])!=0:
|
if len(detections['gw']) != 0:
|
||||||
move_to(rw,detections['gw'][0])
|
move_to(rw, detections['gw'][0])
|
||||||
time.sleep(0.26)
|
time.sleep(0.26)
|
||||||
elif detections['boss'] is not None:#跟随boss
|
elif detections['boss'] is not None: # 跟随boss
|
||||||
boss_suiji1=random.randint(-30,30)
|
boss_suiji1 = random.randint(-30, 30)
|
||||||
boss_suiji2 = random.randint(-30, 30)
|
boss_suiji2 = random.randint(-30, 30)
|
||||||
detections['boss']=(detections['boss'][0]+boss_suiji1,detections['boss'][1]+boss_suiji2)
|
detections['boss'] = (detections['boss'][0] + boss_suiji1, detections['boss'][1] + boss_suiji2)
|
||||||
move_to(rw,detections['boss'])
|
move_to(rw, detections['boss'])
|
||||||
time.sleep(0.7)
|
time.sleep(0.7)
|
||||||
continue
|
continue
|
||||||
elif (detections['center'] is not None and detections['next'] is None and len(detections['gw'])!=0) or (boss_pd==True and detections['center'] is not None and detections['next'] is None) :#识别到中心 但是有怪物
|
elif (detections['center'] is not None and detections['next'] is None and len(detections['gw']) != 0) or (boss_pd == True and detections['center'] is not None and detections['next'] is None): # 识别到中心 但是有怪物
|
||||||
if detections['center'][0]>=rw[0] and detections['center'][1]<rw[1]:#3
|
if detections['center'][0] >= rw[0] and detections['center'][1] < rw[1]: # 3
|
||||||
mb=(rw[0]+100,rw[1])
|
mb = (rw[0] + 100, rw[1])
|
||||||
elif detections['center'][0]<=rw[0] and detections['center'][1]<rw[1]:#4
|
elif detections['center'][0] <= rw[0] and detections['center'][1] < rw[1]: # 4
|
||||||
mb=(rw[0], rw[1]-100)
|
mb = (rw[0], rw[1] - 100)
|
||||||
elif detections['center'][0]<=rw[0] and detections['center'][1]>rw[1]:#1
|
elif detections['center'][0] <= rw[0] and detections['center'][1] > rw[1]: # 1
|
||||||
mb=(rw[0]-100, rw[1])
|
mb = (rw[0] - 100, rw[1])
|
||||||
elif detections['center'][0]>=rw[0] and detections['center'][1]>rw[1]:#2
|
elif detections['center'][0] >= rw[0] and detections['center'][1] > rw[1]: # 2
|
||||||
mb=(rw[0], rw[1]+100)
|
mb = (rw[0], rw[1] + 100)
|
||||||
move_to(rw, mb)
|
move_to(rw, mb)
|
||||||
time.sleep(0.25)
|
time.sleep(0.25)
|
||||||
|
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
elif boss_pd==True and detections['center'] is None and detections['next'] is None:#boss出现了 但是没有中心
|
elif boss_pd == True and detections['center'] is None and detections['next'] is None: # boss出现了 但是没有中心
|
||||||
k=move_randomly(rw,k)
|
k = move_randomly(rw, k)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
elif detections['next'] is not None:
|
elif detections['next'] is not None:
|
||||||
print('进入下一层啦啦啦啦啦啦')
|
print('进入下一层啦啦啦啦啦啦')
|
||||||
panduan = True
|
panduan = True
|
||||||
move_to(rw,detections['next'])
|
move_to(rw, detections['next'])
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
keyboard.send_data("DD")
|
keyboard.send_data("DD")
|
||||||
time.sleep(0.15)
|
time.sleep(0.15)
|
||||||
@@ -298,3 +322,4 @@ while True:
|
|||||||
mouse_gui.send_data_absolute(rw[0], rw[1] - 110, may=1)
|
mouse_gui.send_data_absolute(rw[0], rw[1] - 110, may=1)
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|||||||
325
main_new.py
Normal file
325
main_new.py
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
import cv2
|
||||||
|
from utils.get_image import GetImage
|
||||||
|
from utils.mouse import init_mouse_keyboard, Mouse_guiji
|
||||||
|
from ultralytics import YOLO
|
||||||
|
import time
|
||||||
|
import serial
|
||||||
|
import ch9329Comm
|
||||||
|
import random
|
||||||
|
import math
|
||||||
|
from utils import shizi
|
||||||
|
from config import config_manager
|
||||||
|
|
||||||
|
# 加载YOLO模型
|
||||||
|
model = YOLO(r"best.pt").to('cuda')
|
||||||
|
model0 = YOLO(r"best0.pt").to('cuda')
|
||||||
|
|
||||||
|
# 从配置加载
|
||||||
|
active_group = config_manager.get_active_group()
|
||||||
|
if active_group is None:
|
||||||
|
print("❌ 没有活动的配置组,请在gui_config.py中设置")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
print(f"📋 使用配置组: {active_group['name']}")
|
||||||
|
|
||||||
|
# 初始化串口和鼠标
|
||||||
|
init_mouse_keyboard(active_group)
|
||||||
|
|
||||||
|
# 初始化键盘和鼠标
|
||||||
|
keyboard = ch9329Comm.keyboard.DataComm()
|
||||||
|
from utils.mouse import mouse, mouse_gui # 导入已初始化的mouse和mouse_gui
|
||||||
|
|
||||||
|
# 创建全局的mouse_gui实例
|
||||||
|
mouse_gui = Mouse_guiji()
|
||||||
|
|
||||||
|
# 初始化采集卡
|
||||||
|
get_image = GetImage(
|
||||||
|
cam_index=active_group['camera_index'],
|
||||||
|
width=active_group['camera_width'],
|
||||||
|
height=active_group['camera_height']
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"✅ 初始化完成 - 串口:{active_group['serial_port']} 采集卡:{active_group['camera_index']}")
|
||||||
|
|
||||||
|
# 全局变量
|
||||||
|
left = 0
|
||||||
|
top = 30
|
||||||
|
k = 0 # 控制转圈的方向
|
||||||
|
panduan = False # 是否在图内
|
||||||
|
boss_pd = False # 是否到boss关卡
|
||||||
|
rw = (632, 378)
|
||||||
|
|
||||||
|
# 从配置读取移动速度
|
||||||
|
v = active_group['move_velocity']
|
||||||
|
|
||||||
|
def yolo_shibie(im_PIL, detections, model):
|
||||||
|
results = model(im_PIL) # 目标检测
|
||||||
|
for result in results:
|
||||||
|
for i in range(len(result.boxes.xyxy)):
|
||||||
|
left, top, right, bottom = result.boxes.xyxy[i]
|
||||||
|
scalar_tensor = result.boxes.cls[i]
|
||||||
|
value = scalar_tensor.item()
|
||||||
|
label = result.names[int(value)]
|
||||||
|
if label == 'center' or label == 'next' or label == 'boss' or label == 'zhaozi':
|
||||||
|
player_x = int(left + (right - left) / 2)
|
||||||
|
player_y = int(top + (bottom - top) / 2) + 30
|
||||||
|
RW = [player_x, player_y]
|
||||||
|
detections[label] = RW
|
||||||
|
elif label == 'daojv' or label == 'gw':
|
||||||
|
player_x = int(left + (right - left) / 2)
|
||||||
|
player_y = int(top + (bottom - top) / 2) + 30
|
||||||
|
RW = [player_x, player_y]
|
||||||
|
detections[label].append(RW)
|
||||||
|
elif label == 'npc1' or label == 'npc2' or label == 'npc3' or label == 'npc4':
|
||||||
|
player_x = int(left + (right - left) / 2)
|
||||||
|
player_y = int(bottom) + 30
|
||||||
|
RW = [player_x, player_y]
|
||||||
|
detections[label] = RW
|
||||||
|
return detections
|
||||||
|
|
||||||
|
def sq(p1, p2):
|
||||||
|
"""计算两点之间的欧式距离"""
|
||||||
|
return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
|
||||||
|
|
||||||
|
def process_points(points):
|
||||||
|
if not points:
|
||||||
|
return None # 空列表情况
|
||||||
|
|
||||||
|
n = len(points)
|
||||||
|
|
||||||
|
if n == 1:
|
||||||
|
# 只有一个点,直接返回
|
||||||
|
return points[0]
|
||||||
|
|
||||||
|
elif n == 2:
|
||||||
|
# 两个点取中点
|
||||||
|
x = (points[0][0] + points[1][0]) / 2
|
||||||
|
y = (points[0][1] + points[1][1]) / 2
|
||||||
|
return [x, y]
|
||||||
|
|
||||||
|
else:
|
||||||
|
# 随机选3个点
|
||||||
|
sample_points = random.sample(points, 3)
|
||||||
|
|
||||||
|
# 对每个点计算到这3个点的总距离
|
||||||
|
min_sum = float('inf')
|
||||||
|
best_point = None
|
||||||
|
for p in points:
|
||||||
|
dist_sum = sum(sq(p, sp) for sp in sample_points)
|
||||||
|
if dist_sum < min_sum:
|
||||||
|
min_sum = dist_sum
|
||||||
|
best_point = p
|
||||||
|
|
||||||
|
return best_point
|
||||||
|
|
||||||
|
def move_randomly(rw, k):
|
||||||
|
k = k % 4
|
||||||
|
suiji_t = float(random.randint(10, 13) / 10)
|
||||||
|
if k == 0:
|
||||||
|
keyboard.send_data("66")
|
||||||
|
time.sleep(suiji_t)
|
||||||
|
keyboard.release() # Release
|
||||||
|
elif k == 1:
|
||||||
|
keyboard.send_data("88")
|
||||||
|
time.sleep(suiji_t)
|
||||||
|
keyboard.release() # Release
|
||||||
|
elif k == 2:
|
||||||
|
keyboard.send_data("44")
|
||||||
|
time.sleep(suiji_t)
|
||||||
|
keyboard.release() # Release
|
||||||
|
elif k == 3:
|
||||||
|
keyboard.send_data("22")
|
||||||
|
time.sleep(suiji_t)
|
||||||
|
keyboard.release() # Release
|
||||||
|
return k + 1
|
||||||
|
|
||||||
|
def move_to(rw, mb):
|
||||||
|
"""使用配置的v值"""
|
||||||
|
global v
|
||||||
|
v = active_group['move_velocity'] # 每次都从配置读取最新值
|
||||||
|
if rw[0] >= mb[0]:
|
||||||
|
keyboard.send_data("44")
|
||||||
|
time.sleep(float(abs(rw[0] - mb[0]) / v))
|
||||||
|
keyboard.release() # Release
|
||||||
|
else:
|
||||||
|
keyboard.send_data("66")
|
||||||
|
time.sleep(float(abs(rw[0] - mb[0]) / v))
|
||||||
|
keyboard.release() # Release
|
||||||
|
|
||||||
|
if rw[1] >= mb[1]:
|
||||||
|
keyboard.send_data("88")
|
||||||
|
time.sleep(float(abs(rw[1] - mb[1]) / v))
|
||||||
|
keyboard.release() # Release
|
||||||
|
else:
|
||||||
|
keyboard.send_data("22")
|
||||||
|
time.sleep(float(abs(rw[1] - mb[1]) / v))
|
||||||
|
keyboard.release()
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
print("🚀 开始自动化...")
|
||||||
|
while True:
|
||||||
|
detections = {
|
||||||
|
'center': None,
|
||||||
|
'next': None,
|
||||||
|
'npc1': None,
|
||||||
|
'npc2': None,
|
||||||
|
'npc3': None,
|
||||||
|
'npc4': None,
|
||||||
|
'boss': None,
|
||||||
|
'daojv': [],
|
||||||
|
'gw': [],
|
||||||
|
'zhaozi': None
|
||||||
|
}
|
||||||
|
im_opencv = get_image.get_frame() # [RGB,PIL]
|
||||||
|
detections = yolo_shibie(im_opencv[1], detections, model)
|
||||||
|
|
||||||
|
if shizi.tuwai(im_opencv[0]): # 进图算法
|
||||||
|
im_opencv = get_image.get_frame() # [RGB,PIL]
|
||||||
|
detections = yolo_shibie(im_opencv[1], detections, model0)
|
||||||
|
print('当前在城镇中')
|
||||||
|
if detections['npc1'] is not None and sq(rw, detections['npc1']) > 80:
|
||||||
|
print("向npc1靠近")
|
||||||
|
print(sq(rw, detections['npc1']))
|
||||||
|
move_to(rw, detections['npc1'])
|
||||||
|
continue
|
||||||
|
elif detections['npc1'] is not None and sq(rw, detections['npc1']) <= 80:
|
||||||
|
print("在npc旁边,向上走")
|
||||||
|
print(sq(rw, detections['npc1']))
|
||||||
|
mb = (detections['npc1'][0], detections['npc1'][1] - 1010)
|
||||||
|
move_to(rw, mb)
|
||||||
|
continue
|
||||||
|
elif detections['npc3'] is not None and detections['npc4'] is None:
|
||||||
|
print("在npc3旁边,向右走")
|
||||||
|
mb = (rw[0], detections['npc3'][1] - 50)
|
||||||
|
move_to(rw, mb)
|
||||||
|
mb = (rw[0] + 700, rw[1])
|
||||||
|
move_to(rw, mb)
|
||||||
|
continue
|
||||||
|
elif detections['npc4'] is not None:
|
||||||
|
if sq(detections['npc4'], rw) < 50:
|
||||||
|
print("离npc4很近 直接进入")
|
||||||
|
keyboard.send_data("DD")
|
||||||
|
time.sleep(0.15)
|
||||||
|
keyboard.release()
|
||||||
|
time.sleep(1)
|
||||||
|
im_opencv = get_image.get_frame() # [RGB,PIL]
|
||||||
|
if shizi.daoying(im_opencv[0]):
|
||||||
|
mouse_gui.send_data_absolute(rw[0], rw[1] - 110, may=1)
|
||||||
|
time.sleep(1)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
print("离npc4有点远 点击进入")
|
||||||
|
move_to(rw, detections['npc4'])
|
||||||
|
time.sleep(1)
|
||||||
|
im_opencv = get_image.get_frame() # [RGB,PIL]
|
||||||
|
if shizi.daoying(im_opencv[0]):
|
||||||
|
mouse_gui.send_data_absolute(rw[0], rw[1] - 110, may=1)
|
||||||
|
time.sleep(1)
|
||||||
|
continue
|
||||||
|
elif shizi.tiaozhan(im_opencv[0]): # 开启挑战
|
||||||
|
print('进入塔4')
|
||||||
|
mouse_gui.send_data_absolute(left + 1100, top + 600, may=1)
|
||||||
|
time.sleep(0.3)
|
||||||
|
mouse_gui.send_data_absolute(left + 433, top + 455, may=1)
|
||||||
|
panduan = True
|
||||||
|
continue
|
||||||
|
elif shizi.jieshu(im_opencv[0]): # 结束挑战
|
||||||
|
print('结束挑战')
|
||||||
|
mouse_gui.send_data_absolute(left + 542, top + 644, may=1)
|
||||||
|
time.sleep(0.8)
|
||||||
|
mouse_gui.send_data_absolute(left + 706, top + 454, may=1)
|
||||||
|
continue
|
||||||
|
elif panduan: # 图内情况
|
||||||
|
print("在图内")
|
||||||
|
if shizi.shuzi(im_opencv[0]):
|
||||||
|
boss_pd = True
|
||||||
|
print("进入到boss!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
|
||||||
|
if shizi.fuhuo(im_opencv[0]):
|
||||||
|
print('点击复活')
|
||||||
|
mouse_gui.send_data_absolute(left + 536, top + 627, may=1)
|
||||||
|
mouse_gui.send_data_absolute(rw[0], rw[1], may=0)
|
||||||
|
continue
|
||||||
|
if detections['zhaozi'] is not None:
|
||||||
|
move_to(rw, detections['zhaozi'])
|
||||||
|
continue
|
||||||
|
if len(detections['daojv']) != 0:
|
||||||
|
move_to(rw, process_points(detections['daojv']))
|
||||||
|
for i in range(3 + len(detections['daojv'])):
|
||||||
|
keyboard.send_data("AA")
|
||||||
|
time.sleep(0.15)
|
||||||
|
keyboard.release()
|
||||||
|
continue
|
||||||
|
if shizi.tuichu(im_opencv[0]) and detections['next'] is None and len(detections['daojv']) == 0 and len(detections['gw']) == 0 and boss_pd:
|
||||||
|
print("识别到可以退出挑战!!!!!!!!!!!!!!!!!!")
|
||||||
|
for i in range(3):
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
im_opencv = get_image.get_frame() # [RGB,PIL]
|
||||||
|
detections = {
|
||||||
|
'center': None,
|
||||||
|
'next': None,
|
||||||
|
'npc1': None,
|
||||||
|
'npc2': None,
|
||||||
|
'npc3': None,
|
||||||
|
'npc4': None,
|
||||||
|
'boss': None,
|
||||||
|
'daojv': [],
|
||||||
|
'gw': [],
|
||||||
|
'zhaozi': None
|
||||||
|
}
|
||||||
|
detections = yolo_shibie(im_opencv[1], detections, model)
|
||||||
|
if detections['next'] is not None or len(detections['daojv']) != 0 or len(detections['gw']) != 0 or detections['boss'] is not None:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
mouse_gui.send_data_absolute(left + 640, top + 40, may=1) # 点击退出
|
||||||
|
panduan = False # 退出挑战
|
||||||
|
boss_pd = False
|
||||||
|
time.sleep(2.0)
|
||||||
|
continue
|
||||||
|
if detections['center'] is None and detections['next'] is None and (len(detections['gw']) != 0 or detections["boss"] is not None): # 识别不到中心情况 但是有怪物
|
||||||
|
print("未检测到中心点,但是有怪物")
|
||||||
|
if len(detections['gw']) != 0:
|
||||||
|
move_to(rw, detections['gw'][0])
|
||||||
|
time.sleep(0.26)
|
||||||
|
elif detections['boss'] is not None: # 跟随boss
|
||||||
|
boss_suiji1 = random.randint(-30, 30)
|
||||||
|
boss_suiji2 = random.randint(-30, 30)
|
||||||
|
detections['boss'] = (detections['boss'][0] + boss_suiji1, detections['boss'][1] + boss_suiji2)
|
||||||
|
move_to(rw, detections['boss'])
|
||||||
|
time.sleep(0.7)
|
||||||
|
continue
|
||||||
|
elif (detections['center'] is not None and detections['next'] is None and len(detections['gw']) != 0) or (boss_pd == True and detections['center'] is not None and detections['next'] is None): # 识别到中心 但是有怪物
|
||||||
|
if detections['center'][0] >= rw[0] and detections['center'][1] < rw[1]: # 3
|
||||||
|
mb = (rw[0] + 100, rw[1])
|
||||||
|
elif detections['center'][0] <= rw[0] and detections['center'][1] < rw[1]: # 4
|
||||||
|
mb = (rw[0], rw[1] - 100)
|
||||||
|
elif detections['center'][0] <= rw[0] and detections['center'][1] > rw[1]: # 1
|
||||||
|
mb = (rw[0] - 100, rw[1])
|
||||||
|
elif detections['center'][0] >= rw[0] and detections['center'][1] > rw[1]: # 2
|
||||||
|
mb = (rw[0], rw[1] + 100)
|
||||||
|
move_to(rw, mb)
|
||||||
|
time.sleep(0.25)
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif boss_pd == True and detections['center'] is None and detections['next'] is None: # boss出现了 但是没有中心
|
||||||
|
k = move_randomly(rw, k)
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif detections['next'] is not None:
|
||||||
|
print('进入下一层啦啦啦啦啦啦')
|
||||||
|
panduan = True
|
||||||
|
move_to(rw, detections['next'])
|
||||||
|
for i in range(2):
|
||||||
|
keyboard.send_data("DD")
|
||||||
|
time.sleep(0.15)
|
||||||
|
keyboard.release()
|
||||||
|
continue
|
||||||
|
|
||||||
|
else:
|
||||||
|
k = move_randomly(rw, k)
|
||||||
|
continue
|
||||||
|
elif shizi.daoying(im_opencv[0]):
|
||||||
|
mouse_gui.send_data_absolute(rw[0], rw[1] - 110, may=1)
|
||||||
|
time.sleep(1)
|
||||||
|
continue
|
||||||
|
|
||||||
300
main_old.py
Normal file
300
main_old.py
Normal file
@@ -0,0 +1,300 @@
|
|||||||
|
import cv2
|
||||||
|
from utils.get_image import get_image
|
||||||
|
from utils.mouse import mouse_gui
|
||||||
|
from ultralytics import YOLO
|
||||||
|
import time
|
||||||
|
import serial
|
||||||
|
import ch9329Comm
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
import math
|
||||||
|
from utils import shizi
|
||||||
|
model = YOLO(r"best.pt").to('cuda')
|
||||||
|
model0 = YOLO(r"best0.pt").to('cuda')
|
||||||
|
|
||||||
|
keyboard = ch9329Comm.keyboard.DataComm()
|
||||||
|
mouse = ch9329Comm.mouse.DataComm(1920, 1080)
|
||||||
|
kong_detections = {
|
||||||
|
'center': None,
|
||||||
|
'next': None,
|
||||||
|
'npc1': None,
|
||||||
|
'npc2': None,
|
||||||
|
'npc3': None,
|
||||||
|
'npc4': None,
|
||||||
|
'boss': None,
|
||||||
|
'daojv': [],
|
||||||
|
'gw': [],
|
||||||
|
'zhaozi': None
|
||||||
|
}
|
||||||
|
left=0
|
||||||
|
top=30
|
||||||
|
k=0#控制转圈的方向
|
||||||
|
panduan=False#是否在图内
|
||||||
|
boss_pd=False#是否到boss关卡
|
||||||
|
rw=(632,378)
|
||||||
|
def yolo_shibie(im_PIL,detections,model):
|
||||||
|
results = model(im_PIL)#目标检测
|
||||||
|
for result in results:
|
||||||
|
for i in range(len(result.boxes.xyxy)):
|
||||||
|
left, top, right, bottom = result.boxes.xyxy[i]
|
||||||
|
scalar_tensor = result.boxes.cls[i]
|
||||||
|
value = scalar_tensor.item()
|
||||||
|
label = result.names[int(value)]
|
||||||
|
if label=='center'or label=='next' or label=='boss' or label=='zhaozi':
|
||||||
|
player_x = int(left+(right-left)/2)
|
||||||
|
player_y = int(top+(bottom-top)/2)+30
|
||||||
|
RW = [player_x, player_y]
|
||||||
|
detections[label] = RW
|
||||||
|
elif label=='daojv' or label=='gw':
|
||||||
|
player_x = int(left + (right - left) / 2)
|
||||||
|
player_y = int(top + (bottom - top) / 2) + 30
|
||||||
|
RW = [player_x, player_y]
|
||||||
|
detections[label].append(RW)
|
||||||
|
elif label=='npc1' or label=='npc2' or label=='npc3' or label=='npc4':
|
||||||
|
player_x = int(left+(right-left)/2)
|
||||||
|
player_y = int(bottom)+30
|
||||||
|
RW = [player_x, player_y]
|
||||||
|
detections[label] = RW
|
||||||
|
return detections
|
||||||
|
def sq(p1, p2):
|
||||||
|
"""计算两点之间的欧式距离"""
|
||||||
|
return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
|
||||||
|
def process_points(points):
|
||||||
|
if not points:
|
||||||
|
return None # 空列表情况
|
||||||
|
|
||||||
|
n = len(points)
|
||||||
|
|
||||||
|
if n == 1:
|
||||||
|
# 只有一个点,直接返回
|
||||||
|
return points[0]
|
||||||
|
|
||||||
|
elif n == 2:
|
||||||
|
# 两个点取中点
|
||||||
|
x = (points[0][0] + points[1][0]) / 2
|
||||||
|
y = (points[0][1] + points[1][1]) / 2
|
||||||
|
return [x, y]
|
||||||
|
|
||||||
|
else:
|
||||||
|
# 随机选3个点
|
||||||
|
sample_points = random.sample(points, 3)
|
||||||
|
|
||||||
|
# 对每个点计算到这3个点的总距离
|
||||||
|
min_sum = float('inf')
|
||||||
|
best_point = None
|
||||||
|
for p in points:
|
||||||
|
dist_sum = sum(sq(p, sp) for sp in sample_points)
|
||||||
|
if dist_sum < min_sum:
|
||||||
|
min_sum = dist_sum
|
||||||
|
best_point = p
|
||||||
|
|
||||||
|
return best_point
|
||||||
|
def move_randomly(rw, k):
|
||||||
|
k = k % 4
|
||||||
|
suiji_t=float(random.randint(10,13)/10)
|
||||||
|
if k == 0:
|
||||||
|
keyboard.send_data("66")
|
||||||
|
time.sleep(suiji_t)
|
||||||
|
keyboard.release() # Release
|
||||||
|
elif k == 1:
|
||||||
|
keyboard.send_data("88")
|
||||||
|
time.sleep(suiji_t)
|
||||||
|
keyboard.release() # Release
|
||||||
|
elif k == 2:
|
||||||
|
keyboard.send_data("44")
|
||||||
|
time.sleep(suiji_t)
|
||||||
|
keyboard.release() # Release
|
||||||
|
elif k == 3:
|
||||||
|
keyboard.send_data("22")
|
||||||
|
time.sleep(suiji_t)
|
||||||
|
keyboard.release() # Release
|
||||||
|
return k + 1
|
||||||
|
def move_to(rw,mb):
|
||||||
|
v=470
|
||||||
|
if rw[0]>=mb[0]:
|
||||||
|
keyboard.send_data("44")
|
||||||
|
time.sleep(float(abs(rw[0]-mb[0])/v))
|
||||||
|
keyboard.release() # Release
|
||||||
|
else:
|
||||||
|
keyboard.send_data("66")
|
||||||
|
time.sleep(float(abs(rw[0] - mb[0]) / v))
|
||||||
|
keyboard.release() # Release
|
||||||
|
|
||||||
|
if rw[1]>=mb[1]:
|
||||||
|
keyboard.send_data("88")
|
||||||
|
time.sleep(float(abs(rw[1] - mb[1]) / v))
|
||||||
|
keyboard.release() # Release
|
||||||
|
else:
|
||||||
|
keyboard.send_data("22")
|
||||||
|
time.sleep(float(abs(rw[1] - mb[1]) / v))
|
||||||
|
keyboard.release()
|
||||||
|
i=0
|
||||||
|
while True:
|
||||||
|
detections = {
|
||||||
|
'center': None,
|
||||||
|
'next': None,
|
||||||
|
'npc1': None,
|
||||||
|
'npc2': None,
|
||||||
|
'npc3': None,
|
||||||
|
'npc4': None,
|
||||||
|
'boss': None,
|
||||||
|
'daojv': [],
|
||||||
|
'gw': [],
|
||||||
|
'zhaozi':None
|
||||||
|
|
||||||
|
}
|
||||||
|
im_opencv = get_image.get_frame()#[RGB,PIL]
|
||||||
|
detections=yolo_shibie(im_opencv[1],detections,model)
|
||||||
|
if shizi.tuwai(im_opencv[0]): # 进图算法
|
||||||
|
im_opencv = get_image.get_frame() # [RGB,PIL]
|
||||||
|
detections = yolo_shibie(im_opencv[1], detections, model0)
|
||||||
|
print('当前在城镇中')
|
||||||
|
if detections['npc1'] is not None and sq(rw, detections['npc1']) > 80:
|
||||||
|
print("向npc1靠近")
|
||||||
|
print(sq(rw, detections['npc1']))
|
||||||
|
move_to(rw, detections['npc1'])
|
||||||
|
continue
|
||||||
|
elif detections['npc1'] is not None and sq(rw, detections['npc1']) <= 80:
|
||||||
|
print("在npc旁边,向上走")
|
||||||
|
print(sq(rw, detections['npc1']))
|
||||||
|
mb = (detections['npc1'][0], detections['npc1'][1] - 1010)
|
||||||
|
move_to(rw, mb)
|
||||||
|
continue
|
||||||
|
elif detections['npc3'] is not None and detections['npc4'] is None:
|
||||||
|
print("在npc3旁边,向右走")
|
||||||
|
mb = (rw[0], detections['npc3'][1]-50)
|
||||||
|
move_to(rw, mb)
|
||||||
|
mb = (rw[0] + 700, rw[1])
|
||||||
|
move_to(rw, mb)
|
||||||
|
continue
|
||||||
|
elif detections['npc4'] is not None:
|
||||||
|
if sq(detections['npc4'], rw) < 50:
|
||||||
|
print("离npc4很近 直接进入")
|
||||||
|
keyboard.send_data("DD")
|
||||||
|
time.sleep(0.15)
|
||||||
|
keyboard.release()
|
||||||
|
time.sleep(1)
|
||||||
|
im_opencv = get_image.get_frame() # [RGB,PIL]
|
||||||
|
if shizi.daoying(im_opencv[0]):
|
||||||
|
mouse_gui.send_data_absolute(rw[0], rw[1] - 110, may=1)
|
||||||
|
time.sleep(1)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
print("离npc4有点远 点击进入")
|
||||||
|
|
||||||
|
move_to(rw, detections['npc4'])
|
||||||
|
time.sleep(1)
|
||||||
|
im_opencv = get_image.get_frame() # [RGB,PIL]
|
||||||
|
if shizi.daoying(im_opencv[0]):
|
||||||
|
mouse_gui.send_data_absolute(rw[0], rw[1] - 110, may=1)
|
||||||
|
time.sleep(1)
|
||||||
|
continue
|
||||||
|
elif shizi.tiaozhan(im_opencv[0]):#开启挑战
|
||||||
|
print('进入塔4')
|
||||||
|
mouse_gui.send_data_absolute(left+1100,top+600,may=1)
|
||||||
|
time.sleep(0.3)
|
||||||
|
mouse_gui.send_data_absolute(left + 433, top + 455,may=1)
|
||||||
|
panduan = True
|
||||||
|
continue
|
||||||
|
elif shizi.jieshu(im_opencv[0]):#结束挑战
|
||||||
|
print('结束挑战')
|
||||||
|
mouse_gui.send_data_absolute(left+542,top+644,may=1)
|
||||||
|
time.sleep(0.8)
|
||||||
|
mouse_gui.send_data_absolute(left + 706, top + 454,may=1)
|
||||||
|
continue
|
||||||
|
elif panduan :#图内情况
|
||||||
|
print("在图内")
|
||||||
|
if shizi.shuzi(im_opencv[0]) :
|
||||||
|
boss_pd = True
|
||||||
|
print("进入到boss!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
|
||||||
|
if shizi.fuhuo(im_opencv[0]):
|
||||||
|
print('点击复活')
|
||||||
|
mouse_gui.send_data_absolute(left + 536, top + 627, may=1)
|
||||||
|
mouse_gui.send_data_absolute(rw[0], rw[1], may=0)
|
||||||
|
continue
|
||||||
|
if detections['zhaozi'] is not None:
|
||||||
|
move_to(rw,detections['zhaozi'])
|
||||||
|
continue
|
||||||
|
if len(detections['daojv'])!=0:
|
||||||
|
move_to(rw,process_points(detections['daojv']))
|
||||||
|
for i in range(3+len(detections['daojv'])):
|
||||||
|
keyboard.send_data("AA")
|
||||||
|
time.sleep(0.15)
|
||||||
|
keyboard.release()
|
||||||
|
continue
|
||||||
|
if shizi.tuichu(im_opencv[0]) and detections['next'] is None and len(detections['daojv'])==0 and len(detections['gw'])==0 and boss_pd:
|
||||||
|
print("识别到可以退出挑战!!!!!!!!!!!!!!!!!!")
|
||||||
|
for i in range(3):
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
im_opencv = get_image.get_frame()#[RGB,PIL]
|
||||||
|
detections = {
|
||||||
|
'center': None,
|
||||||
|
'next': None,
|
||||||
|
'npc1': None,
|
||||||
|
'npc2': None,
|
||||||
|
'npc3': None,
|
||||||
|
'npc4': None,
|
||||||
|
'boss': None,
|
||||||
|
'daojv': [],
|
||||||
|
'gw': [],
|
||||||
|
'zhaozi': None
|
||||||
|
|
||||||
|
}
|
||||||
|
detections = yolo_shibie(im_opencv[1], detections,model)
|
||||||
|
if detections['next'] is not None or len(detections['daojv'])!=0 or len(detections['gw'])!=0 or detections['boss'] is not None:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
mouse_gui.send_data_absolute(left + 640, top + 40,may=1)#点击退出
|
||||||
|
panduan = False#退出挑战
|
||||||
|
boss_pd = False
|
||||||
|
time.sleep(2.0)
|
||||||
|
continue
|
||||||
|
if detections['center'] is None and detections['next'] is None and (len(detections['gw'])!=0 or detections["boss"] is not None):#识别不到中心情况 但是有怪物
|
||||||
|
print("未检测到中心点,但是有怪物")
|
||||||
|
if len(detections['gw'])!=0:
|
||||||
|
move_to(rw,detections['gw'][0])
|
||||||
|
time.sleep(0.26)
|
||||||
|
elif detections['boss'] is not None:#跟随boss
|
||||||
|
boss_suiji1=random.randint(-30,30)
|
||||||
|
boss_suiji2 = random.randint(-30, 30)
|
||||||
|
detections['boss']=(detections['boss'][0]+boss_suiji1,detections['boss'][1]+boss_suiji2)
|
||||||
|
move_to(rw,detections['boss'])
|
||||||
|
time.sleep(0.7)
|
||||||
|
continue
|
||||||
|
elif (detections['center'] is not None and detections['next'] is None and len(detections['gw'])!=0) or (boss_pd==True and detections['center'] is not None and detections['next'] is None) :#识别到中心 但是有怪物
|
||||||
|
if detections['center'][0]>=rw[0] and detections['center'][1]<rw[1]:#3
|
||||||
|
mb=(rw[0]+100,rw[1])
|
||||||
|
elif detections['center'][0]<=rw[0] and detections['center'][1]<rw[1]:#4
|
||||||
|
mb=(rw[0], rw[1]-100)
|
||||||
|
elif detections['center'][0]<=rw[0] and detections['center'][1]>rw[1]:#1
|
||||||
|
mb=(rw[0]-100, rw[1])
|
||||||
|
elif detections['center'][0]>=rw[0] and detections['center'][1]>rw[1]:#2
|
||||||
|
mb=(rw[0], rw[1]+100)
|
||||||
|
move_to(rw, mb)
|
||||||
|
time.sleep(0.25)
|
||||||
|
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif boss_pd==True and detections['center'] is None and detections['next'] is None:#boss出现了 但是没有中心
|
||||||
|
k=move_randomly(rw,k)
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif detections['next'] is not None:
|
||||||
|
print('进入下一层啦啦啦啦啦啦')
|
||||||
|
panduan = True
|
||||||
|
move_to(rw,detections['next'])
|
||||||
|
for i in range(2):
|
||||||
|
keyboard.send_data("DD")
|
||||||
|
time.sleep(0.15)
|
||||||
|
keyboard.release()
|
||||||
|
continue
|
||||||
|
|
||||||
|
else:
|
||||||
|
k = move_randomly(rw, k)
|
||||||
|
continue
|
||||||
|
elif shizi.daoying(im_opencv[0]):
|
||||||
|
mouse_gui.send_data_absolute(rw[0], rw[1] - 110, may=1)
|
||||||
|
time.sleep(1)
|
||||||
|
continue
|
||||||
229
preview.py
Normal file
229
preview.py
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
import cv2
|
||||||
|
import tkinter as tk
|
||||||
|
from tkinter import Canvas
|
||||||
|
from PIL import Image, ImageTk
|
||||||
|
import threading
|
||||||
|
import numpy as np
|
||||||
|
from config import config_manager
|
||||||
|
|
||||||
|
class PreviewWindow:
|
||||||
|
"""采集卡预览窗口"""
|
||||||
|
def __init__(self):
|
||||||
|
self.config = config_manager.config
|
||||||
|
self.caps = {}
|
||||||
|
self.frames = {}
|
||||||
|
self.large_window = None
|
||||||
|
self.running = True
|
||||||
|
|
||||||
|
def init_cameras(self):
|
||||||
|
"""初始化所有相机"""
|
||||||
|
for i, group in enumerate(self.config['groups']):
|
||||||
|
if group.get('active', True): # 只加载活动的配置
|
||||||
|
try:
|
||||||
|
cap = cv2.VideoCapture(group['camera_index'], cv2.CAP_DSHOW)
|
||||||
|
if cap.isOpened():
|
||||||
|
cap.set(cv2.CAP_PROP_FRAME_WIDTH, group['camera_width'])
|
||||||
|
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, group['camera_height'])
|
||||||
|
self.caps[i] = {
|
||||||
|
'cap': cap,
|
||||||
|
'group': group,
|
||||||
|
'name': group['name']
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
print(f"无法打开相机 {group['camera_index']}: {e}")
|
||||||
|
|
||||||
|
def capture_frames(self):
|
||||||
|
"""捕获帧"""
|
||||||
|
while self.running:
|
||||||
|
for idx, data in self.caps.items():
|
||||||
|
ret, frame = data['cap'].read()
|
||||||
|
if ret:
|
||||||
|
# 裁剪到配置的区域
|
||||||
|
height, width = frame.shape[:2]
|
||||||
|
crop_top = 30
|
||||||
|
crop_bottom = min(crop_top + 720, height)
|
||||||
|
crop_width = min(1280, width)
|
||||||
|
frame = frame[crop_top:crop_bottom, 0:crop_width]
|
||||||
|
|
||||||
|
# 转换颜色空间
|
||||||
|
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||||||
|
self.frames[idx] = frame_rgb
|
||||||
|
|
||||||
|
def create_grid_window(self):
|
||||||
|
"""创建网格窗口"""
|
||||||
|
root = tk.Tk()
|
||||||
|
root.title("采集卡预览 - 点击放大")
|
||||||
|
root.geometry("1000x700")
|
||||||
|
|
||||||
|
# 获取显示配置
|
||||||
|
display = self.config.get('display', {})
|
||||||
|
preview_width = display.get('preview_width', 640)
|
||||||
|
preview_height = display.get('preview_height', 360)
|
||||||
|
columns = display.get('preview_columns', 2)
|
||||||
|
rows = display.get('preview_rows', 2)
|
||||||
|
|
||||||
|
canvas = Canvas(root, bg='black')
|
||||||
|
canvas.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
# 存储图像对象
|
||||||
|
self.photo_objects = {}
|
||||||
|
|
||||||
|
def update_frames():
|
||||||
|
"""更新帧"""
|
||||||
|
while self.running:
|
||||||
|
try:
|
||||||
|
canvas.delete("all")
|
||||||
|
|
||||||
|
# 计算每个预览窗口的位置和大小
|
||||||
|
window_width = root.winfo_width() if root.winfo_width() > 1 else 1000
|
||||||
|
window_height = root.winfo_height() if root.winfo_height() > 1 else 700
|
||||||
|
|
||||||
|
cell_width = window_width // columns
|
||||||
|
cell_height = window_height // rows
|
||||||
|
|
||||||
|
frame_idx = 0
|
||||||
|
for idx in self.caps.keys():
|
||||||
|
if idx in self.frames:
|
||||||
|
row = frame_idx // columns
|
||||||
|
col = frame_idx % columns
|
||||||
|
|
||||||
|
x = col * cell_width
|
||||||
|
y = row * cell_height
|
||||||
|
|
||||||
|
# 调整图像大小
|
||||||
|
frame = self.frames[idx]
|
||||||
|
h, w = frame.shape[:2]
|
||||||
|
scale = min(cell_width / w, cell_height / h) * 0.9
|
||||||
|
new_w = int(w * scale)
|
||||||
|
new_h = int(h * scale)
|
||||||
|
|
||||||
|
resized_frame = cv2.resize(frame, (new_w, new_h))
|
||||||
|
|
||||||
|
# 转换为PIL图像
|
||||||
|
pil_image = Image.fromarray(resized_frame)
|
||||||
|
photo = ImageTk.PhotoImage(image=pil_image)
|
||||||
|
self.photo_objects[idx] = photo
|
||||||
|
|
||||||
|
# 绘制图像
|
||||||
|
center_x = x + cell_width // 2
|
||||||
|
center_y = y + cell_height // 2
|
||||||
|
canvas.create_image(center_x, center_y, image=photo, anchor='center')
|
||||||
|
|
||||||
|
# 绘制标签
|
||||||
|
name = self.caps[idx]['name']
|
||||||
|
canvas.create_text(center_x, y + 20, text=name, fill='white', font=('Arial', 12, 'bold'))
|
||||||
|
|
||||||
|
frame_idx += 1
|
||||||
|
|
||||||
|
canvas.update()
|
||||||
|
tk._default_root.update_idletasks()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"更新帧错误: {e}")
|
||||||
|
|
||||||
|
import time
|
||||||
|
time.sleep(0.03) # 约30fps
|
||||||
|
|
||||||
|
def on_canvas_click(event):
|
||||||
|
"""点击画布事件"""
|
||||||
|
window_width = root.winfo_width()
|
||||||
|
window_height = root.winfo_height()
|
||||||
|
cell_width = window_width // columns
|
||||||
|
cell_height = window_height // rows
|
||||||
|
|
||||||
|
col = int(event.x // cell_width)
|
||||||
|
row = int(event.y // cell_height)
|
||||||
|
index = row * columns + col
|
||||||
|
|
||||||
|
# 找到对应的配置
|
||||||
|
if index < len(self.caps):
|
||||||
|
idx = list(self.caps.keys())[index]
|
||||||
|
self.show_large_window(idx)
|
||||||
|
|
||||||
|
canvas.bind('<Button-1>', on_canvas_click)
|
||||||
|
|
||||||
|
# 启动更新线程
|
||||||
|
update_thread = threading.Thread(target=update_frames, daemon=True)
|
||||||
|
update_thread.start()
|
||||||
|
|
||||||
|
def on_closing():
|
||||||
|
"""关闭窗口"""
|
||||||
|
self.running = False
|
||||||
|
for data in self.caps.values():
|
||||||
|
data['cap'].release()
|
||||||
|
root.destroy()
|
||||||
|
|
||||||
|
root.protocol("WM_DELETE_WINDOW", on_closing)
|
||||||
|
root.mainloop()
|
||||||
|
|
||||||
|
def show_large_window(self, idx):
|
||||||
|
"""显示大窗口"""
|
||||||
|
if self.large_window is not None and self.large_window.winfo_exists():
|
||||||
|
self.large_window.destroy()
|
||||||
|
|
||||||
|
self.large_window = tk.Tk()
|
||||||
|
self.large_window.title(f"放大视图 - {self.caps[idx]['name']}")
|
||||||
|
self.large_window.geometry("1280x720")
|
||||||
|
|
||||||
|
canvas = Canvas(self.large_window, bg='black')
|
||||||
|
canvas.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
photo_obj = {}
|
||||||
|
|
||||||
|
def update_large_frame():
|
||||||
|
"""更新大窗口帧"""
|
||||||
|
while self.running:
|
||||||
|
try:
|
||||||
|
if idx in self.frames and self.large_window.winfo_exists():
|
||||||
|
canvas.delete("all")
|
||||||
|
|
||||||
|
frame = self.frames[idx]
|
||||||
|
h, w = frame.shape[:2]
|
||||||
|
|
||||||
|
# 调整到窗口大小
|
||||||
|
window_width = self.large_window.winfo_width() if self.large_window.winfo_width() > 1 else 1280
|
||||||
|
window_height = self.large_window.winfo_height() if self.large_window.winfo_height() > 1 else 720
|
||||||
|
|
||||||
|
scale = min(window_width / w, window_height / h)
|
||||||
|
new_w = int(w * scale)
|
||||||
|
new_h = int(h * scale)
|
||||||
|
|
||||||
|
resized_frame = cv2.resize(frame, (new_w, new_h))
|
||||||
|
pil_image = Image.fromarray(resized_frame)
|
||||||
|
photo = ImageTk.PhotoImage(image=pil_image)
|
||||||
|
photo_obj['img'] = photo
|
||||||
|
|
||||||
|
canvas.delete("all")
|
||||||
|
canvas.create_image(window_width // 2, window_height // 2, image=photo, anchor='center')
|
||||||
|
|
||||||
|
self.large_window.update()
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
print(f"更新大窗口错误: {e}")
|
||||||
|
break
|
||||||
|
|
||||||
|
import time
|
||||||
|
time.sleep(0.03)
|
||||||
|
|
||||||
|
update_thread = threading.Thread(target=update_large_frame, daemon=True)
|
||||||
|
update_thread.start()
|
||||||
|
|
||||||
|
self.large_window.mainloop()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""运行预览"""
|
||||||
|
self.init_cameras()
|
||||||
|
|
||||||
|
# 启动捕获线程
|
||||||
|
capture_thread = threading.Thread(target=self.capture_frames, daemon=True)
|
||||||
|
capture_thread.start()
|
||||||
|
|
||||||
|
# 创建并显示网格窗口
|
||||||
|
import time
|
||||||
|
time.sleep(0.5) # 等待几帧
|
||||||
|
self.create_grid_window()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
preview = PreviewWindow()
|
||||||
|
preview.run()
|
||||||
|
|
||||||
@@ -45,6 +45,8 @@ import threading
|
|||||||
class GetImage:
|
class GetImage:
|
||||||
def __init__(self, cam_index=0, width=1920, height=1080):
|
def __init__(self, cam_index=0, width=1920, height=1080):
|
||||||
self.cap = cv2.VideoCapture(cam_index, cv2.CAP_DSHOW)
|
self.cap = cv2.VideoCapture(cam_index, cv2.CAP_DSHOW)
|
||||||
|
if not self.cap.isOpened():
|
||||||
|
self.cap = cv2.VideoCapture(cam_index)
|
||||||
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
|
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
|
||||||
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
|
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
|
||||||
self.frame = None
|
self.frame = None
|
||||||
@@ -70,4 +72,6 @@ class GetImage:
|
|||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
self.cap.release()
|
self.cap.release()
|
||||||
cv2.destroyAllWindows()
|
cv2.destroyAllWindows()
|
||||||
get_image = GetImage()
|
|
||||||
|
# get_image 将在main.py中初始化
|
||||||
|
get_image = None
|
||||||
@@ -1,17 +1,34 @@
|
|||||||
import random
|
import random
|
||||||
import time
|
import time
|
||||||
import ch9329Comm
|
import ch9329Comm
|
||||||
import time
|
|
||||||
import random
|
|
||||||
import serial
|
import serial
|
||||||
serial.ser = serial.Serial('COM6', 9600) # 开启串口
|
|
||||||
mouse = ch9329Comm.mouse.DataComm(1920, 1080)
|
# 全局变量,由main.py初始化
|
||||||
|
serial.ser = None
|
||||||
|
mouse = None
|
||||||
|
|
||||||
|
def init_mouse_keyboard(config_group):
|
||||||
|
"""初始化鼠标和串口"""
|
||||||
|
global serial, mouse
|
||||||
|
# 初始化串口
|
||||||
|
serial.ser = serial.Serial(
|
||||||
|
config_group['serial_port'],
|
||||||
|
config_group['serial_baudrate']
|
||||||
|
)
|
||||||
|
# 初始化鼠标
|
||||||
|
mouse = ch9329Comm.mouse.DataComm(
|
||||||
|
config_group['camera_width'],
|
||||||
|
config_group['camera_height']
|
||||||
|
)
|
||||||
|
print(f"✅ 串口已打开: {config_group['serial_port']} {config_group['serial_baudrate']}")
|
||||||
|
print(f"✅ 鼠标已初始化: {config_group['camera_width']}x{config_group['camera_height']}")
|
||||||
|
|
||||||
def bezier_point(t, p0, p1, p2, p3):
|
def bezier_point(t, p0, p1, p2, p3):
|
||||||
"""计算三次贝塞尔曲线上的点"""
|
"""计算三次贝塞尔曲线上的点"""
|
||||||
x = (1-t)**3 * p0[0] + 3*(1-t)**2*t*p1[0] + 3*(1-t)*t**2*p2[0] + t**3*p3[0]
|
x = (1-t)**3 * p0[0] + 3*(1-t)**2*t*p1[0] + 3*(1-t)*t**2*p2[0] + t**3*p3[0]
|
||||||
y = (1-t)**3 * p0[1] + 3*(1-t)**2*t*p1[1] + 3*(1-t)*t**2*p2[1] + t**3*p3[1]
|
y = (1-t)**3 * p0[1] + 3*(1-t)**2*t*p1[1] + 3*(1-t)*t**2*p2[1] + t**3*p3[1]
|
||||||
return (x, y)
|
return (x, y)
|
||||||
|
|
||||||
def move_mouse_bezier(mouse, start, end, duration=1, steps=120):
|
def move_mouse_bezier(mouse, start, end, duration=1, steps=120):
|
||||||
"""
|
"""
|
||||||
用贝塞尔曲线模拟鼠标移动(安全版)
|
用贝塞尔曲线模拟鼠标移动(安全版)
|
||||||
@@ -45,13 +62,14 @@ class Mouse_guiji():
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.point=(0,0)
|
self.point=(0,0)
|
||||||
|
|
||||||
def send_data_absolute(self, x, y,may=0):
|
def send_data_absolute(self, x, y, may=0):
|
||||||
move_mouse_bezier(mouse, self.point, (x,y), duration=1, steps=120)
|
move_mouse_bezier(mouse, self.point, (x,y), duration=1, steps=120)
|
||||||
if may == 1:#点击左
|
if may == 1: # 点击左
|
||||||
mouse.click()
|
mouse.click()
|
||||||
elif may == 2:
|
elif may == 2:
|
||||||
mouse.click1()#点击右
|
mouse.click1() # 点击右
|
||||||
self.point=(x,y)
|
self.point=(x,y)
|
||||||
|
|
||||||
mouse_gui = Mouse_guiji()
|
# mouse_gui 将在main.py中初始化
|
||||||
|
mouse_gui = None
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user