电梯场景电动车与自行车识别实战:从数据标注到YOLOv8部署

发布时间:2026/10/5 10:48:19
电梯场景电动车与自行车识别实战:从数据标注到YOLOv8部署 简介面向电梯监控场景的电动车与自行车识别项目专为毕业设计、课程设计、工程实训及学科竞赛打造。项目基于电梯内视角数据集对YOLO预训练模型进行微调同时提供基于检测与基于跟踪两种推理方案检测方案对含目标实例的每一帧输出标注结果跟踪方案在检测基础上进行跨帧去重便于直接部署到监控视频流。整套资源包含134个文件、约16.96MB核心代码为34个Python脚本与34个YAML配置文件另有23张JPG和18张PNG图像样本用于测试或展示附带Dockerfile、Shell脚本、CSV训练结果、Jupyter教程及说明文档结构清晰按README即可复现运行。项目经过严格测试答辩评审平均分达96分代码结构清晰、模块化程度高可借鉴用于设计报告也可在此基础上扩展更多功能目前已有65人学习下载适合需要快速落地同类识别系统或借鉴其项目思路的用户。1. 电梯视角的两轮车识别为什么比普通安防检测更麻烦先说一个反直觉的结论电动车和自行车的识别难点从来不在“认识这辆车”而在电梯轿厢这个空间里观察条件极其恶劣。摄像头通常装在轿厢一角俯视角度大画面有鱼眼畸变金属门和地砖疯狂反光夜间红外补光还会把画面颜色整个带偏。检测模型拿到的是侧向压缩、亮度剧烈波动、随时被人或箱体遮挡的残缺目标——这才是毕设和竞赛里真正卡进度的地方。这个项目又特别适合作为毕设、课设、实训或大作业的题目因为它交付物非常清楚一个视频输入一段告警输出附加截图和统计报表。前期跑通YOLO系检测模型很快难的是把“电梯里”这个条件编码进数据和后处理逻辑。你不需要发明检测算法但需要把公开模型改造成能在电梯场景稳定输出结果的东西。下面按我实际做过的技术路线展开先准备数据与标注再训练与压缩模型然后调整后处理参数最后把演示做到能答辩的程度。2. 数据与标注先定义类别和标注规范再动手建数据集2.1 类别边界怎么定电动车、自行车之外还要不要单拎摩托车标题只写“电动车以及自行车”但实际监控画面里常常混进燃油摩托车、三轮代步车、甚至搬货用的手推车。如果只用两个标签模型会把踏板摩托强行塞进电动车类别把带尾箱的跨骑摩托塞进自行车类别推理阶段就会频繁跳变。我一般建议做成三类的结构e_bike电动两轮车、bicycle自行车、motorcycle燃油摩托车。其中摩托车单独一类能让电动车的特征更聚焦也便于答辩时解释“类间差异设计”。如果导师要求严格按标题只保留两类那就把摩托车样本全部归到难例背景里标注时不打框让模型学会“不理会它”。两类方案唯一的问题是漏报率会比较难看因为电动车和燃油摩托车在电梯侧视角下确实非常相似。标注规范要提前写清楚别让一起做课设的同学各标各的。我采用三条规则画面边缘被截断的车只标注可见主体框不脑补完整车身被电梯内乘客挡住超过一半的车不标因为训练时强行标这种框会把置信度拉乱反光地砖里的倒影不标。这三条规则能避免大量无效边界框。2.2 冷启动数据从公开检测数据里抽基类再补自采电梯视频纯自采数据很费时间但在真实电梯视频里抽帧又是后期调精度的关键。常见做法是先从公开的目标检测数据里筛出自行车和摩托车类别图片做冷启动让模型先认识“车”这个概念。这里注意公开数据里几乎没有仰视角度的轿车内图更少有电动车尾部特写所以只能作为底座不能当最终训练集。下一步才是核心找小区或教学楼货梯的监控片段按每3到5秒抽一帧。抽帧密度不要过高同一辆车的连续帧太近会让训练集高度重复mAP数值虚高换到另一部电梯立刻打回原形。按视频内容而不是按时间抽帧在车进电梯、转向、被遮挡、出电梯四个节点各留几帧效果会好很多。我通常会保留一份“负样本池”专门放空电梯、有人搬纸箱、门开了一半这类背景帧。这些帧不需要标任何框但在yaml配置里要作为纯背景图片放进训练集否则模型会在没有车的画面上硬找轮廓出现阴影和座椅腿误报。2.3 半自动预标注流程先用现成模型生成粗标签再人工修正传统做法是人手一张张拉框几百张图拉下来眼睛就花了。常见省力方案是先用一个通用检测模型做预标注再把结果喂给标注工具人工复核。代码可以写得很短# 半自动预标注抽帧 推理 输出YOLO格式标签 from ultralytics import YOLO import cv2, os model YOLO(yolov8s.pt) # 通用检测模型只用来做伪标注 cap cv2.VideoCapture(elevator_01.mp4) frame_id 0 save_dir labeled_frames os.makedirs(save_dir, exist_okTrue) while cap.isOpened(): ret, frame cap.read() if not ret: break if frame_id % 15 ! 0: # 每15帧取1帧避免重合度太高的样本 frame_id 1 continue # 通用模型里 COCO 类别 bicycle 是 1motorcycle 是 3只用这两类先粗标 results model(frame, classes[1, 3], conf0.25, imgsz640) img_h, img_w frame.shape[:2] for box in results[0].boxes.xyxy.cpu().numpy(): x1, y1, x2, y2 box x_c ((x1 x2) / 2) / img_w y_c ((y1 y2) / 2) / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h # 先按 motorcls 写入等人工复核时再改 e_bike/bicycle 标签 with open(f{save_dir}/{frame_id:06d}.txt, a) as f: f.write(f2 {x_c:.6f} {y_c:.6f} {w:.6f} {h:.6f}\n) cv2.imwrite(f{save_dir}/{frame_id:06d}.jpg, frame) frame_id 1 cap.release()这段代码的逻辑很直白通用模型不认识“电动车”和“自行车”的中国式细分但能框出大体位置。人工复核只需要改类别ID和修正边界不需要从零开始画框一分钟大概能修三十张。参数上注意classes[1, 3]必须核对当前模型的类别表不同版本的索引不一样搞错了等于什么都没跑。抽帧间隔按15帧设置在25FPS视频里相当于每0.6秒取一帧既能覆盖车辆运动过程又不会让相邻帧太雷同。2.4 电梯专用增强亮度抖动和仿射变形比马赛克更重要训练时按YOLO默认的mosaic增强虽然能提升整体鲁棒性但电梯场景最稀缺的是“光线突变”和“视角畸变”。我习惯在训练管线里挂一套Albumentations增强策略直接对输入影像做扰动# 电梯场景增强配置对YOLO格式的边界框生效 import albumentations as A train_transform A.Compose([ # 模拟白天到夜间红外补光的亮度波动 A.RandomBrightnessContrast( brightness_limit(-0.25, 0.35), contrast_limit(-0.15, 0.2), p0.9 ), # 模拟电梯轿厢顶灯偏色和红外光下的色调偏移 A.HueSaturationValue( hue_shift_limit8, sat_shift_limit(-30, 20), val_shift_limit(-20, 20), p0.6 ), # 模拟广角镜头引起的侧向压缩和仰视拉伸 A.Affine( scale(0.7, 1.3), translate_percent(-0.1, 0.1), rotate(-12, 12), p0.8 ), ], bbox_paramsA.BboxParams( formatyolo, min_visibility0.4 # 增强后可见面积不足40%的框会被丢弃 )) # 用增强结果覆盖原图或叠加到训练缓存中这里要特别强调三个参数的意义。min_visibility0.4是血泪经验不做这个过滤仿射翻转会把一辆完整自行车挤压成一条横线标签框还在模型反复学习这种扭曲关系最后在真实电梯里看到车身转横向时就漏检。brightness_limit给到0.35而不是0.5是因为电梯画面最暗的时刻是夜间红外模式最亮的时刻是轿厢内日光灯全开过大的亮度变化会把车灯的反射直接烧成纯白块属于破坏性增强。而Affine的旋转范围控制在12度左右配合电梯摄像头实际安装角度已经足够覆盖大部分画面抖动。增强不是越多越好。电梯监控核心失效模式只有三类暗光、反光、侧向压缩。这三个方向覆盖到位其余时间应该留给更干净的真实样本。3. 模型选型与训练先跑稳YOLOv8再做压缩和导出3.1 为什么先上YOLOv8s而不是一上来就选大模型毕设和竞赛里最容易犯的错是迷信“模型越大精度越高”直接开YOLOv8x去训练。电梯识别任务的目标设备大概率是普通电脑、Jetson或者树莓派v8x的推理速度在这些平台上很难达到实时后面裁减和量化又要花大量时间补性能。YOLOv8s是我做这个项目时的默认起点。它参数量适中在640分辨率下CPU也能跑到10FPS上下如果后续有TensorRT部署条件能到30FPS以上。更重要的是电梯里离镜头近的电动车几乎占满画面属于中大目标中大目标对模型容量的要求没那么高真正决定效果的是数据质量而不是网络深度。先从s跑通基线如果mAP50达不到约0.85且排除数据原因后再换m甚至l也不迟。x量级留给那些必须用低置信度识别小目标的人电梯场景几乎用不上。3.2 训练配置与数据集yaml直接给出能跑的最小参数训练前先准备好数据集描述文件我用这样的结构# elevator_two_wheeler.yaml path: dataset train: images/train val: images/val nc: 3 names: 0: e_bike # 电动两轮车 1: bicycle # 自行车 2: motorcycle # 燃油摩托车可选然后训练命令可以这样写# 用YOLOv8s做迁移学习权重会自动下载 yolo train \ modelyolov8s.pt \ dataelevator_two_wheeler.yaml \ epochs200 \ imgsz640 \ batch16 \ patience30 \ device0 \ projectruns/elevator \ nameexp_01参数说明是这类项目最容易被人忽略的部分。patience30让训练在30个epoch内mAP没有提升时提前停避免无意义的过拟合。imgsz640是精度和速度的平衡点我用736训练过夜间小目标召回略有提升但CPU推理时间从约90ms涨到约130ms竞赛演示现场会很尴尬。batch16在显存只有8GB时可能爆显存调成8就稳了如果连8都不行说明数据增强里默认开启了太多复制子图先关掉half也不迟。device0表示NVIDIA GPU纯CPU训练就写devicecpu但200个epoch可能跑到第二天早上一般建议用云GPU或者本地借一张老卡。3.3 怎么验收训练结果不要只盯mAP50-95这一个数训练完会生成results.csv除了loss曲线还需要去看类别级别的mAP。电梯项目最容易出现的情况是所有指标都不错但打开bicycle那一行的precision只有0.7说明自行车和电动车的尾部特征相互污染。这类问题在monitor状态里隐藏得很深只看总mAP会漏掉。竞赛答辩时其实更看重工程指标。我整理交付时给出一张三列的表类别、precision、recall。并且在每列下补充说明“本类误检的主要对象是谁”。这样评委一眼就能看出你理解场景而不是只跑了个默认脚本。FPS指标同样重要。推荐在验证集上专门统计推理延迟而不是用训练时自动打印的时间。因为YOLO训练打印的FPS不计预处理和后处理在演示时帧率会明显缩水。晚些时候在验收环节要跑完整管线测一条视频从视频读取到告警弹出整个过程计时这个数字才真正代表可用性。3.4 导出ONNX并做CPU推理部署前的必经步骤训练出best.pt后别急着在答辩现场用PyTorch直接跑视频。PyTorch推理会占用大量内存加载权重也慢。导出ONNX和写一个轻量推理脚本是更稳妥的做法# 导出固定尺寸ONNX模型 yolo export \ modelruns/elevator/exp_01/weights/best.pt \ formatonnx \ imgsz640 \ opset12 \ simplifyTrue导出后的ONNX可以用ONNX Runtime在CPU上推理推理代码写在第四章因为要和后处理参数放在一起讲。这里先说明一个细节simplifyTrue会做图优化去掉一些冗余算子但偶尔会有量化层面的精度损失。如果导出后测试发现检测结果明显变差就关掉simplify再导一次。对于竞赛或课设把推理管线跑到ONNX这一步基本已经达标。如果你要上嵌入式设备比如Jetson Orin或RK3588后续可以继续转TensorRT或RKNN但我一般会先确认需求再加班以免投入时间换不回来答辩时的实际效果。4. 电梯场景的3个必调参数与后处理逻辑4.1 置信度阈值和NMS阈值预设值在电梯里不够用模型给定的默认参数一般是conf0.25iou0.7。这两个值在通用场景问题不大但在电梯里会出现两类毛病conf太低导致地砖反光里的车影被当车conf太高导致暗光下的真实车漏检。我最终的参数都是用一个小脚本扫出来的# 参数扫描在不同conf/iou下统计mAP和误报数 import onnxruntime as ort import numpy as np import cv2 sess ort.InferenceSession(best.onnx, providers[CPUExecutionProvider]) input_name sess.get_inputs()[0].name def scan_thresholds(val_images, val_labels): best_conf, best_iou 0.3, 0.6 best_score 0 for conf in [0.2, 0.25, 0.3, 0.35, 0.4, 0.45]: for iou in [0.3, 0.4, 0.5, 0.6, 0.7]: # 在验证集上推理用conf过滤低分框 # iou传入后续NMS逻辑统计F1分数 f1 evaluate_on_val(conf, iou) # 自定义评估函数 if f1 best_score: best_score, best_conf, best_iou f1, conf, iou return best_conf, best_iou在实际项目里我得到的较优组合通常是conf0.35、iou0.45左右。iou0.45比默认值小原因在于人和车、车和车在电梯里经常发生大面积重叠过高IoU会把互相遮挡的两个不同目标合并成一个框。而conf不要低于0.3因为电梯内真实目标往往体积大、置信度高低于这个阈值的大多是影子或边缘伪影。4.2 后处理业务规则检测框之外的场景过滤模型输出的是全部检测框但电梯监控要求的是“靠近门、准备进入”时触发告警。写一小段业务规则比让模型自己学“电梯门在哪”可靠得多import numpy as np ROI_RATIO 0.30 # 轿厢门侧区域占画面底部30%左右 MIN_BOX_AREA 300 # 面积低于300像素的碎片框直接丢弃 def filter_elevator_boxes(boxes, scores, frame_shape): h, w frame_shape[:2] keep [] for box, score in zip(boxes, scores): x1, y1, x2, y2 box if (x2 - x1) * (y2 - y1) MIN_BOX_AREA: continue # 只保留位于画面靠下区域的框 if y2 h * (1 - ROI_RATIO): continue keep.append((box, score)) return keep这里使用ROI_RATIO只是示例电梯摄像头装在左上角时画面底部通常对应轿厢门沿。如果摄像头视角是俯视全局ROI区域画法改成梯形或四边形的顶点坐标代码会更复杂但思路一样用空间约束滤掉画面边缘的反射残影。滤波逻辑要写在NMS之后而不是之前因为NMS需要综合全局信息去掉重复框空间过滤会破坏这种全局性。4.3 用ByteTrack做连续帧跟踪而不是单帧判断单帧检测的抖动特别严重尤其是电动车启动时车身倾斜某一帧识别成自行车下一帧又跳回电动车。只靠单帧输出很容易误报和跳变。更好的方案是接入ByteTrack这类轻量跟踪器在检测框之上维护每个目标的连续轨迹# 伪代码ByteTrack与检测输出融合 from bytetrack import ByteTrack tracker ByteTrack( track_thresh0.35, # 与检测置信度保持一致 match_thresh0.8, # 相邻帧特征匹配的门槛 frame_rate25 ) for frame in video_stream: dets model_infer(frame) # 返回 boxes, scores, class_ids tracks tracker.update( np.array(dets[boxes]), np.array(dets[scores]), np.array(dets[class_ids]), frame ) for track in tracks: if track.score 0.35 and track.hit_streak 3: trigger_alarm(track.box) # 连续3帧稳定再报警match_thresh0.8这个值比较讲究。设太高角度一变就会跟丢设太低人和自行车交错时会把两个人目标的轨迹粘连。视频帧率25FPS时0.8是比较稳的中间值。hit_streak3是压制单帧误报的关键只有连续出现3帧以上的跟踪目标才认为真实存在这样地面反光造成的偶发假框基本不会触发告警。跟踪器的引入也让答辩多了可以展示的内容可以画出每个目标的轨迹ID、停留时间和进出方向。这些信息不仅能用于演示还能用来统计某一时段电梯被两轮车占用的次数是一个很有说服力的附加功能。5. 避坑与排查电梯两轮车识别最容易翻车的4个点5.1 现象夜间红外画面下检测率从0.9掉到0.4夜间电梯监控会切换到红外模式画面变成灰度偏紫或偏黄。白天训练好的模型拿到这种图片检测结果几乎崩溃。原因在于我训练集里的白天影像占绝大多数模型学到的颜色分布和夜间完全不同。解决方法是两手抓第一从夜间监控视频里抽帧加进训练集第二在预处理里把图片统一转成BGR后再归一化不要让模型直接面对传感器输出的原始YUV格式。如果红外画面非常暗先用cv2.createCLAHE做局部直方图均衡再进网络能明显提高召回。5.2 现象反光地砖上的车影被识别成真实车辆轿厢地面常是镜面不锈钢或抛光瓷砖电动车一进来车影清晰可见。模型对轮廓敏感影子轮廓和车身高度相似于是误报。规避手段不是等模型自己去学“影子不是车”而是从两个层面压制业务规则里只保留画面靠下ROI区域的检测框影子通常比真实车身更靠近地板或更偏跟踪器的连续帧机制能在影子闪烁抖动时判定目标不连续从而不触发告警。如果这种场景在你的数据集里特别多那就把反光较强的视频帧专门挑出来放进负样本池效果更直接。5.3 现象电动车横放时宽高比接近2比1小模型漏检严重电梯里经常同时进出好几辆电动车最后进来的那辆只能斜着或横着放。YOLO默认的方形缩放会把这种横向拉长的目标压缩得很小容易跟背景纹理混在一起。解决办法是适当调大训练分辨率到736试试看同时给增强中的Affine增加沿水平方向的拉伸和压缩。如果你的模型最终部署在边缘设备上736分辨率会造成不小的性能损失那就退而求其次增加更多“横放”样本让模型专门去记住这个形态。实际操作中我从真实电梯视频截了100多张横放车的图片效果比网上找的同类图片好非常多。5.4 现象mAP很高但连续视频测试时频繁出现鬼影训练集mAP高、视频测试差多半是数据和验证数据时间跨度太近或者验证集就是从同一条视频抽的帧。若验证集和训练集里的张数相似但来自同一时段模型的mAP会虚高。解决这种虚高问题要让验证集来自另一部电梯、另一天的录像哪怕是同样环境至少时间错开。另外训练时开启cacheTrue会把数据缓存到内存加速如果换了数据文件但没重建缓存老数据残留也会让测试不真实。这种情况我一般会删掉dataset/cache目录重新生成。5.5 现象训练正常但导出ONNX后输出全部为空训练时用PyTorch跑得好好的导出到ONNX申请之后推理结果全没了。常见原因有三个模型训练时的imgsz和导出时不一致输入图像没有做与训练相同的数据预处理ONNX Runtime版本和导出opset不匹配。逐一排查即可。具体做法是把导出命令里的imgsz640固定成训练时的值并在推理代码里使用完全相同的BGR转RGB顺序和归一化方式。此外检查输入时ort_session.get_inputs()[0].shape有时导出的动态轴是None要手动指定成NCHW否则会出现数组形状报错。6. 验收与加分能让演示更像工程落地的两个小动作6.1 用视频循环回放模拟实时监控流现场演示最怕素材一次性播完屏幕上就只剩一片“空电梯”。用视频循环回放就能守住演示效果# demo.py循环回放 实时告警截图保存 import cv2 from tracking_pipeline import run_inference_with_tracker cap cv2.VideoCapture(demo_elevator.mp4) frame_idx 0 while cap.isOpened(): ret, frame cap.read() if not ret: # 视频播完回到开头模拟流式监控 cap.set(cv2.CAP_PROP_POS_FRAMES, 0) continue result run_inference_with_tracker(frame) if result[alarm]: cv2.imwrite(falarm_log/{frame_idx:06d}.jpg, frame) cv2.putText(frame, ALARM, (40, 60), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 0, 255), 2) cv2.imshow(Elevator Monitor, frame) if cv2.waitKey(1) 0xFF ord(q): break frame_idx 1这段代码把项目从“离线检测”提升到“实时监控”的观感。每次转场后视频会继续循环告警帧自动存储为截图答辩时能展示历史告警记录这是评委很看重的闭环细节。6.2 把性能指标打上画面让答辩一分钟说清结果演示时在视频画面角落持续打印FPS和当前目标数比任何报告都直观# 在显示帧上叠加FPS和检测目标数 # fps的计算使用滑动窗口平均避免单帧波动欺骗观众 def overlay_stats(frame, fps, obj_count): cv2.putText(frame, fFPS: {fps:.1f}, (20, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) cv2.putText(frame, fObjects: {obj_count}, (20, 70), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) return frameFPS建议用最近20帧的平均值不要用瞬时值。被模型偶尔的一次大目标推理拖慢时瞬时FPS会从30跳到8看起来像程序卡死平均帧率才是稳定的工程指标。6.3 答辩现场的总基调最后补一句我个人带队做这类项目的习惯不要把所有时间都花在刷mAP上先保证演示视频里“白天、夜间、多人遮挡、车横放”这四个场景各有一段能稳定告警。再去补精度和参数量。这个顺序反了答辩现场很容易在夜间场景翻车而夜间场景恰恰是最难补的。希望你在把这篇笔记落到自己项目时也能从数据质量入手先建立一套能说明白的电梯场景基准。真到答辩或者竞赛评审那一刻你能讲清楚“为什么这样调阈值、为什么过滤ROI、为什么用连续帧跟踪”比一句“模型准确率很高”有说服力得多。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询