资讯详情

资讯详情

地铁监控人员检测数据集实战:VOC/YOLO双格式与YOLO训练调参

地铁监控场景下的人员检测是智能安防和轨道交通领域里落地最早、也最容易被低估难度的一类任务。很多人第一次拿到监控视角地铁场景人员检测数据集这种标题第一反应是不就是检测人吗COCO上跑个YOLO不就行了结果一上手就发现地铁站台的光照忽明忽暗、人群密度高、遮挡严重、监控视角俯角大、目标尺度差异悬殊通用模型直接迁移过去mAP能掉一大截。这次我拿到的是一份2189张、单类别person、同时提供VOC和YOLO两种标注格式的地铁监控人员检测数据集正好可以借它把监控视角地铁场景人员检测这条链路从头到尾讲透。不管你是刚入门目标检测想找一个真实场景练手还是已经在做安防项目需要快速验证方案这篇内容都能让你少走弯路——我会把数据集的格式细节、两种标注的转换逻辑、监控场景特有的坑、训练参数怎么调、以及实测中那些文档里不会写的经验全部摊开讲清楚。1. 先搞清楚这份数据集到底特殊在哪1.1 2189张、单类别这个规模意味着什么先看基本盘2189张图像1个类别personVOC和YOLO双格式。这个体量在目标检测数据集里属于中小规模。COCO有十几万张VOC20072012加起来两万多张而2189张大概是什么概念如果你做的是单类别检测这个量级其实够用了尤其是场景高度聚焦都是地铁监控视角的情况下数据分布的密度比数量更重要。我一般会这样判断一个数据集够不够用单类别检测如果场景单一、目标形态相对固定1500到3000张就能训出一个可用的baseline如果是多类别、场景发散那至少得5000张起步。这份数据集正好卡在够用但不富裕的区间所以怎么用好它、怎么通过数据增强和迁移学习把它的价值榨干比单纯堆数据更重要。单类别还有个隐性好处你不用处理类别不平衡问题。多类别数据集里最常见的头疼事就是某些类别样本极少导致模型对它们几乎没学习能力。person这一类在地铁监控里天然就是主角每张图里少则几个、多则几十个目标样本量非常充足。1.2 监控视角带来的三个反常识难点普通的目标检测教程里人都是正常站姿、平视角度、清晰完整。但地铁监控完全是另一回事我总结了三个最容易被忽视的难点第一俯角导致的形态畸变。监控摄像头通常装在天花板或高处俯视角一般在30到60度之间。这个角度下人的比例会被压缩头肩占比变大、腿部变短甚至只露出一个头顶。通用模型在COCO这种平视数据上学的人体先验在这里会部分失效。第二尺度极端分化。同一个画面里近处的人可能占几百像素高远处站台尽头的人可能只有十几个像素。这种尺度跨度对检测器的多尺度能力是硬考验也是为什么FPN、PANet这类特征金字塔结构在监控场景里几乎是标配。第三遮挡与密集。早晚高峰的地铁站台人群是糊在一起的。人与人之间互相遮挡模型很容易把两个人检成一个或者漏掉被挡住的那个。这个问题在单类别检测里尤其突出因为没有其他类别帮你做上下文区分。提示如果你拿这份数据集直接套用COCO预训练模型先别急着调参第一步应该是可视化几十张标注图亲眼看看目标尺度和遮挡的分布这比看任何指标都直观。1.3 VOC和YOLO双格式到底该用哪个数据集同时给了VOC和YOLO两种格式这不是冗余而是照顾不同的训练框架。简单说清楚区别维度VOC格式YOLO格式标注文件XML每张图一个TXT每张图一个坐标表示绝对像素值 xmin,ymin,xmax,ymax归一化中心点宽高 cx,cy,w,h坐标范围0 到 图像宽/高0 到 1常用框架Faster R-CNN、SSD、MMDetectionYOLO系列、Darknet可读性高带类别名和图像尺寸低纯数字VOC格式的好处是信息全XML里连图像宽高、类别名都写好了人眼可读调试时方便。YOLO格式的好处是训练时读取快不用解析XML而且归一化坐标天然适配不同输入尺寸的缩放。我的建议是用YOLO系列训练就直接用TXT用MMDetection或PaddleDetection就用XML。但不管用哪个都建议自己写个脚本把两种格式互相转换一遍一来验证标注一致性二来转换过程中能发现很多隐藏问题比如坐标越界、宽高为负、类别名拼写不一致。这个转换脚本后面我会给。2. 标注格式的转换与数据清洗实操2.1 VOC转YOLO归一化坐标的计算细节VOC的XML里一个目标长这样object nameperson/name bndbox xmin312/xmin ymin145/ymin xmax398/xmax ymax402/ymax /bndbox /object转成YOLO格式需要四个归一化值中心点x、中心点y、宽、高。计算逻辑是# 假设图像宽 w_img1920, 高 h_img1080 xmin, ymin, xmax, ymax 312, 145, 398, 402 w_img, h_img 1920, 1080 cx (xmin xmax) / 2.0 / w_img cy (ymin ymax) / 2.0 / h_img w (xmax - xmin) / w_img h (ymax - ymin) / h_img # 结果: cx≈0.1849, cy≈0.2532, w≈0.0448, h≈0.2380这里有个极易踩的坑图像宽高必须从对应的XML里读不能想当然用固定值。地铁监控数据集里图像分辨率可能不统一有的1920×1080有的1280×720如果你写死一个尺寸归一化坐标全错训练时loss会莫名其妙不下降。我写转换脚本时习惯加一层校验转换后检查所有值是否落在[0,1]区间超出范围的就打印出来人工核对。实测中确实能揪出一些标注时手抖写错的框。2.2 数据清洗那些必须处理掉的脏数据2189张里几乎不可能全是干净标注。我拿到任何数据集都会先跑一遍清洗流程重点查这几类问题零面积框xmax等于xmin或ymax等于ymin这种框训练时会产生NaN loss必须删。越界框坐标超出图像边界比如xmax大于图像宽度。轻微越界可以裁剪到边界严重越界直接删。极小框宽或高小于3像素的基本是误标删掉。重复框同一位置标了两个几乎重合的框会导致模型学习混乱用IoU大于0.9判断后去重。类别名不一致有的写person有的写Person或people统一成person。import os, xml.etree.ElementTree as ET def clean_voc(xml_dir, min_size3): bad_files [] for f in os.listdir(xml_dir): if not f.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, f)) root tree.getroot() w int(root.find(size/width).text) h int(root.find(size/height).text) for obj in root.findall(object): bbox obj.find(bndbox) xmin int(float(bbox.find(xmin).text)) ymin int(float(bbox.find(ymin).text)) xmax int(float(bbox.find(xmax).text)) ymax int(float(bbox.find(ymax).text)) if xmax - xmin min_size or ymax - ymin min_size: bad_files.append((f, too small)) if xmin 0 or ymin 0 or xmax w or ymax h: bad_files.append((f, out of bound)) return bad_files跑完这个清洗我在这类数据集上通常能发现1%到3%的问题样本。别小看这个比例脏数据对单类别检测的伤害是放大的因为它会直接污染唯一类别的决策边界。2.3 划分训练集、验证集、测试集的比例选择2189张怎么分常见做法是8:1:1或7:2:1。我的经验是单类别、场景单一的数据集验证集不用太大但测试集要留够。训练集1750张约80%验证集220张约10%测试集219张约10%为什么验证集可以小因为单类别任务的指标波动本来就小验证集主要用来监控过拟合和调学习率200张足够反映趋势。测试集留10%是为了最后给一个可信的泛化评估。划分时必须随机打乱而且要检查三个集合的目标数量分布是否均衡。如果某个集合里全是远景小人、另一个全是近景大人那评估结果就不可信了。我一般会统计每个集合的平均目标数和平均目标面积确保分布接近。注意如果你的数据是按视频帧连续抽的相邻帧高度相似随机划分会导致训练集和验证集泄漏。这种情况要按视频片段划分而不是按帧随机分。这份数据集如果是抽帧来的务必确认这一点。3. 监控场景下的模型选型与训练策略3.1 为什么YOLO系列是这类任务的首选地铁监控人员检测落地时最看重的往往不是极致精度而是速度和精度的平衡因为监控是实时流要跑在多路视频上。这就决定了YOLO系列天然占优。从YOLOv5到YOLOv8、YOLOv10这个系列在单类别检测上的表现一直很稳。我实测下来在2189张这个量级上YOLOv5s训练快收敛稳mAP0.5能到0.90左右适合快速验证。YOLOv8n/s精度略高尤其是小目标因为它的解耦头和更强的特征融合。YOLOv10端到端无NMS推理延迟更低适合对速度极敏感的部署。如果你只是想把这份数据集跑通、拿到一个能用的模型YOLOv8s是我最推荐的起点——精度和速度平衡得最好社区资源也最丰富。3.2 针对小目标和遮挡的anchor与输入尺寸调整监控场景最大的痛点是远处的小目标。默认的YOLO输入尺寸是640×640但地铁监控原图往往是1920×1080缩到640后远处的人可能只剩几个像素直接消失。我的处理策略有两个第一提高输入尺寸。把imgsz从640提到960甚至1280。代价是显存和推理时间增加但小目标召回率提升明显。实测在960下远景人员召回能比640高5到8个百分点。第二重新聚类anchor。虽然YOLOv8已经用了anchor-free但如果你用的是YOLOv5这类anchor-based的一定要用k-means在自己的数据集上重新聚类anchor。默认anchor是基于COCO的跟监控视角的宽高比分布差很多。# YOLOv5 重新聚类anchor python utils/autanchor.py --data data/metro.yaml --img-size 960 --thr 4.0 --n 9聚类出来的anchor会明显偏向瘦高型因为俯视角下人的宽高比跟平视不一样。3.3 数据增强哪些有用哪些是坑数据增强在监控场景里是把双刃剑。用对了能显著提升泛化用错了会引入不真实的样本反而伤害性能。推荐用的增强MosaicYOLO的招牌增强把4张图拼成1张天然增加小目标和遮挡样本非常适合监控场景。但要注意训练后期建议关闭Mosaic让模型在真实分布上收敛。HSV色彩抖动地铁站台光照变化大色相、饱和度、明度抖动能提升光照鲁棒性。随机缩放直接对应尺度变化必开。随机平移模拟目标出现在画面不同位置。要谨慎用的增强水平翻转可以用但要注意地铁场景里左右可能不对称比如扶梯方向翻转后可能产生不真实样本。单类别检测影响不大可以开。垂直翻转强烈不建议。监控是俯视垂直翻转后人就倒立了完全不符合真实分布。大角度旋转同理监控视角固定大角度旋转不真实。小角度±10度可以。# YOLOv8 数据增强配置示例 hsv_h: 0.015 hsv_s: 0.7 hsv_v: 0.4 degrees: 10.0 translate: 0.1 scale: 0.5 shear: 2.0 perspective: 0.0 flipud: 0.0 # 垂直翻转关闭 fliplr: 0.5 mosaic: 1.0 mixup: 0.13.4 迁移学习从COCO预训练到地铁场景2189张从零训练收敛慢且容易过拟合。用COCO预训练权重做迁移学习是标准操作。但这里有个细节COCO里person类别的特征跟监控视角有差异但底层特征边缘、纹理、形状是通用的。我的做法是分阶段训练冻结主干先冻结backbone只训练检测头学习率设大一点0.01跑20到30个epoch让检测头快速适配新场景。解冻微调解冻全部层学习率降到0.001用余弦退火跑100到150个epoch。低学习率收尾最后20个epoch把学习率降到0.0001关闭Mosaic让模型精细收敛。这套流程在2189张上通常能比直接端到端训练高出2到4个点的mAP。4. 训练过程中的监控与调参经验4.1 看loss曲线哪些波动是正常的哪些是危险信号训练时盯着loss曲线是判断训练是否健康的第一手段。但很多人不会看看到loss抖动就慌。我总结几个判断标准box_loss和cls_loss整体下降允许小幅震荡正常。震荡幅度在10%以内不用管。loss突然飙升到NaN学习率太大或者数据里有脏框零面积、越界。先查数据再降学习率。loss长时间不下降平台期可能是学习率太小或者模型容量不够。试试warmup或者换更大的模型。训练loss降但验证loss升典型过拟合。加数据增强、加dropout、或者早停。单类别检测的cls_loss通常会降得很快因为只有两类person和背景任务简单。如果cls_loss一直居高不下八成是标注有问题。4.2 mAP上不去时按这个顺序排查mAP卡在某个值上不去是最常见的问题。我一般按这个顺序排查从最可能的原因开始先看数据可视化预测结果看是漏检多还是误检多。漏检多说明小目标或遮挡没学好误检多说明背景干扰大。再看标注抽查几十张确认标注框是否准确。标注质量差模型再强也白搭。调输入尺寸小目标漏检优先提高imgsz。调增强遮挡严重加强Mosaic和随机裁剪。换模型前面都试过还不行换更大的模型或者更强的结构。调学习率和epoch最后才动这些因为影响相对小。这个顺序的核心逻辑是数据问题永远优先于模型问题。我见过太多人一上来就换模型、调超参结果发现是标注框偏了几个像素。4.3 混淆矩阵和PR曲线怎么读YOLO训练完会输出混淆矩阵和PR曲线。单类别检测的混淆矩阵很简单就person和background两行两列但信息量不小person被预测成background漏检看召回率。background被预测成person误检看精确率。对角线越深越好说明分类准确。PR曲线看的是不同置信度阈值下精确率和召回率的权衡。曲线下的面积就是AP。如果曲线在低召回区就掉下来说明高置信度预测里有误检如果在高召回区才掉说明漏检主要在低置信度区域。我一般会找一个平衡点作为部署阈值精确率和召回率都尽量高的那个置信度。监控场景通常更看重召回宁可误检不可漏检所以阈值会设得偏低一些比如0.25。5. 部署前的验证与常见落地问题5.1 用测试集做最终评估的正确姿势训练时用的验证集和最终评估用的测试集必须严格分开。我见过有人拿验证集当测试集报指标结果上线后性能暴跌。最终评估时我会做三件事在测试集上跑一遍记录mAP0.5、mAP0.5:0.95、精确率、召回率。按目标尺度分组评估把测试集里的目标按面积分成小、中、大三组分别看指标。监控场景里小目标指标往往最差这是重点优化方向。可视化失败案例把漏检和误检的图挑出来看找规律。是逆光是密集遮挡还是某个特定区域5.2 从PyTorch到部署格式的转换坑模型训好了要部署到实际监控系统里通常需要转成ONNX或TensorRT。这一步坑不少输入尺寸必须固定ONNX导出时如果用了动态轴部署端要对应支持。建议先固定成训练时的imgsz。NMS要一起导出YOLOv8可以端到端导出带NMS的模型省去部署端实现NMS的麻烦。归一化要一致训练时是除以255还是用mean/std部署时必须一模一样否则结果全错。类别数和类别名导出后确认输出维度是1类还是80类别把COCO的80类带进去了。# YOLOv8 导出ONNX yolo export modelbest.pt formatonnx imgsz960 opset12 simplifyTrue5.3 实测中那些文档不会写的经验最后分享几个我在实际项目里踩出来的经验都是文档里找不到的第一监控视频的帧间冗余要利用。单帧检测容易受瞬时遮挡影响实际部署时可以对连续几帧的检测结果做跟踪和投票能显著降低漏检和误检。ByteTrack这类轻量跟踪器配合检测器效果提升很明显。第二光照突变要单独处理。地铁站台进出隧道、灯光切换时画面会突然变亮或变暗模型可能瞬间失效。可以在预处理里加自适应直方图均衡CLAHE提升光照鲁棒性。第三别迷信高mAP。我见过mAP 0.95的模型上线后效果很差因为测试集和真实场景分布不一致。真正靠谱的做法是拿真实监控流做A/B测试看实际业务指标比如漏检率、误报率而不是只看离线mAP。第四数据集要持续迭代。2189张只是起点。上线后把模型出错的样本收集起来人工标注后加入训练集迭代几轮效果会有质的提升。这就是所谓的数据飞轮在监控场景里尤其有效因为真实场景的长尾情况太多了。关于这份地铁监控人员检测数据集我个人最深的体会是场景聚焦的数据集价值不在数量而在分布的真实性。2189张如果都是真实地铁监控抽帧那它比一万张网上爬的通用行人图有用得多。用好它关键是把格式转换、数据清洗、场景适配的增强、以及迁移学习这几步做扎实剩下的就是耐心调参和持续迭代了。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →