资讯动态

游戏目标检测实战:3000张6类MOBA数据集从标注转换到YOLO训练全流程

发布时间:2026/10/14 15:15:08 来源:尧图企业网站定制
简介本资源为LOL英雄联盟角色检测数据集面向计算机视觉方向的目标检测学习者与算法工程师可用于训练和验证游戏场景下的多目标识别模型。数据集共3000张jpg图片每张均配有对应的VOC格式xml标注与YOLO格式txt标注标注工具为labelImg采用矩形框方式完成。标注类别共6类包括队友小兵、己方防御塔、敌方小兵、敌方防御塔以及LUX、VAYNE两个英雄角色总标注框数达24665个其中敌方小兵框数最多为10973个VAYNE为3669个LUX为1531个类别分布较为丰富。压缩包为zip格式内含1999个xml文件与1个说明txt文件整体约135.85MB目录结构清晰便于直接接入YOLO或VOC训练流程。目前已有464人学习下载适合需要游戏目标检测数据、开展模型训练与对比实验的读者参考使用。1. 从一张截图说起为什么3000张6类的角色检测数据集值得你花时间做游戏画面分析的同学大概率遇到过这个场景想给直播画面加一个自动导播或者给录播做一波高光切片第一步就卡在“怎么把画面里的角色、小兵、防御塔框出来”。通用检测模型在自然图像上表现不错一进游戏画面就集体翻车——UI 元素干扰、角色贴图风格统一、小兵扎堆重叠、防御塔半透明血条遮挡这些都不是 COCO 预训练权重能直接搞定的。这时候一个标注好的、类别定义贴合 MOBA 场景的检测数据集价值就出来了。标题里这份数据集的核心信息很明确3000 张图像、6 个类别覆盖队友、己方小兵、敌方小兵、防御塔、韦恩这类游戏内目标。它解决的不是“通用检测”问题而是“游戏画面里谁是谁、属于哪一方”的细粒度识别问题。适合两类人一是想快速跑通游戏目标检测 pipeline 的工程师二是需要在自己的游戏分析项目里做迁移学习的开发者。下面我按“数据长什么样 → 怎么转格式 → 怎么训 → 坑在哪 → 怎么调优”的顺序把这条链路拆开讲。2. 先看清数据再动手6类标注的语义边界与分布陷阱2.1 六个类别的定义与容易混淆的地方拿到一份游戏检测数据集第一件事不是急着写 dataloader而是把类别定义和标注规则吃透。这份数据集的 6 个类别里队友和敌方小兵、己方小兵和敌方小兵之间的区分靠的是颜色、血条颜色和模型贴图差异而不是形状。韦恩作为一个具体英雄类别单独列出说明标注时对英雄个体做了区分而不是笼统归为“英雄”。类别判定依据常见混淆对象队友友方血条颜色 模型轮廓与敌方英雄颜色接近时易混己方小兵蓝色/绿色血条 小兵模型与敌方小兵模型高度相似敌方小兵红色血条 小兵模型同上防御塔固定建筑结构 底座与水晶、基地建筑易混韦恩特定英雄模型 技能特效与其他射手英雄轮廓接近这里有个血泪经验小兵类别的区分极度依赖血条颜色如果图像分辨率不够或者血条被特效遮挡标注一致性会明显下降。你在训练前最好抽样 100 张用脚本统计每个类别的框数量和平均框面积看看有没有某个类别样本过少或者框面积异常。2.2 用脚本做一次数据体检在训练之前我一般会写一个轻量脚本把标注文件读进来统计类别分布、框的宽高比、以及每张图的框数量。这一步能提前暴露“某类只有几十个框”或者“框面积全是小目标”的问题。import os import json from collections import Counter # 假设标注是 COCO 格式的 json如果是 YOLO txt 需要另写解析 ann_path annotations/instances.json with open(ann_path, r, encodingutf-8) as f: data json.load(f) # 统计每个类别的框数量 cat_counter Counter() for ann in data[annotations]: cat_counter[ann[category_id]] 1 # 映射类别 id 到名称 id2name {c[id]: c[name] for c in data[categories]} for cid, cnt in cat_counter.most_common(): print(f{id2name[cid]}: {cnt} boxes) # 统计每张图的框数量分布 img_box_count Counter() for ann in data[annotations]: img_box_count[ann[image_id]] 1 avg_boxes sum(img_box_count.values()) / len(img_box_count) print(f平均每张图框数: {avg_boxes:.2f}) print(f框数最多的图: {img_box_count.most_common(3)})这段脚本的逻辑很直接先按 category_id 聚合再按 image_id 聚合。参数上唯一需要注意的是标注格式COCO 的 category_id 通常从 1 开始YOLO 的 class_id 从 0 开始转换时别搞错。如果发现某个类别框数低于总数的 5%训练时就要考虑加权重采样或者用 focal loss 来缓解类别不平衡。2.3 3000 张的规模意味着什么3000 张图像、6 个类别平均下来每类 500 张左右的量级。这个规模对于从零训练一个检测网络来说偏小但对于微调一个预训练模型是够用的。我的建议是不要从零训直接用 COCO 预训练的 YOLO 或者 Faster R-CNN 做 backbone 初始化只替换检测头。3000 张图在单卡上跑 100 到 150 个 epoch配合数据增强通常能收敛到一个可用的水平。3. 把标注转成 YOLO 格式转换脚本与四个边界坑3.1 为什么优先选 YOLO 格式游戏画面检测对推理速度有要求尤其是你想做实时导播或者直播叠加的时候。YOLO 系列在速度和精度平衡上比较成熟而且格式简单一个 txt 对应一张图每行class_id x_center y_center width height全部归一化到 0 到 1。相比 COCO 的 jsonYOLO 格式在训练时读取更快也不容易因为 json 解析出问题导致整个训练卡住。3.2 转换脚本从 COCO 到 YOLO假设你拿到的标注是 COCO 格式下面这个脚本可以直接用。核心是把绝对坐标转成归一化中心点坐标同时把 category_id 映射成从 0 开始的连续整数。import json import os from PIL import Image def coco_to_yolo(coco_json, img_dir, out_dir): with open(coco_json, r, encodingutf-8) as f: data json.load(f) # 建立 image_id 到文件名的映射 img_info {img[id]: img for img in data[images]} # 建立 category_id 到连续 id 的映射 cat_ids sorted([c[id] for c in data[categories]]) cat_id_map {cid: idx for idx, cid in enumerate(cat_ids)} os.makedirs(out_dir, exist_okTrue) # 按 image_id 聚合标注 from collections import defaultdict ann_by_img defaultdict(list) for ann in data[annotations]: ann_by_img[ann[image_id]].append(ann) for img_id, anns in ann_by_img.items(): info img_info[img_id] w, h info[width], info[height] lines [] for ann in anns: x, y, bw, bh ann[bbox] # COCO: 左上角 x,y,宽,高 # 转成中心点归一化坐标 x_center (x bw / 2) / w y_center (y bh / 2) / h nw bw / w nh bh / h cls cat_id_map[ann[category_id]] lines.append(f{cls} {x_center:.6f} {y_center:.6f} {nw:.6f} {nh:.6f}) # 写 txt文件名与图片同名 base os.path.splitext(info[file_name])[0] with open(os.path.join(out_dir, base .txt), w) as f: f.write(\n.join(lines)) coco_to_yolo(annotations/instances.json, images, labels)逻辑说明COCO 的 bbox 是[x_min, y_min, width, height]YOLO 需要的是中心点加宽高且全部除以图像宽高做归一化。参数上要注意cat_id_map的构建必须保证类别 id 连续否则 YOLO 训练时会报类别索引越界。另外如果某张图没有标注脚本不会生成对应的 txt训练时要么跳过这张图要么生成空文件取决于你的 dataloader 实现。3.3 四个容易翻车的边界情况第一个坑是图像尺寸和标注尺寸不一致。有些数据集里的 width/height 是原始截图尺寸但你实际拿到的图片可能被压缩过。转换前一定要用 PIL 读一下实际图片尺寸和 json 里的对不上就先缩放标注。第二个坑是 bbox 越界。游戏画面里角色贴边时标注框可能超出图像边界转成 YOLO 后中心点可能小于 0 或大于 1。训练前加一行 clamp 把坐标限制在 0 到 1 之间否则某些框架会直接报错。第三个坑是类别 id 不连续。COCO 的 category_id 可能是 1、3、7 这种跳号直接拿来当 YOLO 的 class_id 会出问题。必须重新映射成 0、1、2 这样的连续整数。第四个坑是文件名冲突。不同文件夹下的图片可能重名转换后的 txt 会互相覆盖。建议在输出文件名里保留原始子目录结构或者加前缀。4. 训练配置怎么定从 anchor 到学习率的实操参数4.1 选 YOLOv5 还是 YOLOv8如果追求快速跑通YOLOv5 的生态最成熟配置文件清晰社区里游戏检测的案例也多。YOLOv8 的精度略高但配置文件结构变化较大新手容易在数据 yaml 上卡住。我的建议是先用 YOLOv5s 跑一版 baseline确认数据 pipeline 没问题再考虑换更大的模型或者 YOLOv8。4.2 数据 yaml 的写法YOLO 训练需要一个 data.yaml指定训练集、验证集路径和类别名称。路径建议用绝对路径避免相对路径在不同工作目录下解析出错。# data.yaml train: /data/lol_detection/images/train val: /data/lol_detection/images/val nc: 6 names: [teammate, ally_minion, enemy_minion, tower, vayne, other]这里nc必须和实际类别数一致names的顺序要和转换脚本里的cat_id_map完全对应。如果顺序错了模型会把队友识别成敌方小兵这种错误在验证集上 loss 正常但实际效果完全不对属于典型的“黑匣子”问题。4.3 关键训练参数与调整逻辑python train.py \ --img 640 \ --batch 16 \ --epochs 150 \ --data data.yaml \ --weights yolov5s.pt \ --cfg models/yolov5s.yaml \ --hyp data/hyp.scratch.yaml \ --name lol_exp1--img 640是输入分辨率游戏画面里小兵和英雄的尺寸差异大640 在速度和精度之间比较平衡。如果显存够可以上 1280对小目标更友好。--batch 16在单张 12G 显存的卡上比较稳显存不够就降到 8。--epochs 150是针对 3000 张规模的保守值如果验证集 mAP 在 100 epoch 后还在涨可以加到 200。学习率方面YOLOv5 默认的hyp.scratch.yaml里lr0是 0.01对微调来说偏大。我一般会改成 0.001配合 cosine 衰减。如果发现训练前期 loss 震荡厉害再降到 0.0005。4.4 anchor 需不需要重新聚类游戏画面的目标宽高比和自然图像差异很大防御塔是竖长条小兵接近方形英雄介于两者之间。用 COCO 的默认 anchor 不是不能跑但召回率会受影响。建议用 YOLOv5 自带的kmeans.py对自己的标注做一次 anchor 聚类把结果替换到模型配置里。这一步大概能带来 2 到 3 个点的 mAP 提升属于性价比很高的操作。5. 避坑与排查训练不收敛、类别混淆、小目标漏检5.1 训练 loss 不降反升现象前 10 个 epoch loss 正常下降之后突然飙升或者震荡。原因通常是学习率太大或者数据里有标注错误的样本。解决先把学习率降一个数量级如果还不行用脚本抽查一批标注可视化看看有没有框错类别或者框到 UI 上的情况。游戏画面里技能特效和血条很容易被误标这类脏数据对训练伤害很大。5.2 队友和敌方小兵互相误检现象验证集上这两个类别的混淆矩阵明显偏高。原因模型主要靠颜色区分但图像增强里的色彩抖动hsv_h、hsv_s把颜色信息破坏了。解决把hsv_h降到 0.01 以下hsv_s和hsv_v也相应调小让模型更多依赖形状和纹理。如果还是不行考虑在数据里补充一些颜色接近的困难样本。5.3 小兵漏检严重现象mAP 整体还行但小兵类别的召回率明显低。原因小兵在画面里尺寸小640 分辨率下可能只有十几个像素。解决把输入分辨率提到 960 或 1280同时在数据增强里减少 mosaic 的概率因为 mosaic 会把小目标进一步缩小。另外可以调整 anchor专门为小目标增加一组更小的 anchor。5.4 防御塔被识别成背景现象防御塔的 AP 很低模型几乎不输出这类框。原因防御塔在画面里位置固定且经常被 UI 遮挡样本多样性不足。解决检查标注里防御塔的框是不是只出现在固定区域如果是需要在数据增强里加随机裁剪和平移让模型见到不同位置的防御塔。另外可以单独统计防御塔的框数量如果太少考虑过采样包含防御塔的图像。5.5 验证集 mAP 高但实际推理效果差现象验证集 mAP 0.7 以上但拿真实直播截图去测漏检和误检都很严重。原因验证集和训练集来自同一批录像分布太接近模型过拟合了。解决重新划分验证集确保验证集的录像片段和训练集不重叠。如果数据里不同地图、不同皮肤的画面差异大验证集要覆盖这些变化。6. 进阶技巧用半自动标注和困难样本挖掘把 mAP 再推一截6.1 用训练好的模型做半自动标注3000 张标注完不是终点。实际项目里你很快会遇到新地图、新皮肤、新英雄重新标 3000 张成本太高。我的做法是用当前模型对未标注的新画面做推理把置信度高于 0.6 的框自动导出成标注人工只修正漏检和误检的部分。这样一轮下来新增 500 张标注的时间能从两天压缩到半天。import torch from PIL import Image model torch.hub.load(ultralytics/yolov5, custom, pathbest.pt) model.conf 0.6 # 只保留高置信度框 img Image.open(new_frame.jpg) results model(img) # 导出为 YOLO 格式 results.save(auto_labels/)这里conf设 0.6 是个经验值太低会引入大量误检太高会漏掉困难样本。导出后一定要人工过一遍尤其是小兵和队友这种容易混的类别。6.2 困难样本挖掘的具体操作训练完一版模型后把验证集里 loss 最高的前 100 张图挑出来看看模型错在哪。常见的高 loss 样本包括团战画面目标密集重叠、技能特效遮挡目标不完整、极端光照地图阴影区域。把这些图单独复制一份在下一轮训练里重复采样 2 到 3 次能明显提升模型在这些场景下的鲁棒性。6.3 一个验证模型是否值得上线的检查清单在把模型推到实际业务之前我一般会跑一遍这个清单第一用最近一周的真实直播截图做测试mAP 不低于验证集的 80%第二单帧推理时间在目标硬件上满足实时要求比如 30 FPS 对应 33ms 以内第三类别混淆矩阵里队友和敌方小兵的误检率低于 5%第四防御塔和韦恩的召回率不低于 0.7。这四条都过了才考虑上线。6.4 我踩过的最大的一个坑早期做游戏检测的时候我图省事直接把训练集和验证集按 8:2 随机划分。结果验证集 mAP 冲到 0.85上线后实际效果惨不忍睹。后来才发现同一局游戏的相邻帧被分到了训练集和验证集模型相当于在“背答案”。改成按整局游戏划分之后验证集 mAP 掉到 0.68但这才是真实水平。这个教训让我养成了一个习惯任何时序相关的数据划分验证集时一定要按片段切不能按帧随机切。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑