拓冰建站拓冰建站
首页 / 资讯中心 / 正文

基于YOLO的无畏契约目标检测:数据集制作实战指南

1. 项目概述与目标梳理1.1 项目需求解析这件事到底在做什么“基于YOLO的无畏契约内目标检测”说白了就是用目标检测算法从游戏画面的截图中识别出敌人、队友、目标单位等物体。这类需求在我接触的读者里并不少见有人想做游戏AI实验有人想分析自己的对局数据也有人纯粹是想用YOLO练手找一个不算太简单也不算太难的应用场景。选这个项目当入门到进阶的过渡合适。原因有两个第一目标类型明确无非是人物、枪械、技能标识这些有限类别第二游戏画面的背景变化相对可控比自动驾驶那种开放场景简单一个量级适合入门。但别高兴太早里面有个最大的坑——数据从哪里来。这个项目的第一篇就解决“数据集制作”是把整条流水线的地基打牢。这一篇咱们不聊模型怎么选、不聊训练参数怎么调只聊一件事搞出一份能用、够用、不坑自己的数据集。为什么我一上来就强调这一点因为目标检测项目里数据准备通常占掉整个项目60%以上的时间而大多数人恰好死在这一步。你训练集标注得烂、样本分布不科学后面网络结构再好也白搭。1.2 为什么“数据的制作”比想象中的关键得多很多人在跑通YOLOv8那个“bus.jpg”示例图之后就觉得自己已经入门目标检测了。实际上示例模型是官方用几万张图片训练出来的你跑一次前向只是调用不是学会。只有当你想检测自己场景里的目标时才会发现官方模型根本不认识你游戏里的“队友”“敌人”“目标单位”这些概念。这时候你必须亲自做数据集。而这个环节的核心矛盾是你一个人不可能像COCO数据集那样标注几十万张图但你仍然需要让模型达到可用效果。所以“用有限的人工标注换取尽量高的泛化能力”就是数据制作的指导思想。另一层现实是数据质量直接影响模型上限。我见过太多人急着训练结果标签框偏了、漏标了、类别标错了训练出来的模型在测试集上表现不错一到真实游戏画面就疯狂误检。那种排错过程非常痛苦因为你会分不清是模型问题还是数据问题。所以这篇博客的任务很朴实把数据这关过扎实让后续训练和调优阶段少折腾。2. 数据采集从游戏画面到素材库2.1 采集前需要明确的三个问题在按下录制键之前先想清楚三件事检测目标是什么、素材来源是什么、最终给YOLO喂什么。第一检测目标。我的项目里把目标分成三类敌人、队友、训练场靶子就是靶场里的机器人。这样设计一是因为游戏里对抗双方外观差异相对清晰模型有机会学出区别二是因为靶子颜色与人物差异极大可以当成一个“弱正样本”帮模型快速收敛。你也可以根据自己的需求调整比如只检测敌人或者加上“被击倒”状态。类别越细标注成本越高新手起步建议控制在3类以内。第二素材来源。无畏契约的回放系统、自定义房间、训练场都是绝佳的素材来源。你完全不需要自己一场一场打排位录第一视角那样素材里的视角、走位太单一。我建议优先利用自定义房间和回放功能可以固定机位、反复录制同一条路线方便裁剪出不同时间段的画面。相比实排这样采出来的素材时间利用率高出不少。第三最终喂给YOLO的是什么。YOLO接受的输入是原始图像和图像对应的标注文件不用做视频。因此你录完视频以后还需要抽帧。录制素材时的目标是画面稳定、分辨率足够、帧率适中能在后续抽帧时保证画面清晰不糊。分辨率至少要1080p帧率不需要特别高30帧就行——60帧抽出来的连续帧之间相似度太高浪费存储空间。2.2 录屏工具选型与参数设置思路游戏录屏工具有很多OBS Studio、NVIDIA ShadowPlay、Windows自带的Xbox Game Bar都可以。我倾向OBS理由很朴素它对画质和码率的控制最细还能设置“录制时降低硬件占用”不会让游戏帧数掉太多。重点说参数设置思路。分辨率选2560×1440如果机器带不动就选1920×1080不建议用4K因为后续训练时YOLO输入一般是640×640或1280×12804K图缩放时细节并不比1080p多多少但预处理和解码时间翻倍。码率固定到较高档比如CRF 15左右保证画面里的边缘纹理比如人物轮廓是清晰的。如果录制画面出现马赛克一样的块状压缩痕迹检测任务会变得非常难受因为模型容易把压缩块当特征学进去。帧率建议30fps一局比赛按30分钟算抽帧时每10秒取1帧一局差不多能拿到180张画面足够覆盖多数场景了。这里有个小技巧录制时开启“显示鼠标指针”选项方便你后续判断哪些画面里的人是在移动的移动目标在标注时框体位置更值得关注。注意录制前把游戏内“动态模糊”和“景深”特效关掉。这两个特效会把画面细节抹匀静态截图看起来还行一旦目标边缘动起来就会模糊极难标注模型也学不到锐利边缘。2.3 多样性数据集的“四多原则”数据集的质量不是看总数量而是看多样性。我总结了一个“四多原则”多地图、多视角、多时间段、多角色外观。多地图不多解释每一张地图的光照、墙面色块、视野开阔程度差别很大。如果只录一张图模型可能会把某张地图的背景纹理当成特征换张图就失灵。多视角指的是在自定义房间里更换站位同时主动切换第一人称视角、高处俯视视角、近距离切角视角。多时间段是指录制时覆盖游戏内不同回合的不同阶段比如手枪局、长枪局、残局甚至在烟雾弹边缘的画面也录一些这些场景下的目标遮挡和可见度都不相同。多角色外观则需要花点心思。无畏契约里每个英雄的体型、衣服配色、技能特效五花八门模型如果没见过某些皮肤配色实战中容易漏检。所以素材里尽量多换英雄模型或者和朋友开自定义房间换着角色录。如果实在凑不齐把训练场里十来个站桩靶子的肤色、大小差异利用起来也是一种补救。采集阶段的体量目标我建议是原始视频时长2小时左右。这个量对应后期处理完大约1500到2000张有效图片一个人手动标注可以接受模型也够学基础特征了。你要是时间充足能采集到5000张效果会更稳但第一版没必要先跑通全流程更重要。3. 标注方案选型与YOLO格式说明3.1 打标工具LabelImg还是Label Studio数据集制作的另一半工作就是给图片打标签。工具的坑踩过才懂我最初用过在线标注平台传图慢、界面卡顿、标注框容易误拖动体验极差。本地工具才是正路。目前主流选择是LabelImg和Label Studio。LabelImg轻量纯Python写的老牌工具界面简陋但操作干脆最适合单机一个人打几百张图。Label Studio功能强大支持多人协作、自动标注模型接入、多格式导出但配置成本高一个人用属于杀鸡用牛刀。我推荐用LabelImg理由有四点安装简单pip install labelimg 一条命令搞定。默认支持YOLO格式读写不需要自己做格式转换。快捷键齐全W键画框、D键翻图、A键上一张标注节奏很快。开源遇到问题去GitHub翻issue基本都能解决。安装完以后记得在菜单栏里把默认标签格式切换成YOLO保存时它会为每张图片生成一个相同文件名、后缀为.txt的标签文件。图片统一放到一个images目录下标签自动落到同一目录即可。实操心得如果你用Windows系统别从源码直接运行main.py容易缺依赖。直接用conda建一个干净环境执行 pip install labelimg然后命令行敲 labelimg 启动能少踩不少环境坑。3.2 YOLO标签格式一行一个目标很多新手项目的失败不是模型不行而是标签文件写错了模型直接没法训练。YOLO格式的标签特别简单一个txt文件里每行代表一个目标包含5个字段。class_id x_center y_center width height其中class_id从0开始计数对应你在标注时设置的类别顺序。x_center、y_center、width、height四个值是归一化后的0到1小数。归一化是指相对图片宽高的比例不是像素坐标。举个例子一张1080p图片里有个目标中心点在像素坐标(540, 360)宽300、高400那它对应的YOLO标签就是0 0.5 0.3333 0.2778 0.3704计算过程x_center540/19200.28125吗不对等等——1920×1080的图中心点横坐标540对应比例540/19200.28125我这里算错了应该是像上面括号里那种直接套公式就行。实际操作中LabelImg会自动替你计算并写入文件你不需要手算。但你一定要理解这个格式的含义因为在后续数据检查阶段你会需要直接读txt文件来判断标注是否合理。文件夹结构建议这样组织dataset/ images/ frame_001.jpg frame_002.jpg labels/ frame_001.txt frame_002.txtLabelImg默认把txt保存在图片所在目录。为了后续训练方便我习惯用脚本把图片和标签分离到两个目录这在后面“数据划分”部分会提到。3.3 标注规范框什么、怎么框、边界在哪标注规范是整个数据制作最核心的规则。不提前定好标准标了50张以后发现框法不一致返工成本高到你怀疑人生。我的标注规范如下直接抄作业即可。框的目标是“可见主体”。敌人、队友、靶子都框整个身体不要只框头。模型在游戏画面里看到的绝大多数目标是全身或半身只框头会让训练时的样本语义不完整推理时反而对头的依赖变强一旦目标转身只有背影就漏检。当然如果你之后想做“爆头检测”那种精细任务另当别论。框体贴近目标边缘。不要留太大边距也不要卡太紧。太松会让模型学到的目标中掺杂大量背景太紧则可能丢失人物的手持武器和肩部轮廓。一般留出目标图像边缘大概2%的边距即可。目标被大面积遮挡时如果可见区域不足30%直接不标。为什么YOLO训练时是靠可见区域特征做学习的漏标总比标一个残缺框强残缺框会教模型把碎片也当作完整目标。而完全被烟雾弹盖住的目标本身测试时模型也看不见不标不影响评估。类别名必须严格一致。我在LabelImg里预设的类名顺序是“enemy”“teammate”“dummy”对应class_id为0、1、2。每次启动LabelImg之前先编辑好classes.txt文件再进入标注界面。中途改类别顺序会导致旧的txt文件映射错乱千万别动。4. 标注实操与质量控制4.1 打标全流程从第一张图到成规模的量产标注流程我拆成三步预标注准备、正式标注、抽样复查。预标注准备包括把抽好的帧按顺序命名方便后续处理打开LabelImg把图片目录挂载好点一下“PascalVOC”旁边的下拉框确认当前格式是YOLO在标签列表里输入类别。正式标注时我的节奏是这样的先标完100张图休息一下再回头审视前20张。这一步特别重要因为人的标注尺度会漂移——刚开软件时框得紧绷标了一百张后手一快框子就开始随手拉边界越留越宽。回头审视能让尺度拉回到统一水平。抽样复查要在标完一批后立刻做标准做法是每50张抽2张对照原图和标注框检验是否贴合目标。别等全部标完再查因为这时候你对图片内容已经麻木了查不出新问题。表的格式对新手极度友好检查项合格标准出现问题的处理方式框体位置目标主体约占框内面积的80%以上打开图片重新调整框类别正确敌人标enemy队友标teammate直接修改该图txt漏标检查可清晰辨认的目标必须全部框出补画缺失目标完全遮挡可见区域30%的不标无需处理模糊目标动态模糊导致无法确认轮廓删除该图或跳过全流程走完我会用脚本统计所有标签文件的行数检查有没有某张图对应txt文件为空——这种情况发生在图片里确实没有目标时比如队伍全灭后的看戏画面、或者镜头对着天空的转场画面。空标签文件本身不致命但如果占的比例太高模型会学到“倾向于什么都不检测”我通常会把空文件占比压到5%以下删掉对应的图片。4.2 数量与类别平衡别让模型偏心数据量不能平均分摊要根据类别出现频率分配。在无畏契约的正常对局里敌人和队友出现频率差不多但训练场靶子的出场率会高得多。如果你采集素材时也录制了训练场靶子数量可能是敌人的两倍以上。这种不平衡会造成什么问题呢YOLO的训练过程会按图片粒度计算损失类别样本多的那一类贡献了更多梯度更新模型学得更充分类别样本少的那一类就容易被“忽略”。表现在结果上就是靶子检测准确率很高敌人经常误检成靶子或者干脆漏检。我处理的办法是控制三类样本量的比例在1.5:1:1以内。具体操作是抽帧时不是均匀抽而是优先抽取敌方或友方角色清晰可见的画面减少纯靶子画面的比例。或者干脆用图像裁剪脚本从大图里裁出包含人物的区域只保留人物区域作为训练样本这样既减少了背景干扰又变相扩大了目标类别样本的数量。裁剪窗口尺寸按原始尺寸的80%缩放比如1080p图裁成864×864的方形区域。实操心得遇到类别不均衡时最先做的不是找什么复杂的采样算法而是回到数据源头把占比调均衡。因为目标检测的类别平衡没法靠删除某个类别样本硬凑每删一张图都可能丢失有价值的空间位置信息。4.3 小目标处理远距离敌人的标注策略FPS游戏里有个天然难点敌人离你远的时候在1080p画面里可能只占20×40像素。这么小的目标YOLO默认的anchor设计不一定能覆盖好而且人眼标注时容易忽略。我做了两手准备。第一在标注界面设置“显示所有标签”之后仔细扫一遍画面外围区域重点找那些远距离的小目标把它们也标出来但不要假装它们很大。第二对所有包含极小目标的图片做一个额外处理在截取训练图时把原图切分成多块比如把一张1920×1080的图切分成左半、右半两个960×1080的区域分别作为训练样本小目标在块内的相对尺寸就变大了。这一招能明显改善模型对远处敌人的检测能力。切分后的图片也要同步切分标签文件。因为YOLO标签用的是归一化坐标切分后需要重新计算每个目标在新图里的坐标。这个操作手动计算太痛苦后续我会单独用一段Python脚本实现这里先讲思路把x_center、width这些值减去切分偏移量再等比放大到新图尺寸即可。5. 数据集划分与目录结构5.1 目录组织分得清跑得动标注完成的图片和标签如果不梳理训练时会乱成一团。标准目录结构dataset/ images/ train/ val/ test/ labels/ train/ val/ test/ classes.txtYOLOv8工程目录下的data.yaml文件里就需要指定train、val、test三个路径并且通过names字段指定类别名称列表。目录越规范后面跑训练越顺。为什么要分train、val、test三份训练集让模型学习特征验证集用于调参和观察过拟合测试集是最终考核模型泛化能力用的。三者的图片不能有重叠。尤其是游戏画面的连续帧抽帧之后相邻帧几乎一样如果同时出现在训练集和测试集里测试分数会虚高。5.2 划分脚本一行代码干完的活别用鼠标点按70%训练、15%验证、15%测试的比例随机划分。我写了段Python代码可以直接抄import os import random import shutil random.seed(42) img_dir dataset/images label_dir dataset/labels split {train: 0.7, val: 0.15, test: 0.15} # 收集所有图片文件名且只保留有对应标签文件的图片 for root, _, files in os.walk(os.path.join(img_dir, raw)): # 假设原始未划分图片在images/raw pass # 实际使用时建议把图片放在统一目录下再划分参考如下逻辑 names [] for f in os.listdir(img_dir): if f.endswith(.jpg) and os.path.exists(os.path.join(label_dir, f.replace(.jpg, .txt))): names.append(f) random.shuffle(names) boundary1 int(len(names) * split[train]) boundary2 int(len(names) * (split[train] split[val])) for i, name in enumerate(names): if i boundary1: dst train elif i boundary2: dst val else: dst test os.makedirs(os.path.join(img_dir, dst), exist_okTrue) os.makedirs(os.path.join(label_dir, dst), exist_okTrue) shutil.move(os.path.join(img_dir, name), os.path.join(img_dir, dst, name)) shutil.move(os.path.join(label_dir, name.replace(.jpg, .txt)), os.path.join(label_dir, dst, name.replace(.jpg, .txt))) print(划分完成图片总数:, len(names))运行完以后跑一遍统计脚本检查三个集合里各类别数量是否均衡。如果测试集里某个类别数量为0说明样本分配不均匀模型效果会失真。此时可以用带类均衡的采样重新划分或者手动拷贝特定类别的图片到测试集。5.3 标签内容检查肉眼找茬不如脚本代劳标注完的txt文件虽然格式简单但人工核对几千个文件不现实。我写过一个极简的Python检查脚本专门用于排查常见问题import os from collections import Counter label_dir dataset/labels ok_count 0 empty_count 0 bad_format 0 cls_counter Counter() for root, _, files in os.walk(label_dir): for f in files: if not f.endswith(.txt): continue path os.path.join(root, f) with open(path, r, encodingutf-8) as fp: lines [line.strip() for line in fp if line.strip()] if len(lines) 0: empty_count 1 continue for line in lines: parts line.split() if len(parts) ! 5: bad_format 1 continue try: cls int(parts[0]) vals [float(v) for v in parts[1:]] except ValueError: bad_format 1 continue if vals[0] 0 or vals[0] 1 or vals[1] 0 or vals[1] 1: bad_format 1 cls_counter[cls] 1 ok_count 1 print(正常文件:, ok_count) print(空标签文件:, empty_count) print(格式错误行数:, bad_format) print(类别分布:, cls_counter)这个脚本主要抓三类错误txt为空、行数不为5、归一化坐标越界。在实际项目里坐标越界和格式错误比漏标更隐蔽因为如果你在把COCO格式转成YOLO格式时用错脚本很容易产生错误的标签文件。6. 常见问题与经验教训6.1 标着标着发现有些图根本不该标我在做数据集的时候连续踩了几个坑列出来给后来人避雷。第一个坑是抽帧太密。刚开始录制时我按每秒抽1帧的频率处理结果素材里连续30帧画面上的人物位置几乎没变训练集信息冗余不说标注工作量还剧增。后面改成了每10秒抽1帧素材冗余度大幅下降。第二个坑是空场景。自定义房间刚开始录制时有一段等待画面没有玩家进入视野抽出来的帧全是空的。这类图片如果直接留在训练集里会让模型丧失检测欲望。必须仔细检查能删则删。第三个坑是极小目标的定义。早期我坚持把所有目标都标出来哪怕画面里只有5×5像素的移动点也标。那一版数据训练出的模型在验证集上看起来很准但面对正常游戏画面时误检特别多因为模型把太多的噪声也学进去了。后来我才意识到小于8×8像素的目标没有标注意义放进数据集只会干扰模型学习。6.2 数据量到底多少才够我在各个社区被问最多的问题是做YOLO目标检测到底多少张图够用我的回答是看目标复杂度但入门项目有一个大致水位。对于无畏契约这种角色外观相对统一、背景相对固定的游戏画面我个人经验是1000张有效标注图是一个保底数能帮模型跑出像样的结果。2000张以上在类别不多的情况下基本能支撑一个不错的小模型。如果你是新手第一版先别追求测试集分数能到0.98之类的能到0.85就足够验证整个流程了——因为这个阶段的目的不是“炼出一个完美模型”而是“把数据集、训练、推理这条路跑通”。这里还有个经验之谈有时候投入精力的重点不是图片总数而是一致性。用同一个标准标1000张比今天标宽松、明天标严格地标3000张效果更好。标注人员如果多个人参与必须提前统一规范否则模型会捕捉到框体尺寸漂移这种纯标注噪声。6.3 数据集工具链和后续规划本文是把数据集从零做到可训练状态全程用到的工具链不复杂OBS LabelImg Python脚本。这几个工具配合起来单人就能完成从录制到数据集的全部流程。接下来第二篇计划写“怎么用这份数据集训练YOLO模型”包括训练参数imgsz、batch、epochs的拟定思路、训练过程的loss曲线怎么看、遇到模型不收敛时如何回查数据集。同时也会补充如果数据集需要调整类别、增加新目标时怎么样低成本地延续这个制作流程。在数据准备阶段花的时间会在后续模型训练和实际部署时十倍地还给你。这份数据集制作经验不仅限于无畏契约换成任何游戏、任何实时视频流目标检测任务思路都是一样的。最后分享一个小技巧人眼对亮度、对比度变化不那么敏感但模型很敏感。录制素材时不要只录默认亮度比较适中的画面多调几次游戏内Gamma值把暗部细节和过曝画面也录一些进来。这样训练出来的模型在实际各种显示环境下会稳得多。数据集的“脏”不是坏事关键是脏得多样、脏得符合真实分布。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门