电梯开关及乘客检测数据集:从YOLO/VOC格式到实战避坑指南
发布时间:2026/10/2 3:17:58来源:尧图网络
简介一套面向电梯场景目标检测任务的数据集包含电梯开关门状态以及轿厢内有无乘客两类核心识别维度适合训练安防监控、智能楼宇或电梯运维场景中的视觉检测模型。资源共610张清晰拍摄的jpg图片并同时提供VOC格式的xml标注和YOLO格式的txt标注使用者可依据框架直接切换无需额外转换格式。压缩包总体积约27.8MB内含1832个文件其中jpg图片610张、xml标注610个、txt标注612个四类标注分别为closed_elevator、empty_elevator、open_elevator、people_in_elevator累计矩形框1230个各类别样本分布较均衡可用于模型训练与验证。已有160人学习下载适合有一定目标检测基础、需要标准格式数据快速开展训练或算法评测的开发者使用。1. 电梯开关及有无乘客检测数据集610 张图凭什么够用如果你负责楼宇智能化或安防项目大概率会卡在同一个问题上项目方要“电梯门开关状态 轿厢有没有人”两个结果用来做梯控联动和困人告警但现场视频不能直接外发训练手里只有一台相机和两周交付时间。这时候一份像“数据集电梯开关及有无乘客检测数据集yolovoc格式610张.zip”这样的数据包就会很有吸引力它把两个任务合并成一整套标注并且同时给出 yolo 和 voc 两种格式省去你从头标框再互转格式的半天功夫。610 张图不算多但对“门开/门关/有人”这类状态判别任务来说只要场景覆盖到位、框标得干净完全够做一次及格线以上的电梯检测基线再靠现场数据迭代。这个标题真正能帮你解决的问题是把“电梯门开关”与“有无乘客”变成两个可训练的目标检测任务而不是让你拿一套通用模型硬上。2. 先读标注再定类别yolovoc 双格式数据集的体检清单拿到任何检测数据集我的习惯都不是直接开训练而是先把目录结构和标签文件读一遍。很多项目翻车都是因为类别名和实际含义对不上或者标注文件和图片不在同一层目录YOLO 训练器报了 None 还不知道错在哪。2.1 第一件事是拆包看目录结构而不是直接开始训练电梯这个场景里标注对象通常只有三类门开、门关、人。有的数据集会把门框、楼层按钮也标进去当作辅助类也有的会把“有人”直接写成 person。先做一次目录体检能看到图片和标签是否一一对应也能确认 yolo 和 voc 两份标注是不是同一个版本。cd elevator_dataset find . -maxdepth 3 -type d | sort echo --- 图片数量 --- find . -name *.jpg | wc -l echo --- 标签数量 --- find ./labels -name *.txt | wc -l echo --- 类别定义 --- cat labels/classes.txt这个命令只是看包的结构。图片数量和标签数量应该大致相等如果图片 610 张、txt 只有 580 份说明有 30 张图漏标或标注文件没生成完整。classes.txt 是 YOLO 项目里常见的类别清单一行一个类别名顺序就是类别索引。读到这三类时要先想清楚 door_open 和 door_close 的边界门开到一半算开还是算关电梯里有人但门正在关person 和 door_close 能不能同时出现2.2 三个类别怎么定义door_open、door_close、person 的边界电梯门开关检测最容易踩的第一个坑是边界定义不一致。有人在标注时把门缝超过 20 厘米记为 open有人把门完全静止才算 open还有人把门套区域整个框进 box。同样 610 张图三种标准训练出来的模型行为完全不一样。所以拿到这份数据我先建议你打开几张有代表性的图把框和图片叠起来看不要只信 classes.txt 里的名字。常见做法是door_open 框住两侧门扇打开后露出的通口区域door_close 框住闭合后的门缝和门板重叠区域person 框住人体可见部分包括被门挡住一半的躯干。如果标注里还有 elevator door 这种父类就把它当背景处理或者合并到 door_open/door_close 里。这里有一个小经验门在中间状态时按地面投影和门扇夹角来判断夹角大于约 30 度就算 open小于 30 度算 close。配置文件里后面要不要做类别合并取决于原数据标注粒度。2.3 用一段 bash 统计各类别数量防样本严重偏斜610 张图片看着少如果三类分布变成 500 张关门、80 张开门、30 张有人那训练结果大概率是开门和有人全部漏检。先把类别数量统计出来心里有数再谈训练策略。for f in labels/train/*.txt labels/val/*.txt; do awk {print $1} $f | sort | uniq -c done | awk {count[$2] $1} END {for (c in count) print c, count[c]} | sort -k2 -n这个统计把每个 txt 文件里出现的类别索引逐行读出来再用 awk 按类别累加。如果 labels 目录没有按 train/val 分先去掉路径前缀直接labels/*.txt跑一遍。看到的结果如果是 door_close 500、door_open 300、person 200 这类比例说明原始数据做过一定的均衡可以直接用。如果 person 只有 40 个框就要考虑在训练参数里给 person 加类别权重或者干脆用“有人/没人”作为二分类减少正样本不足的压力。3. 把 VOC XML 转成 YOLO TXT兼容脚本与三个归一化细节标题既然给了 yolovoc 两种格式工作流里最常见的需求是把 VOC 当原始真值把 YOLO 当训练输入。VOC 格式存的是xmin,ymin,xmax,ymax绝对坐标YOLO 格式要的是归一化后的x_center,y_center,width,height。两者之间的转换不难但细节错一个整个训练就在用错框。3.1 一个可以直接跑的 VOC 转 YOLO 脚本下面的脚本按单张图片转换xml 和图片同名不同后缀遍历目录就能把整套 VOC 转成 YOLO。import os import xml.etree.ElementTree as ET CLASSES [door_open, door_close, person] # 顺序必须与 classes.txt 完全一致 def convert_voc_to_yolo(xml_path, txt_path): tree ET.parse(xml_path) root tree.getroot() size root.find(size) width float(size.find(width).text) height float(size.find(height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in CLASSES: continue cls_id CLASSES.index(name) box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) x_center (x1 x2) / 2.0 / width y_center (y1 y2) / 2.0 / height w (x2 - x1) / width h (y2 - y1) / height # 做出界保护坐标略超图片范围就按边界钳制 x_center max(0.0, min(1.0, x_center)) y_center max(0.0, min(1.0, y_center)) w max(0.0, min(1.0, w)) h max(0.0, min(1.0, h)) if w 0.001 or h 0.001: continue # 面积几乎为 0 的框直接丢弃 lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(txt_path, w) as f: f.write(\n.join(lines)) if __name__ __main__: xml_dir voc_xml out_dir yolo_txt os.makedirs(out_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue base xml_file[:-4] convert_voc_to_yolo( os.path.join(xml_dir, xml_file), os.path.join(out_dir, base .txt) )这段代码里CLASSES 列表顺序就是最终 txt 文件里的数字索引。如果把 door_open 放在 index 0、door_close 放在 index 1、person 放在 index 2那每行开头是 0、1、2。转换时以 xml 里的 size 节点为基准因为有的视频抽帧会把原图缩放后再标注直接用图片实际尺寸读取更保险。钳制部分看起来多余但电梯监控边缘经常有画面裁切标注工具偶尔会把框拉到画幅外钳制之后至少不会让 YOLO 训练报 box 越界的错。3.2 类别索引、尺寸读取和边界钳制最容易错的三个参数每个参数都有一次踩坑机会。类别索引错是最隐蔽的转换出来的 txt 数字和 classes.txt 对不上训练时 loss 照常下降但输出类别永远是错的。解决方法是转换后随手跑一次head -3看每一行首位数字再回看 xml 的 object name 确认。尺寸读取错一般发生在图片是竖屏的电梯轿厢内景时。xml 里 width1080, height1920但有些代码写成float(size.find(width).text)和float(size.find(height).text)时忘了 height顺序反过来人就从站在原地变成了横躺在电梯里。第三处容易错的是 w 和 h 的钳制如果框完全在画面外x_center 钳到 0w 钳到 0这个框会退化成一个点YOLO 训练会出现 loss 突跳。脚本里w 0.001的判断就是对它做的过滤。3.3 回画标注框验证转换结果用 OpenCV 做一次目检数字对不对最后要用眼睛确认。转换完随便挑三十张图把 txt 里的归一化坐标还原成坐标画上去如果框和电梯门缝、人体轮廓贴合转换链路才算通。import os import cv2 def draw_yolo_box(image_path, txt_path, classes, out_path): img cv2.imread(image_path) h, w img.shape[:2] with open(txt_path) as f: for line in f: parts line.strip().split() if not parts: continue cls_id, xc, yc, bw, bh parts x1 int((float(xc) - float(bw) / 2) * w) y1 int((float(yc) - float(bh) / 2) * h) x2 int((float(xc) float(bw) / 2) * w) y2 int((float(yc) float(bh) / 2) * h) color (0, 255, 0) if cls_id 0 else (0, 0, 255) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) cv2.putText(img, classes[int(cls_id)], (x1, y1 - 8), cv2.FONT_HERSHEY_SIMPLEX, 0.8, color, 2) cv2.imwrite(out_path, img)这里 cls_id 是字符串转 int 后再去 classes 列表里取名字。打印时顺便把框的面积列出来如果看到大量宽度不超过原图宽度 3% 的竖条框那多半是标注只框了门缝没框门板后面训练时模型会把细缝当成唯一特征最后变成“见了缝就报开门”。4. 用 YOLOv8 训练电梯场景数据集切分、data.yaml 与关键超参数格式准备妥当后进入训练环节。610 张图不至于要用大模型硬扛YOLOv8n 或 YOLOv8s 已经足够。关键在于把数据集结构切好让训练器知道哪张图带哪份标签再把超参数调成“小数据集模式”否则模型会高方差地乱跳。4.1 切分目录与 data.yaml让 YOLOv8 直接读 610 张图同一份数据YOLOv5 和 YOLOv8 都希望 images 和 labels 按 train/val 分成两个大目录txt 和 jpg 名字一致。我一般按 8:2 切也就是 488 张训练、122 张验证。不搞独立测试集因为 610 张本身就紧留出测试集后训练数据只剩四百多张效果波动太大。mkdir -p images/train images/val labels/train labels/val python3 split.py # 按 8:2 随机划分并把 txt 同步移动切分脚本没什么玄学按文件名随机撒种子就行重点是要保持图片和标签相同比例移动。电梯数据有个特殊性连续帧不能同时落进训练集和验证集否则模型看到的是同一扇门在不同角度下的重复帧验证 mAP 虚高。如果这份数据集原始来源是按视频抽帧的建议先把帧号排序按时间窗口切而不是纯随机切。data.yaml 写清楚路径和类别名yolo 训练命令读它即可。path: /home/user/elevator_dataset train: images/train val: images/val names: 0: door_open 1: door_close 2: personnames必须与 labels/classes.txt 顺序一致。这里最容易犯的错是 val 路径写成 images/val 但标签文件实际还在 labels/valYOLOv8 默认会直接把 images/val 下同名 txt 去找如果不在就报 label 缺失。目录结构里 images 和 labels 是兄弟目录训练器会自动去 labels/ 下匹配。4.2 输入尺寸、batch 与 epoch小数据集最容易表现突兀的三个旋钮电梯门的宽高比和普通目标不太一样门开时目标接近一个竖长方形门关时是一个窄条person 又是一个明显的竖向目标。imgsz 给 640 能照顾中距离摄像头视角但不要盲目推到 1280因为 trainer 内部会对图片缩放原图里 600 像素高的门在 1280 下并不会多出更多语义信息反而让训练变慢、batch 变小。参数推荐值说明imgsz640兼顾门框与人体细节batch1632显存够就用 32小于 8 容易 BN 抖动epochs80120用早停控制不固定跑满patience1015验证 mAP 连续不涨就停lr00.0050.01预训练权重下不宜过大warmup_epochs3小数据集让 BN 先热起来batch 是 610 张图里最关键的一个参数。电梯场景往往只有一台不贵的 GPU显存 8G很多人顺手设成 batch4结果训练 loss 能降但验证集表现随机因为 BN 层在极小 batch 上计算的均值和方差太抖。常见做法是 batch 至少 16如果显存不足就把 imgsz 降到 480而不是把 batch 压到 4。epochs 则要看早停脸色通常 610 张图 80 轮内就收敛了跑满 300 轮只会过拟合到电梯轿厢的固定纹理上。4.3 预训练权重和冻结 backbone小数据集的成熟方案我建议直接用 YOLOv8n.pt 或 YOLOv8s.pt 开始而不是随机初始化。电梯门和人的特征在 COCO 预训练权重里已经学得不错micro 权重在 610 张图上更快收敛。这里有一个容易误导新手的点预训练权重不等于直接跳过训练只是给了模型一个更好的起点。yolo train dataelevator.yaml modelyolov8n.pt \ epochs80 imgsz640 batch16 patience12 \ lr00.005 warmup_epochs3yolov8n.pt如果本地没有训练器会自动下载预训练权重。训练时需要理解几个关键位置lr0 控制整体学习率在小数据集上过高会导致 loss 在验证阶段爆掉warmup_epochs 让学习率从很小的值爬升BN 层的统计量能先稳定下来。如果动手能力强前 10 轮可以先冻结 backbone只训练检测头让模型先专注学习电梯门的边框分布第 10 轮之后解冻 backbone 做整体微调。610 张图不足以让 backbone 重新学习通用视觉特征但足以微调它去关注门缝和人体轮廓。冻结部分在 YOLOv8 里没有直接的一行参数需要改 trainer 逻辑一般我会在项目里这样处理前 10 轮把 backbone 参数 requires_gradFalse之后再置回 True这样能明显减少过拟合。4.4 用混淆矩阵和 mAP 看这两个任务的真实表现训练结束后不要只看总体 mAP那会把问题藏住。电梯项目真正要看的是 door_open 与 door_close 之间的混淆程度以及 person 帧上面的漏检率。Ultralytics 训练完之后会在 runs/detect/train 下生成 confusion_matrix.png打开它检查“door_open 被预测成 door_close”的格子是不是非零值密集。yolo val modelruns/detect/train/weights/best.pt dataelevator.yaml验证命令跑完后重点看两个数一个是各类别的 mAP50 和 mAP50-95另一个是验证集图片上门框框的可视化结果。如果 door_open 的 mAP 高但框势明显整体偏移说明标注边界把门套也包进去了模型学到的是门套特征而不是门洞特征。person 这个类在轿厢内通常比在候梯厅好检测得多因为背景简单、人体站姿完整如果 person 的 mAP 出奇低多半是样本数量和遮挡问题后面靠现场补帧比靠调参快。5. 电梯场景训练避坑记录门缝阴影、镜面误检与 BN 崩溃这套任务看起来简单实际训练时最容易翻车的几个点都藏在“电梯环境”本身而不是模型结构里。下面五条是我在多轮实战里反复踩过的坑每条都按照现象、原因、解决的顺序写清楚。5.1 开门与关门互相混淆门缝反光和标注框越界成了“同一个特征”现象训练集 mAP 在 0.85 以上验证图里大门关闭时模型却报出 door_open而且框的位置都在门缝中线附近。原因电梯轿厢门关闭时中间会有一条竖直反光线标注时如果把 door_close 的框画得过大把门缝反光区域也包进去模型学到的就是“一道亮线”而不是“两片门板合拢”。解决把 door_close 的框收窄只包左右门板重叠区域door_open 的框放宽到门洞两侧并配合数据增强里的随机亮度变化。如果原标注已经带了这个毛病别急着重新标 610 张先用一个小脚本把关闭状态框的宽度缩到原来的 80%代价略高但比重标快得多。5.2 乘客被镜面电梯壁误检人在反射区域出现多框现象ushaped 的轿厢里有三面镜子实际只有一个人站在中间模型却输出两个 person 框一个在人体上一个在镜面反射里。原因YOLO 训练时把镜面中的人影也当成了正样本推理阶段镜面里的残留人影会产生高置信度响应。解决先看数据集里镜面场景占多少比例。如果只是少数几张加一两种镜像翻转增强没有用反而让人影更强。有效做法是把镜面里的标注框去掉或者在训练 loss 里指定 ignore 区域更简单的手段是部署端做时序去重同一目标相邻两帧的 IoU 大于阈值且位置在镜面区域直接丢弃一个框。这条坑说明 610 张数据集不会自带“电梯壁反光”这个语义要靠推理端补。5.3 mAP 在第三个 epoch 突然掉到 0小 batch 的 BN 崩溃现象前两个 epoch loss 下降正常第三个 epoch 验证 mAP 归零再往下跑偶尔能恢复但整体像心电图。原因batch 太小加学习率偏大BN 层统计量在小批量上剧烈波动模型参数一次更新过大后开始发散。这是 yolo 训练过程中典型的小数据集不稳定场景。解决把 batch 从 4 提高到 16 以上lr0 降到 0.005并加 warmup_epochs3。如果显存实在不够把 imgsz 降到 416不要降 batch。另一个后悔药是训练时开启cos_lrTrue让学习率平滑下降而不是阶梯跳变对 BN 抖动有明显抑制。5.4 验证集挺好、部署翻车低照度在 610 张里根本没出现现象本地验证集 mAP 稳定在 0.9接上电梯井道相机后关门检测频繁漏报画面拉亮一看全是夜间低照度、门缝边缘有运动模糊的帧。原因610 张原始图片大部分是白天或均匀光照模型没有见过电梯厅昏暗场景过拟合到特定亮度分布上。解决不要指望调 epoch 修这个问题先把摄像头位置和光源条件搞清楚。如果现场是红外补光把训练集做灰度化和亮度抖动再在验证时把输入从 BGR 转 GRAY 后拉大对比度。还可以盯着 loss 曲线看如果 val loss 在 40 epoch 后开始上升而 mAP 还在微升说明模型已经开始背训练图像此时立刻用早停把 best.pt 切回来。5.5 标签里出现 0 面积框用脚本先踩平再训练现象训练日志出现大量corrupt box警告loss 直接变成 nan。原因格式转换时有个别 XML 的 bndbox 坐标 xmin 等于 xmax或者 ymin 大于 ymax把这些脏框当正样本参与训练就会让损失函数无法计算。解决训练前跑一遍清洗脚本凡是 w 或 h 小于等于 0 的框直接扔掉坐标超过图片边界的钳制到 01 之间。跑完之后重新统计每一个 txt 的行数和 xml 的 object 数量对比差异集中在某几张图上就手动打开看一眼大概率是标注工具导出时漏了小数位。6. 用 610 张数据集守住部署边界阈值调整与场景扩展数据集小模型能做的提升有限但部署端面仍有很多腾讯飞起的余地。最好的落地方式是把测试视频流切成帧用训练好的权重做一次批推逐帧看置信度分布再确定报警和联动阈值。6.1 用测试视频回放调整置信度阈值YOLOv8 默认 conf0.25对 610 张训练集来的模型并不是默认最合适。电梯门状态这种二值任务宁可让 door_open 的阈值低到 0.15 换召回也不要把 conf 拉到 0.5 以上导致门开到一半时漏报。person 的阈值则要略高因为误报会造成门口卡顿的联动动作。yolo predict modelbest.pt sourcelift_clip.mp4 conf0.2 iou0.4 imgsz640跑完看结果视频重点观察“图像中无人的镜面反射”和“门板关闭瞬间的阴影”这两类帧。如果门开后两秒才第一次出现框把 conf 降到 0.15如果关门但框还残留超过半秒增加 iou 阈值到 0.5把重叠框合并掉。6.2 电梯门动作不减半帧率的时序一致性过滤单帧检测很容易发生门开状态在某一帧闪断部署端最简单的办法是加一个长度为 3 到 5 帧的滑动窗口门开关状态必须连续两帧保持一致才允许翻转。人有没有这个判断同样不能只看当前帧可以在两帧之间加一个tracking IoU判定给框分配一个最小存活帧数少于两帧的框当作噪声丢弃。这样做对 610 张原训练集来说等于免费提升了一个点的稳定性。这段时间几次做下来我自己的习惯是任何小数据集模型上线前先挑一段 10 分钟现场视频按 30 秒一段拆成帧用验证集和测试帧各跑一遍把输出的 JSON 结果按帧号对齐人工核对所有误报和漏报帧再将这类帧回灌进训练集做一轮增量微调。电梯开关和有无乘客这类任务真实死角往往不是模型结构而是你根本没把现场亮度和镜面反射当成第一优先级来对待。610 张能搭出可用基线但别停在基线里把避坑记录和阈值调整都写上项目文档后面每次加数据都能少踩一遍同样的坑。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网