
简介这是一个基于YOLOv5识别算法实现的DNF自动脚本优质项目面向计算机相关专业正在准备毕业设计、期末大作业或需要项目实战练习的学生也适合对目标检测与游戏自动化结合有兴趣的开发者。项目整体难度适中内容经导师指导与评审98分源码均在本地编译调试通过可正常运行便于学习者直接复现与二次开发。资源包共94个文件压缩后约27.3MB主要以Python脚本.py、编译缓存.pyc、模型权重.pt、配置YAML、图像模板PNG/JPG及文本说明等组成涵盖图像抓取、技能识别、方向移动、按键模拟等功能模块并配有测试截图与文档说明。已有330人浏览学习适合用于学习YOLOv5模型调用、OpenCV图像处理、游戏窗口识别与自动化操作流程设计。通过此项目可掌握从模型推理到游戏场景自动决策的完整链路也可为后续相关课题提供可扩展的代码基础。1. 基于yolov5识别算法的DNF自动脚本目标检测如何真正接管横版格斗画面横版动作游戏里最难写的自动化从来不是按键宏而是画面理解。早年这类脚本大多靠固定坐标加像素颜色比对游戏改一次分辨率、换一个地图阈值全部作废。基于yolov5识别算法的DNF自动脚本换了一条路直接把游戏截图当成一帧视频流喂给目标检测模型让模型在一整屏里同时找到怪物、掉落物、NPC和出入口再把这些检测框翻译成键盘鼠标动作。它的核心价值在于识别是语义级的——怪物换个姿态、背景换个颜色模型照样认得出来而不是靠某个坐标点的RGB碰运气。对想研究检测模型怎么嵌进实时自动化链路的人而言这个标题其实拆成三个独立课题yolov5网络结构与小目标适配、DNF场景数据集的训练落地、推理结果到键鼠操作的坐标换算。本文按这三条线展开最后收在误检抑制和效果验证上。适合正在做游戏图像识别、OpenCV自动化、或拿yolov5做仿真环境感知的工程师参考新手也能照步骤把最小链路跑通。2. yolov5网络结构与DNF场景检测流程的设计2.1 为什么是yolov5而不是yolov8或传统模板匹配DNF的界面特点是UI固定、场景纵深感弱、角色与怪物尺寸小。传统模板匹配对同一只怪物换帧动画无能为力而yolov5的CSPDarknet骨干网络加PANet特征金字塔天然适合这种中等尺寸目标居多的画面。yolov5s版本在GTX 1660级别显卡上推理耗时约5到8毫秒单帧检测完全能跟上游戏每秒30到60帧的刷新这是它能做实时自动化的先决条件。yolov5另一个实际优势是工程生态。训练脚本、导出脚本、ONNX转OpenVINO的链路都齐全做自动化脚本时如果不想在游戏机器上跑PyTorch可以直接导出成ONNX用onnxruntime加载依赖体积小一个量级。yolov8虽然精度略高但部署生态相对新对识别完还要接键鼠模拟这种需求反而多一层转换成本。2.1.1 DNF小目标识别需要关注的yolov5网络结构细节yolov5的Detect头在三个尺度上输出预测80x80、40x40、20x20特征图分别负责小、中、大目标。DNF的怪物在1080p截图里大约只占20到40像素宽属于典型小目标因此默认anchor里针对小目标的anchor尺寸必须保留。训练时不要贪快把 --img 降到320否则小目标直接丢特征。PANet的底层特征图与顶层语义特征反复融合对小目标是有利的。实际训练DNF数据时backbone冻不冻结差别不大因为游戏画面和COCO分布差异太大建议直接全量微调。Batch size在8到16之间即可太大反而让模型对游戏UI这种强规律背景过拟合。2.2 实时检测流程截图、预处理、推理、坐标映射整个自动脚本的检测链路按以下步骤组织每一步的延迟都会叠加到最终的反应速度上用Win32 API抓取游戏窗口客户区转成BGRA数组避免走剪贴板截图剪贴板有100毫秒左右的延迟对截图做letterbox缩放保持宽高比填充到640x640记录填充比例和偏移量送入yolov5模型推理得到检测框、类别、置信度按置信度阈值过滤后把检测框从640坐标系映射回原始窗口坐标将坐标换算成屏幕绝对坐标交给键鼠模拟模块以下是我常用的截图与推理最小实现依赖只有opencv、onnxruntime和pywin32import cv2 import numpy as np import onnxruntime as ort import win32gui, win32ui, win32con def grab_window(hwnd): left, top, right, bottom win32gui.GetWindowRect(hwnd) w, h right - left, bottom - top hwnd_dc win32gui.GetWindowDC(hwnd) mfc_dc win32ui.CreateDCFromHandle(hwnd_dc) save_dc mfc_dc.CreateCompatibleDC() bmp win32ui.CreateBitmap() bmp.CreateCompatibleBitmap(mfc_dc, w, h) save_dc.SelectObject(bmp) save_dc.BitBlt((0, 0), (w, h), mfc_dc, (0, 0), win32con.SRCCOPY) img np.frombuffer(bmp.GetBitmapBits(True), dtypenp.uint8).reshape(h, w, 4) return img[..., :3].copy(), (left, top) session ort.InferenceSession(dnf_best.onnx, providers[CPUExecutionProvider]) def letterbox(img, size640): h, w img.shape[:2] r min(size / h, size / w) nh, nw int(round(h * r)), int(round(w * r)) resized cv2.resize(img, (nw, nh)) canvas np.full((size, size, 3), 114, dtypenp.uint8) top, left (size - nh) // 2, (size - nw) // 2 canvas[top:top nh, left:left nw] resized return canvas, r, left, top def detect(frame): canvas, r, left, top letterbox(frame) blob canvas[..., ::-1].transpose(2, 0, 1).astype(np.float32) / 255.0 blob np.expand_dims(blob, axis0) preds session.run(None, {session.get_inputs()[0].name: blob})[0] # preds shape: [1, 25200, 85]需要按坐标还原 return preds, r, left, top这段代码的逻辑说明grab_window用BitBlt抓取窗口客户区比PIL的ImageGrab快且不受屏幕缩放影响letterbox记录缩放比例和填充偏移推理结束后把检测框坐标除以r再减去left/top即可还原。注意preds前4个值是中心点坐标和宽高后81维里前80维是DNF数据集的类概率最后一维是置信度解析时别取反。提示如果游戏全屏独占BitBlt可能抓到黑屏。常见的做法是让DNF跑在无边框窗口模式这也是为什么很多自动化项目要求调整分辨率和窗口模式。3. 用yolov5训练自己的DNF数据集标注、参数与导出3.1 数据采集从游戏录屏到干净训练集训练数据的质量直接决定脚本的误检率。建议先开一局用OBS或NVIDIA ShadowPlay录20到30分钟完整游戏过程覆盖不同地图、不同怪物组合、技能特效密集的时段。录屏拿到后按每秒抽1帧得到约1200到1800张原始图片然后手动筛掉模糊、技能光效完全遮住怪物的帧。清洗后按8:1:1划分训练集、验证集、测试集。标注用labelimg或labelme导出YOLO格式的txt每行是class_id cx cy w h坐标都是归一化到0到1的浮点数。DNF这类横版格斗场景建议的类别不要超过6个常见设计如下表类别ID标签名检测目标标注要点0monster普通怪物只框身体主体不框血条1bossBoss怪物血量多、判定大的单独一类2item掉落物包括金币和装备小目标需要放大截图标注3portal传送门/出入口固定出现位置但换图后坐标变化4player自己角色用于相对位移判断5npc任务NPC名字牌可归入此类3.1.1 小目标标注的坑item类在1080p截图里往往只有15到20像素肉眼放大标注时容易漏框。一个有效技巧是用ffmpeg把原视频局部放大2倍后再标注标注完把坐标除以2映射回原图。另一个坑是DNF的背景有大量暗色装饰物和某些掉落物外观接近宁可少标也不要硬标硬标会让模型学到错误特征。3.2 训练命令与超参数调整数据集按yolov5要求的目录结构放好后训练命令直接走官方train.py。DNF场景不是COCO那种大目标分布超参数需要针对性调整python train.py --data dnf.yaml --weights yolov5s.pt --img 640 \ --batch-size 16 --epochs 100 --device 0 \ --hyp hyp.dnf.yaml --project runs/dnfdnf.yaml里必须写对路径train: /data/dnf/images/train和val: /data/dnf/images/val类别数nc: 6类别名与标注ID一一对应。hyp.dnf.yaml是训练超参数重点改几个关键项参数默认值DNF建议值原因lr00.010.005游戏画面分布偏窄学习率过大会震荡mosaic1.00.5马赛克增强会切碎小怪物降低强度scale0.50.3缩放增强范围太大让小目标更小conf_thres0.250.4提高置信度过滤减少UI误检anchor_t4.03.0收紧anchor匹配适配小目标分布这里说明几个关键参数的含义mosaic是四图拼接增强游戏画面拼接后语义混乱降一半即可scale控制随机缩放DNF怪物本身就小太大反而丢失特征conf_thres不是训练参数而是推理参数但训练时也会用于NMS调高能明显降低把UI图标当怪物这类误检。训练结束后看runs/dnf/weights/best.pt的验证集mAP。DNF场景mAP0.5能到0.9以上比较理想mAP0.5:0.95在0.6到0.7就够用因为脚本执行动作只需要框的位置准确不需要框和真实目标完全贴合。提示显存不够时不要直接降batch到4优先降--img到512。DNF目标是中小目标640降到512损失不大但batch太小BN层统计不稳定训练反而更难收敛。3.3 导出模型训练到部署的距离训练好的best.pt是PyTorch格式直接用于实时脚本太重。常见做法是导出成ONNX再用onnxruntime加载CPU上也能跑出30毫秒以内的推理性能python export.py --weights runs/dnf/weights/best.pt \ --include onnx --imgsz 640 --batch-size 1 \ --opset 12 --simplify导出的best.onnx与训练时的letterbox参数强绑定部署端必须用相同尺寸预处理。如果你打算用Intel核显机器做自动化可以继续用OpenVINO跑ONNX延迟能从30毫秒降到15毫秒左右对反应速度有要求的场景值得做。注意导出后先在本地用一张真实游戏截图做推理对比确认坐标还原一致再进脚本。4. 自动脚本的工程实现坐标换算、键鼠操作与运行环境4.1 从检测框到具体动作的决策逻辑模型输出的只是哪里有什么要变成自动脚本还需要一层决策逻辑。以刷图场景为例一般按优先级判断有item类且距离玩家小于阈值时走向物品有monster类时释放攻击技能有portal类且清场完毕时走向传送门。这个决策层越简单越稳定复杂的有限状态机在游戏场景里容易因为某个状态漏判而卡死。核心代码框架如下import time import pydirectinput def decide_actions(detections, player_center): items, monsters, portal [], [], None for det in detections: x1, y1, x2, y2, cls, conf det cx, cy (x1 x2) / 2, (y1 y2) / 2 if cls 2: items.append((cx, cy)) elif cls in (0, 1): monsters.append((cx, cy, cls)) elif cls 3: portal (cx, cy) # 先捡近处的物品 if items: items.sort(keylambda p: (p[0] - player_center[0]) ** 2 (p[1] - player_center[1]) ** 2) target items[0] dx, dy target[0] - player_center[0], target[1] - player_center[1] if abs(dx) 10: pydirectinput.press(right if dx 0 else left) else: pydirectinput.press(x) # 有怪物时放技能 elif monsters: pydirectinput.press(c)这段决策逻辑说明了几个关键点pydirectinput是对pyautogui的替代它直接调用SendInput触发游戏内置的按键映射更稳定pyautogui在某些游戏里会被反作弊机制忽略所有动作前先算目标与玩家中心的距离差避免角色原地抖动x是拾取键、c是攻击键实际按键取决于DNF的键位设置改为配置文件更灵活。决策层的判断频率要低于推理频率。模型每秒跑20到30帧但物理按键不需要那么高频通常每2到3帧做一次决策就够了。高频按键反而容易触发游戏的行为检测且角色移动动画还没播完就开始下一次操作会卡位。4.1.1 双开分辨率和多窗口坐标偏移DNF双开是常见需求两个游戏窗口在同一屏幕内的分辨率相同但窗口起始坐标不同。Win32的GetWindowRect拿到的坐标是屏幕绝对坐标而检测框的坐标是从单个窗口抓图算出来的相对坐标映射到屏幕必须加上窗口的left, top偏移。多窗口管理时建议用一个字典维护hwnd到坐标偏移的映射每帧动态刷新因为用户拖动窗口后偏移会变。def to_screen_coords(det_box, window_offset): x1, y1, x2, y2 det_box win_left, win_top window_offset return (x1 win_left, y1 win_top, x2 win_left, y2 win_top)坐标换算的坑主要在Windows DPI缩放。如果系统缩放是125%或150%GetWindowRect返回的是物理像素坐标而BitBlt抓到的图像尺寸可能是缩放后的虚拟坐标两者不匹配会导致点击偏移。常见处理是在脚本入口调用SetProcessDPIAware()使进程感知DPI让所有坐标统一在物理像素下计算。4.2 窗口模式、运行库与依赖清单DNF自动化脚本的最佳运行环境是窗口模式或者无边框全屏。全屏独占模式下GDI抓图拿不到内容需要用DXGI Desktop Duplication这一类更底层的API但DXGI对游戏兼容性不稳定。无边框窗口是抓图兼容性和游戏性能的平衡点这也是为什么很多同类项目默认要求设置无边框。依赖环境方面使用PyTorch训练模型的机器和跑脚本的机器可以分离。脚本运行机只需要CPU版onnxruntime、opencv-python、pywin32、pydirectinput、numpy这几项体积小很多。DNF本体需要VC运行库和DirectX组件缺失时游戏窗口会异常闪退现象是抓图正常但游戏进程无故消失排查时先看系统事件日志再检查运行库是否装全。依赖版本建议用途onnxruntime1.14ONNX推理opencv-python4.x截图预处理、letterboxpywin32306Win32窗口抓图pydirectinput最新键鼠模拟numpy1.21数组操作提示脚本运行过程中游戏切换地图或加载场景时检测框会短暂消失。决策逻辑里要有超时判断连续N帧没有检测到任何目标就停止动作避免角色对着空气放技能。5. 误检抑制与长时间运行的稳定性验证自动脚本真正要过的关是长时间运行的误检累积。单帧误检率1%看起来不高但每秒20帧决策跑10分钟就是上万次判断一次误检把Boss当NPC走上去对话就可能卡流程。我常用的手法是连续帧投票同一目标至少连续出现3帧才认为确认存在执行动作后设置冷却时间。投票机制的简化实现class VoteFilter: def __init__(self, threshold3, cooldown1.0): self.threshold threshold self.cooldown cooldown self.count {} self.last_action_time 0 def update(self, detections, now): confirmed [] for det in detections: key (round(det[0], 1), round(det[1], 1), det[4]) self.count[key] self.count.get(key, 0) 1 if self.count[key] self.threshold: confirmed.append(det) if now - self.last_action_time self.cooldown: return [] if confirmed: self.last_action_time now return confirmed使用这类滤噪机制时需要特别注意检测框抖动导致的key频繁变化——怪物移动时框坐标每帧差几个像素取整到1像素精度后key仍然会漂移。实际应用时建议以类别加网格坐标比如按50像素分块作为key而不是精确像素坐标。冷却时间按动作类型区分移动动作冷却300毫秒、攻击动作冷却600毫秒比统一冷却更接近人类操作节律。验证环节不要只看训练集的mAP要跑到真实环境里看以下几项指标站立不动时每秒误触发次数应接近0刷完整张图是否能正常拾取所有掉落物传送门识别在远近两种距离下的稳定帧率。把这些指标记录成日志每轮迭代改的是模型阈值、投票参数还是决策逻辑一眼就能看出来。对这套脚本类项目来说检测精度是上限决策与滤噪逻辑才是真实体验的下限。本文还有配套的精品资源点击获取