电梯内人车识别数据集构建:从采集、标注到训练全流程
发布时间:2026/9/24 23:27:56来源:尧图网络
简介面向电梯监控场景的目标检测标注资源包含97张真实电梯内图像的人车标注信息覆盖 person、motorcycle、bicycle 三类目标适合算法工程师、计算机视觉学习者用于电梯内人车识别模型训练与效果验证也可直接作为 YOLOv5YOLOv10、Faster R-CNN、SSD 等主流目标检测框架的输入数据。压缩包共2000个文件由1999个 txt 标签文件和1个类别配置 yaml 文件组成整体大小约193.33MBtxt 标签为模型提供了边界框与类别编号yaml 文件可帮助快速完成类别映射与训练参数配置所有标注均已按目标检测常见格式整理解压后即可接入检测流程。目前已有200人学习/下载说明该场景数据受到一定关注。借助现成的标注格式与类别配置可省去自行采集、标框和整理数据的时间快速搭建电梯内人车检测的基线模型尤其适合有安防监控项目落地需求的实践者参考。1. 电梯内人车识别为什么值得单独做一套数据集电梯监控这类俯视、低照度、强反光的封闭场景直接套用通用目标检测数据集训练出来的模型落地时几乎都会翻车。原因不是模型不够强而是数据分布差太远通用数据集里大量是平视视角、光照充足的街景和室内图而电梯轿厢里是顶装摄像头人和电动车、轮椅、推车在画面里的尺度和姿态完全不一样。标题里“电梯内”三个字才是这套数据的真正价值点。人车识别在电梯场景下解决的是两类刚需一是防止电瓶车进梯入户二是统计轿厢内的人流密度和进出方向。前者需要准确区分“推着电瓶车的人”和“只是站着的行人”后者需要在高遮挡、低照度下稳定框出每一个人。这两个任务单独拿出来都不算难难在它们叠加在同一个俯视小视场里目标之间互相遮挡严重反光和不锈钢镜面还会让模型学到一堆伪特征。这篇笔记面向的是准备自己动手做电梯人车识别、或者正在选型数据集和训练方案的工程师。我会把数据从哪来、怎么标、怎么转格式、怎么验证讲透附上可以直接跑的命令和脚本也会把最容易踩的几个坑单独拎出来说。数据集的终点是喂给目标检测模型所以全文以 YOLO 系模型为主线但采集和标注的思路对 Faster R-CNN、SSD 同样适用。2. 数据从哪来公开集打底、自有采集补场景、合成数据补边界2.1 三类来源的搭配策略以及为什么不能只用公开集电梯内人车识别的数据集常见做法是三类来源混合公开数据集提供基础样本自有采集解决场景特异性合成数据补极端边界。只靠公开集训练出来的模型在真实电梯里表现普遍不理想——光照和视角是第一道坎第二道坎是类别的上下文依赖。比如一辆电瓶车在楼道里和平视摄像头下特征清晰但电梯轿厢里顶装俯视时车身被严重压缩轮胎和车把的特征几乎丢失模型很容易把电瓶车认成轮椅或大件行李。我一般建议的比例是公开集占 40%50%自有采集占 30%40%合成数据占 10%20%。公开集负责让模型学到人和车的通用特征自有采集负责让模型适应电梯的真实光照、镜面反射和遮挡模式合成数据负责制造那些“现实中很难碰到但碰到一次就出事”的边界情况。这里的“出事”指的是漏检电瓶车导致报警失效或者把拖把桶误检成人。2.2 采集场景矩阵不同时段、层站、朝向的覆盖标准自有采集的数据要覆盖足够多的变量否则训练集和验证集分布相似测试时一换电梯就崩。可以按一个场景矩阵来控制采集每个维度至少覆盖 3 档光照档位白天自然光、夜间节能灯、强顶光/无光红外补光。电梯内灯光通常是固定的但轿厢门开合会把走廊光引进来这一档的变化比很多室外场景还要剧烈。人员状态单人站立、多人拥挤、推电瓶车进入、推轮椅/婴儿车、搬运大件。这里注意“人车识别”的车不只是电瓶车轮椅、手推车、清洁车都算类别设计时要提前想清楚。目标朝向背对摄像头、侧身、正面、部分遮挡。俯视视角下人头顶和肩部的特征最重要不同朝向决定了模型能不能靠头部特征锁定目标。遮挡程度无遮挡、人员互遮挡、人和车互遮挡、轿厢门框遮挡。遮挡超过 50% 的目标是否还要标注需要在标注规范里明确否则标出来的边界框一致性很差。采集到的视频不要直接抽帧使用相邻帧高度相似会造成严重的数据冗余。我一般用视频抽帧工具按每秒 25 帧抽取再按场景相似度做去重保证同一段视频里不出现连续 10 帧以上的近重复样本。2.3 合成数据的引入方式仿真渲染和图像拼接的取舍合成数据不要一开始就用等真实数据训练出的初版模型跑出混淆矩阵后再来补合成样本。两个常用路线一是用仿真环境比如 Gazebo、Unity 的室内场景插件渲染电梯轿厢模型放置虚拟人物和车辆模型导出带标注的 RGB 图像二是用图像拼接把公开数据集里的车和人大致裁剪下来贴到真实电梯空景图上再手工修正标签位置。路线一生成的图像语义一致性高但渲染质感如果和真实监控差距太大模型学到的纹理特征反而会影响真实场景表现路线二实现简单但贴图边界的伪影容易被模型当成特征需要在增强阶段加入随机模糊、噪声和亮度抖动来稀释。合成数据在初版模型迭代里最大的作用是补“目标尺度极端”的样本——比如人在镜头正下方、车在画面边缘的场景这类真实现场很难刻意采集。特征和边界都清楚了下面讲标注和格式清洗。这是整个流程里耗时最长、也最容易返工的一步。3. 标注与格式处理从原始图像到能直接喂给 YOLO 的 txt3.1 类别设计的边界三类还是五类为什么不要在“车”上贪多电梯场景的类别设计我踩过直接照搬 COCO 类别表的坑。COCO 里人、自行车、摩托车是独立类别但电梯里出现的“车”绝大多数是电瓶车、轮椅、手推车、清洁车它们在 COCO 里根本不存在或属于其他类。照搬的结果是模型把轮椅当成椅子把清洁车当成车误检率直接失控。我建议按任务复杂度控制类别数量方案类别适用场景基础方案person, vehicle只做主流程报警不细分车型进阶方案person, e-bike, wheelchair, cart需要区分车辆类型方便物业管理不同策略细粒度方案person, e-bike, wheelchair, baby_cart, luggage场景复杂要求输出详细事件标签注意类别越多平均到每个类别的标注样本量要求越高。电梯数据集本身采集成本高类别数量从 3 类增加到 5 类总样本量至少要翻一倍才能维持同等精度。现有公开的人车识别数据集多为二分类或三分类直接在它们基础上增加自定义类别会导致标签不兼容需要从标注阶段重新规划。3.2 标注工具的选型LabelImg 和 X-AnyLabeling 哪个更省事目标检测常用的标注工具我实际用过两套LabelImg 和 X-AnyLabeling。LabelImg 是老牌工具写标签文件时直接用 Python 生成 VOC 格式。# 标注环境准备Ubuntu 20.04/Windows WSL 均可 pip install labelimg labelimg # 启动图形界面打开图像目录后开始画框LabelImg 把标注结果保存为 Pascal VOC XML 格式每个图像对应一个同名 XML。标注时设置difficult1可以标记模糊目标后续转 YOLO 格式时可以选择是否排除。X-AnyLabeling 更适合配合预标注使用——先加载一个 YOLO 或 SAM 模型自动预标注然后人工修正电梯这类场景重复度高的数据能省不少时间。提示无论选哪个工具标注前的类别顺序表必须先定死。YOLO 格式的类别索引是按标注文件里的顺序从 0 开始编号的训练时改了类别顺序旧标注全部作废。电梯内这类遮挡严重的场景标注规范至少需要两条硬性规则一是被遮挡超过 60% 的目标不标注二是一个目标只用一个边界框禁止把一个遮挡目标拆成多个框。如果不立这个规矩标注员之间的一致性会变得很差模型学到的边界框回归目标本身就是乱的。3.3 VOC 转 YOLO 的脚本直接复制改路径就能用标注完成后最终要转成 YOLO 系列的 txt 格式——每行class_id cx cy w h坐标值是归一化到 0~1 的浮点数。下面这个脚本是把 VOC XML 批量转成 YOLO txt 的最小实现import os import xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(xml_path, out_dir, class_names): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) out_lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in class_names: continue # 未登记的类别直接跳过 cls_id class_names.index(cls_name) bndbox obj.find(bndbox) x1, y1 float(bndbox.find(xmin).text), float(bndbox.find(ymin).text) x2, y2 float(bndbox.find(xmax).text), float(bndbox.find(ymax).text) # 转归一化中心点坐标注意边界裁剪 cx min(max(((x1 x2) / 2) / img_w, 0.0), 1.0) cy min(max(((y1 y2) / 2) / img_h, 0.0), 1.0) w min(max((x2 - x1) / img_w, 0.0), 1.0) h min(max((y2 - y1) / img_h, 0.0), 1.0) out_lines.append(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) out_path Path(out_dir) / (Path(xml_path).stem .txt) out_path.write_text(\n.join(out_lines), encodingutf-8) return out_lines if __name__ __main__: classes [person, e-bike, wheelchair] xml_dir annotations_xml/ out_dir annotations_yolo/ os.makedirs(out_dir, exist_okTrue) for f in os.listdir(xml_dir): if f.endswith(.xml): voc_to_yolo(os.path.join(xml_dir, f), out_dir, classes)这段脚本里有三个容易忽略的点。第一个是bndbox的读写路径——用root.find(size/width)这种写法时如果 XML 结构里有嵌套标签或命名空间查找会失败建议标注完先检查一下size是否存在第二是cx cy w h全部做了 0~1 裁剪防止标注时手滑画出了图像边界导致训练报错第三是没登记的类别直接跳过而不是报错退出——这么做是为了让你在转换时容忍空标注文件但需要在训练前统计一下跳过了多少样本占比超过 5% 说明类别设计或标注流程有问题。3.4 划分训练/验证/测试集时要避开的坑很多教程会直接随机划分数据集但电梯场景这么做有大问题——同一段视频抽出来的连续帧会被分到训练集和验证集导致验证集泄漏精度虚高。我采用的是按“视频片段”划分而不是按“图像”划分# 目录结构先按片段组织好 data/ 原始素材/ clip_01/ # 同一段电梯监控视频抽出的帧和对应的标注 clip_02/ clip_03/ # 用 skimage 库的 train_test_split 按片段索引划分 python - EOF from sklearn.model_selection import train_test_split import glob clips sorted(glob.glob(原始素材/clip_*)) train_clips, val_clips train_test_split(clips, test_size0.15, random_state42) # 把划分结果写入 txt供训练脚本引用 with open(train.txt, w) as f: f.write(\n.join(train_clips)) EOF按片段划分的核心思想是同一段视频的图像只能出现在一个集合里这样验证时模型看到的是“完全没见过的一段监控记录”而不是“同一段视频里抽出的几个新画面”。实际测试下来前者验证的 mAP 通常会比随机划分低 510 个百分点但这才接近真实部署的表现。划分后还要确认每个集合里的类别分布比例跟总体一致不能训练集里全是人、验证集里全是电瓶车。4. 数据增强与模型训练把数据集的潜力榨干净4.1 电梯场景必开的增强组合旋转、光照抖动和 mosaic 的叠加顺序电梯轿厢里视角相对固定但同一段视频里目标朝向和光照变化仍然明显。数据增强的目标不是把场景变得花哨而是让模型对光照、遮挡和尺度变化更鲁棒。我常用的增强组合是Mosaic拼图、Rotation小角度旋转、HSV 扰动亮度/饱和度微调和 RandomPerspective随机透视。这些增强用 YOLO 系自带的augment参数就能控制。以 YOLOv8 的训练命令为例yolo detect train \ modelyolov8n.pt \ dataelevator.yaml \ epochs120 \ imgsz640 \ batch16 \ mosaic1.0 \ degrees10 \ hsv_h0.015 \ hsv_s0.5 \ hsv_v0.4 \ scale0.5 \ fliplr0.5 \ projectele_train \ nameexp01几个参数值得专门说。degrees10控制旋转范围电梯里目标不会倒置旋转超过 15 度反而会让模型学到不存在的姿态scale0.5控制尺度抖动配合小目标增强使用fliplr0.5是水平翻转概率电梯内摄像头固定水平翻转不会破坏语义但要注意车牌这类对称性差的特征会受到影响。Mosaic 增强在训练后期建议降到 0.5否则模型会对拼图边界产生依赖。4.2 小目标问题为什么电梯里的人头比人身体更可靠电梯顶装摄像头的视角里距离镜头远的目标在图像中的像素面积很小。一个站在角落的人身体可能只有 40×80 像素但头部仍有 25×25 像素。这种情况下检测小目标不能只看全局特征而是要把注意力放到头部区域。处理方法有两个一是调整数据集标注策略对小目标额外标注一个 head 类别让模型学两个检测头的输出二是用切片推理先把图像切分成若干 320×320 的 patch分别推理再合并结果。切片推理的代价是推理耗时成倍增加在电梯监控这种低成本边缘设备上不一定扛得住。所以更常用的做法是在标注阶段加一条规则目标高度小于 32 像素时只标注可见的头部不标身体。这样模型学到的是“电梯里如果有人头就是一个人”而不是“电梯里如果有完整人形就是一个人”。后者在俯视场景里经常会因为遮挡直接失效。4.3 用 YOLOv8 训练自己的数据集配置文件的完整写法训练前需要把数据集描述成 YAML 配置文件路径和类别顺序必须与第 3 章转换脚本里的完全一致# elevators.yaml path: /home/user/elevator_dataset train: images/train val: images/val test: images/test nc: 3 names: 0: person 1: e-bike 2: wheelchair运行训练命令时data参数直接指向这个 YAML。nc的值必须与names里的条目数一致否则 YOLO 在构建数据加载器时会报类别索引越界。出现这个报错时不要急着调模型先把 YAML 里的nc数一遍再数names里的数量绝大多数情况是这里的手滑。训练过程中需要盯三个指标train/box_loss是否单调下降、val/box_loss是否在某个 epoch 后回升过拟合信号、metrics/mAP50是否达到预期阈值。电梯数据集的样本量通常在几千到几万张预训练权重yolov8n.pt起步的训练时间不会太长但不要直接上yolov8x过拟合风险和显存占用都不划算。5. 数据验证与迭代如何判断数据集够不够用以及 5 个典型踩坑记录5.1 数据集质量验证的完整闭环判断数据集是否合格不能只看 mAP 数字。我一般从三个层面做验证第一层是标注质量抽检随机抽取 5% 的标注文件可视化叠加在原图上人工核对边界框是否贴合目标轮廓、有没有漏标或错标第二层是类别分布检查统计每个类别在训练集/验证集中的占比偏差超过 5% 就要考虑补样本或调整划分第三层是模型训练的逆检验——用这个数据集训练出的模型在真实场景视频上做推理统计漏检和误检的具体模式。第三层最有价值。如果推理结果里大量出现“镜面反射导致误检人形”说明数据集中没有包含电梯门反射样本需要在采集阶段专门补一段“开门状态镜面反射”的视频如果出现“电瓶车在画面边缘漏检”说明边缘位置的目标尺度和位置多样性不足需要补边缘区域的标注框。数据集的迭代不是一个线性过程而是“训练-推理-找错-补数据”的循环循环两三轮之后数据质量才会趋于稳定。5.2 踩坑记录一模型把电瓶车全部认成轮椅现象训练后的模型在验证集上 mAP50 有 0.87但在真实电梯视频里电瓶车几乎全部误检为轮椅。原因数据集中电瓶车样本多来自平视拍摄模型学到的是侧面轮廓特征而轮椅样本大多来自电梯内俯视镜头两者在俯视角下轮廓高度相似。数据里“俯视电瓶车”的样本不足模型找不到足够区分特征。解决在采集阶段专门补拍“电瓶车推入电梯后从顶视角看”的样本并把这些样本在增强阶段用随机透视进一步变换视角。处理后误检率下降了一半以上但并没有完全消除——最终在推理阶段加了一个规则如果检测到轮椅检查其移动速度超过 2 m/s 则重新判定为电瓶车。注意目标检测模型输出的是静态单帧的框不带时序信息。电梯场景里很多误检可以通过帧间运动特征消除但这不是数据集能解决的问题需要在后处理阶段单独做。5.3 踩坑记录二验证集 mAP 高但实际检测频繁漏人现象验证集 mAP50 达到 0.92但实际部署后轿厢角落站立的人经常漏检。原因验证集的划分方式出了问题——随机划分导致同一段视频的连续帧同时出现在训练集和验证集模型在验证时“见过的”数据占比过高mAP 虚高。真实场景里的角落样本在训练数据里占比本来就低被随机划分进一步稀释。解决改成按视频片段划分第 3.4 节的做法用train.py里的clip索引重新生成数据划分。重新训练后验证集 mAP 降到 0.81但实际部署的漏检率明显下降。这个数据表明验证集 mAP 的绝对大小没有意义它和真实场景表现的差距才是有价值的信息。5.4 踩坑记录三标注时把“车”的边界框画到了人身上现象模型训练 loss 收敛后输出的人体框普遍偏大人车重叠时框的中心偏移到车身上。原因标注阶段多目标高度重叠时采用了“一个框框住人车”的偷懒做法边界框的 GT 本身包含了背景和另一个类别模型回归目标混乱。解决修改标注规范要求即使人和车紧贴也必须分别画两个框宁可小框不要大框。对已有的标注文件用脚本自动检测——如果一个类别的边界框与另一类别框之间的 IoU 大于 0.7 且面积差超过 30%则标记为疑似问题样本人工逐条复核。这一轮清洗下来边界框的回归精度提高了 12%。5.5 踩坑记录四镜面反射场景导致的目标“复制”现象电梯内不锈钢镜面导致同一辆车在画面中出现两次模型输出两个框后处理 NMS非极大值抑制无法消除触发多次报警。原因数据集中缺少镜面反射样本模型把镜面里的倒影当成真实目标。这不是模型能力问题而是训练数据分布覆盖不足。解决在采集阶段把带镜面反射的电梯场景作为独立类别纳入训练数据增强阶段额外增加垂直翻转模拟反射方向同时在推理后处理里加入基于空间位置的重叠抑制——两个目标框的中心距离小于真实目标最小物理尺寸对应的像素距离时保留置信度更高的一个。这个位置约束的阈值可以通过数据集里的目标尺寸分布统计得到我根据统计把阈值设成了 45 像素。5.6 踩坑记录五负样本缺失导致的“幽灵目标”现象模型在无人无车的电梯空景里频繁输出矩形目标框置信度还不低。原因训练数据中空电梯场景占比太低模型学到“这个场景里必有目标”输出被背景纹理中的亮斑触发。解决在数据集中加入 20% 的空景负样本不带任何标注框训练时这些样本只参与背景特征的学习。这个改动不需要重新采集从已有的视频片段里把无人时间段剪出来抽帧即可。加了负样本后“幽灵目标”数量直接下降了一个数量级。负样本也要严格按片段划分进训练/验证集防止空景泄漏到验证里造成指标假阳性。6. 数据集的可扩展性从 3 类识别到多楼层事件分析的演进路径电梯人车识别数据集的价值不在于一次性训练跑完而在于能持续迭代和扩展。比如项目前期只做“person”和“e-bike”两类识别但运营过程中发现推轮椅的用户也需要关注这时不需要重新标注全部数据只需要在“训练-验证-增量标注”的框架下补标注轮椅类别然后让模型在旧数据基础上增量训练。增量训练时要注意冻结底层的特征提取层只训练检测头否则旧类别的精度会掉下来。扩展到多楼层事件分析时数据集的需求又不一样。此时不只是“轿厢内有没有人/车”还要知道“人从哪层进、哪层出”“是否在轿厢内停留过久”。这类需求要求数据集包含视频帧之间的时序关系而不仅仅是单帧图片加边界框。解决思路是在数据集里保留“片段 ID”和“帧序”字段标注文件除了目标检测的 txt额外维护一个片段元数据表记录电梯编号、楼层、时间段等信息。这样后续做跟踪、ReID行人重识别或行为分类时可以直接复用同一套底数。在落地阶段我通常会从数据集中切出一个“鲁棒性子集”专门放那些光照异常、大角度遮挡、镜面扭曲的样本所有模型改动都必须在这个子集上通过后才能上真实设备。这个习惯帮我拦下过好几次“训练指标很好但现场翻车”的变更。比如有一次我给模型加了一个新的数据增强方式整体 mAP 提高 1.8%但鲁棒性子集上的小目标召回率掉了 6%最终回滚了这个改动。电梯人车识别这类垂直场景的数据集做一次不难难的是把它做成一个能跟着业务演进的资产。每一次补充样本、调整标签、增加片段都建议顺手把数据集的版本号、类别表、划分方式的变更记录写进一个简单的 README。半年后回来看这份记录比模型权重本身更有价值。希望这篇笔记能帮你少走一段弯路把数据集的功夫下在真正决定模型上限的地方。本文还有配套的精品资源点击获取
网站建设高端定制企业官网