从零构建国内监控场景行人排队检测数据集全流程解析

从零构建国内监控场景行人排队检测数据集全流程解析
简介面向计算机视觉开发者与算法研究者的自制行人检测数据集基于国内某高铁站监控视角制作采集真实排队场景适合用于训练和评估YOLO等目标检测网络。资源包共9864个文件包含4932张JPEG原始监控截图与4932个XML标注文件标注由LabelImg完成、类别统一为“行人”整体约947MB压缩包内Annotations目录存放逐图标注信息JPEGImages目录存放原始图像结构清晰方便直接接入训练流程。此外附带拍摄原视频可用于连续帧行为分析和追踪性能验证。目前已有703人学习下载。该数据集样本量充足、场景真实覆盖复杂背景、遮挡和光照变化等情况有助于提升模型在智能安防、客流统计等现实任务中的鲁棒性是算法验证与毕设实践的实用基础资源可作为算法对比与论文实验的基准数据。 做监控场景下行人排队检测这个方向最早遇到的坎就是数据集。公开集里行人检测的很多但专门针对“排队”这一行为的、且是国内监控视角的几乎找不到现成的。国外那几个经典数据集要么是水平视角拍的商场走廊要么是稀疏人流拿到国内地铁闸机、医院挂号处、景区售票口这种高密度、强遮挡、俯拍角度又刁钻的场景里模型效果直接打骨折。所以我决定自己动手从零搭一个“国内监控视角行人排队检测数据集”这篇文章就把整个制作过程、踩过的坑、以及最终训练验证的完整路径展开聊聊。这套数据集的定位很明确用来训练“排队场景下的行人检测排队状态判断”模型。适合下面几类朋友参考一是要做智慧零售、客流统计、安防巡检这类项目的工程师二是想用YOLO、RT-DETR或MMDetection训练自定义检测任务但还没搞定数据构建的同学三是对监控视频结构化感兴趣想研究行人行为分析的研究者。我会尽量把从定义任务、设计标注规范、采集清洗、训练调参到效果评估的每个环节都讲透保证你看完能直接照着搭一套自己的方案。1. 内容整体设计与思路拆解1.1 为什么公开数据集撑不起“国内监控排队”这个场景先泼一盆冷水公开数据集不少但能直接用于国内监控排队检测的几乎没有。最常被引用的行人检测数据集比如Mall Dataset、UCSD Pedestrian拍摄角度多是平视或者轻微俯视场景集中在国外商场、校园步道人流的密度和排列方式跟国内早高峰地铁站排队完全是两码事。国内监控摄像头的典型架设高度在3到6米镜头下压角度通常在30度到60度之间画面里行人呈现的是明显的“头肩视角”排队时人与人之间的前后间距很小、左右错位严重遮挡是常态而不是个例。这就带来三个核心挑战第一俯拍角度下人形外观变化大平视数据集训练出的模型很容易把头顶和肩膀的轮廓错认成背景第二密集排队时人挨着人检测框之间大量重叠普通的NMS后处理会误删目标第三国内场景有大量特定元素比如隔离带、一米线、闸机口、围栏这些在公开数据集里几乎没有标注。所以无论从检测还是后续的行为判断来看自建数据集都是绕不开的一步。1.2 任务定义检测排队行人而不是只框出“人”项目标题里写的是“行人排队检测”我把它分成两层任务第一层是密集行人检测输出每个人的位置框第二层是排队状态判断判断哪些行人处于排队状态、哪些是路过或游离的。前者是目标检测的经典问题后者我选择在检测结果基础上做规则判定——通过一条预设的“队列线”从排队起始点到服务窗口来判断行人是否处于队列区域内。为什么不在模型里直接加一个“排队/不排队”的分类头我试过效果一般。原因是排队状态跟时间顺序强相关单帧图像里一个人站在队列尾端和站在队伍旁边视觉特征差异很小强行用分类头去做本质上是在让模型“猜”而不是“看”。更稳的做法是检测框负责空间定位队列线负责几何判定两者结合后的状态判断准确率明显更高。这也是很多工业级客流分析系统的通用方案。1.3 场景覆盖要让模型见多识广数据集的泛化能力取决于采集时的场景多样性。我最初只录了一个室内大厅的排队视频训练出来后在另一个室外售票点测试mAP直接掉了十几个点。后来重新规划采集把场景拆成四个维度室内医院/银行/食堂、室外景区/车站广场、半封闭地铁闸机口/安检通道、以及不同光照时段白天自然光、傍晚混合光、夜间红外模式。如果条件有限没法多场地采集至少也要保证同一场景下覆盖多时段、多机位角度否则模型很容易把某个场地的背景纹理学进去换个地方就失灵。2. 数据采集、清洗与预处理全流程2.1 采集设备与合规注意点我用的采集设备其实很普通海康的4MP网络摄像头架在三脚架上模拟监控视角高度大约3.5米镜头俯角约45度焦距手动调到能覆盖约8米长的队伍。有条件的可以直接用支持RTSP的摄像头接入NVR录制能顺便保留时间戳和原始码流方便后续按时间段分析。没有硬件条件的话用手机架在高处录制也行但要注意画面必须稳定、不能用运动镜头因为监控场景是固定的视角。这里必须提醒一句合规问题。监控视频涉及个人隐私自制数据集时如果画面里有清晰的、可识别的人脸一定要在发布前做人脸模糊处理或者干脆在采集时让参与人员签署知情同意书。我自己是安排同事、朋友扮演行人在明确的告知前提下进行录制这样后期发布、开源都不需要担心肖像权纠纷。另外不要直接去网上抓监控录像来标注来源不明数据既容易侵权也可能卷入法律问题。2.2 抽帧策略不要按固定间隔无脑抽很多人做视频数据集时喜欢每10帧抽一帧但实际效果很差。排队场景的行人运动非常缓慢连续帧之间几乎没区别抽出来的是大量近似重复帧不仅浪费标注时间还会让训练集高度自相关造成过拟合。我采用的是“按动作变化抽帧”先用光流或帧差法算出每帧的运动量只在运动量超过阈值的帧里随机抽取对于排队队列基本静止的时段则每隔3到5秒抽一帧。具体来说我写了一段小脚本处理原始录像。核心逻辑是对视频每15帧计算一次帧间绝对差均值mean absolute difference如果大于设定阈值就把当前帧加入候选池如果小于阈值就丢弃。然后从候选池里按目标数量比如想要2万张有效帧均匀采样。这样既保留了排队过程中的瞬时遮挡、插队、人员进出等关键变化又避免了大量剪影完全一样的冗余帧。2.3 清洗环节这些帧必须删抽完帧后不要急着标注先花半天时间做人工清洗。我总结了几类必须删除的帧严重过曝或欠曝导致行人轮廓丢失的镜头被遮挡的比如有人从摄像头面前走过画面中排队人数少于3人、完全没有排队结构的长镜头以及模糊帧——尤其是夜间红外开启时行人快速移动会产生拖影这种框就算标了模型也学不到有效特征。清洗后的数据量通常会缩水20%到30%这是正常的宁缺毋滥。清洗时我还会按场景和时间段做一次分层统计确保每个子目录下的样本数不悬殊。比如上午场景有8000帧夜间红外只有1500帧那我会在采样时对夜间段做加权避免模型在夜间模式上彻底失灵。2.4 数据增强合理增强别把监控视角搞乱训练阶段的数据增强能明显提升泛化能力但要结合监控视角做取舍。水平翻转、随机亮度对比度、高斯噪声、随机缩放擦除都是靠谱的增强方式我每轮训练都会用。但有两个增强要慎用一个是大幅旋转监控画面里的地平线、门框、柜台方向是有物理意义的旋转超过15度会产生不真实视角模型容易学到奇怪的对齐关系另一个是任意角度裁剪建议限制在水平方向做平移或小范围缩放垂直方向尽量不要动因为俯拍画面里人形的大小和它在图像中的位置远处小、近处大是强相关的破坏了这种关系反而有害。3. 标注规范与实操细节3.1 标注工具选型从LabelImg到X-AnyLabeling早期我用LabelImg它对VOC格式支持好操作简单但纯手动标注密集排队场景非常痛苦——队伍里20个人每个人都要在重叠遮挡的情况下框出准确边界。后来换成X-AnyLabeling最大优势是支持加载YOLO预标注模型跑“自动标注”先让模型给出初框人工只做调整效率提升了三倍以上。具体做法是先用一个在COCO上预训练的YOLOv8l行人检测模型跑一遍所有抽帧图像导出YOLO格式的初标框再在X-AnyLabeling里加载初标结果逐帧修正删除误检、补全漏检、调整框的大小和位置。3.2 类别设计不是只有“人”一个类虽然任务名叫“行人排队检测”但实务里我不建议只标person一个类。我最终的类别体系是三个person队列中的行人包括正在排队和短暂停留的人员。queue_line排队路线参考线从队首服务区延伸到队尾用折线标出。它是后续判断排队状态的关键几何依据。queue_area排队区域框标出队伍允许存在的范围。这个类主要用来过滤误检——如果检测框中心落在queue_area之外就判定为非排队人员。增加queue_line和queue_area两个类的好处是让几何判定有明确的锚点而不是靠手工画一条固定直线。不同摄像头架设角度下同一个排队的“队列线”应当由标注来定义而不是在代码里硬编码。如果你觉得三个类太繁琐至少也要保留person和queue_line两个类否则后续做排队状态判断时会非常被动。3.3 密集遮挡场景的标注要领密集排队中标注最大的难点是遮挡。我的标注原则是只标注可见部分的实际边界不臆测被遮挡的肢体。比如排在队尾的人半个身体被前面的人挡住框就应该贴着可见的肩膀和头部区域画而不是脑补整个人的轮廓。这样训练出来的检测器对遮挡反而更鲁棒因为在监控俯拍视角下模型本来能看到的就只是头肩和上半身强行标全身框只会引入大量噪声。另一个经验是距离摄像头远的人画面顶端框要尽量精确哪怕只有几十个像素也要标。很多人在标注时觉得远处小人不容易看清就跳过结果模型在远端漏检极其严重。这是影响mAP的大坑务必让标注人员专注把每个小目标标全。3.4 标注质检与数据统计标注完成后我建议做一轮“双人复核”——不是让第二个人从头看一遍而是只抽查容易出错的帧比如人数大于15人的密集帧、遮挡超过50%的帧、以及队列线横跨整幅画面的帧。抽查比例在10%到15%之间就行重点检查漏检和框偏。最终我的数据集统计大概是这样有效图像共21240帧标注person框约173500个queue_line标注约8240条每条是连续折线queue_area约7960个。类别数量上person占绝对多数所以在训练时我会对queue_line和queue_area适当提高loss权重或者用过采样来平衡否则模型会倾向于忽略这两个类。4. 模型训练与效果验证4.1 数据格式转换与目录结构标注工具导出的是JSON格式X-AnyLabeling默认我需要转成YOLO训练用的txt格式。转换时要注意坐标归一化YOLO的每个物体标注行是“class_id x_center y_center width height”全部用0到1的小数表示。我写了一个简单的转换脚本核心逻辑如下import json import os def convert_labelme_to_yolo(json_path, out_dir, class_map): with open(json_path, r, encodingutf-8) as f: data json.load(f) img_w, img_h data[imageWidth], data[imageHeight] lines [] for shape in data[shapes]: label shape[label] if label not in class_map: continue class_id class_map[label] points shape[points] xs [p[0] for p in points] ys [p[1] for p in points] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys) x_center (x_min x_max) / 2 / img_w y_center (y_min y_max) / 2 / img_h width (x_max - x_min) / img_w height (y_max - y_min) / img_h lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) base os.path.splitext(os.path.basename(json_path))[0] with open(os.path.join(out_dir, base .txt), w) as f: f.write(\n.join(lines))对于queue_line这种折线标注我会在转换时把整条折线的外接最小矩形min-area rectangle转成检测框保证它也能参与YOLO训练。虽然折线会被近似成矩形但在实际推理时我的算法会重新读取标注的原始折线坐标不会影响几何判定的准确性。数据集目录结构采用最通用的YOLO格式训练时方便直接套用ultralyticsdatasets/queue/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yaml划分比例我是8:1:1但划分时严格按“视频片段”分组而不是按帧随机划分。否则同一个视频的相邻帧会同时出现在训练集和验证集里验证指标会虚高部署后直接露馅。4.2 训练参数与调优记录我用的是YOLOv8m轻量版输入分辨率640×640batch size 16初始学习率0.01cosine衰减训练150轮。显卡是单张RTX 3090整个过程大约需要5个小时。这里要强调一个参数mosaic增强的开启会有帮助但在密集人群场景下mosaic拼接产生的图像边界会把行人切成两半导致部分目标框面积过大或过小所以我设置mosaic0.5随机对一半的样本应用而不是默认的1.0。另一个关键参数是NMS的IoU阈值我从默认的0.45调到了0.3。因为密集排队时两个人靠得太近检测框的重叠程度很高默认阈值会把其中一个框抑制掉导致漏检。调低阈值后重叠的目标更容易被保留但随之而来的是误检增加所以我还加了置信度阈值0.35作为平衡。实测下来mAP0.5提升约2.3%F1从0.81升到0.84。4.3 排队状态判断的逻辑实现模型输出检测框后我用这样一个状态判断流程首先把queue_line从图像坐标转成一条直线方程然后计算每个person检测框中心点到这条线的垂直距离。如果距离小于设定阈值我这边取30像素同时检测框的底部与队首服务窗口的水平距离小于某个值就判定为“排队中”否则标记为“非排队”。这套逻辑简单直接效果稳定而且不依赖特殊后处理库。如果场景里有多个服务窗口和多条队列可以给每条队伍分配独立的queue_line和queue_area然后逐个计算。只要数据集的标注没有交叉混乱这个方案做多队列检测也完全可行。后来我还加了时序稳定性约束——用队列序号和最近N帧的平均位置做卡尔曼跟踪避免单帧抖动造成状态误切这属于工程优化可以根据需要再展开。4.4 实测效果与误差分析在自己的测试集上完全未参与训练的独立监控片段共2600帧最终效果是person类的mAP0.5达到0.872mAP0.5:0.95为0.601queue_line类mAP0.5为0.794。排队状态判断的准确率在室内固定机位下约91%在室外多变光线下约83%。有个明显的误差来源是夜间红外场景人形轮廓和背景对比度低模型在夜间段的mAP只有白天的七成左右。后来我专门补了一批红外模式的数据并加入随机亮度扰动加强夜间段的mAP才拉回到白天的85%以上。5. 常见问题与排查技巧实录5.1 密集人群漏检严重如果发现测试时队伍中部的人总是检测不到先检查两件事一是NMS阈值是否过高优先把NMS IoU阈值从0.45调到0.3附近二是训练时mosaic增强是否把完整的人形切碎导致模型对小而完整的行人反而敏感度下降这种情况把mosaic调到0.5以下或不启用。如果仍然漏检可以尝试在标注里补充中远景小目标的“头肩区域框”这类目标完整身体框非常难学但头肩框特征更清晰、更容易收敛。5.2 queue_line类训练不收敛有朋友跑我的方案时反馈queue_line一直学不好。排查下来发现是数据格式的问题X-AnyLabeling导出的折线转换为矩形框时因为折线跨度太大生成的矩形几乎覆盖全图class imbalance直接爆炸。解决办法是不要把整条队列线转成一个框而是把折线按断点切分成多段短线段每段生成一个小矩形框。这样参与训练的queue_line目标数量大幅增加、形状也更规则收敛速度明显改善。5.3 跨场景泛化差训练集和测试集都来自同一个大厅模型指标很好看一换到另一个排队场景就拉胯。这种情况说明模型把背景纹理和光照当成了关键特征。应对思路是增强训练数据的场景多样性如果实在没有条件可以把原始图片做HSV随机扰动、随机背景替换、以及把高光区域做局部遮挡。我见过有团队用风格迁移生成不同天气模拟图也能有效提升泛化能力但训练成本较大作为后期优化手段更合适。5.4 标注效率太低总是来不及长时间纯手动标注密集人群速度是每小时200到300框整个数据集做下来人的精力会被榨干。我的经验是先跑一轮通用行人检测模型做预标注再人工修正对于排队这个具体任务还可以先把queue_area标出来在这个区域外的行人一律不标减少无效标注量。如果预算允许界面化标注工具和预标注流程配合使用是当前自建数据集性价比较高的方案。6. 踩坑总结与后续扩展做这个数据集的过程里最深的体会是“任务定义先行”。如果一开始没有把“行人检测”和“排队状态判断”这两层任务拆开我大概率会在标注类别上进行无休止的纠结是否要把插队的人单独设类是否要把服务窗口也标成物体这些问题全被前面的清晰方案解决了。建议所有想自建数据集的朋友第一周不要打开标注工具先写清楚任务文档、类别定义和判断逻辑。另一个心得是所有环节都要留日志。采集视频的时段、抽帧参数、清洗规则、标注版本、训练参数每一步改动都能回溯。AI项目最怕的不是效果差而是效果变好了却不知道哪个环节起了作用效果变差了也不知道改了什么导致的。这个数据集的后续扩展方向我认为有两个很值得做一是增加长时间连续片段的标注让模型结合时序信息直接输出排队时长和队伍长度变化曲线这对商场、医院管理特别有价值二是引入多机位协同把两个相邻摄像头的队列线拼接起来解决长队超出单一画面视野的问题。数据集的构建不是一个一次性工作它更像是一个持续迭代的基础设施越到后期越能看出前期细节打磨的价值。本文还有配套的精品资源点击获取

最新新闻

日新闻

周新闻

月新闻