
简介面向电梯监控场景的电动车与自行车识别项目适用于毕业设计、课程设计、工程实训及竞赛等场景。项目基于电梯内视角数据集对YOLO预训练模型进行微调同时提供检测与跟踪两种处理方式检测方法逐帧标注目标实例跟踪方法进一步去重便于后续分析或告警联动。压缩包共包含134个文件以Python源码、YAML配置、标注图片与测试图片为主另有Dockerfile、Shell脚本、Jupyter Notebook教程、README及CSV结果记录等支持快速搭建复现环境整体体积约16.96MB结构清晰、轻量易用。目前已有65人浏览学习适合希望快速复现目标检测项目或在此基础上扩展功能的研究者与学生。资源内含完整工程文件与说明文档代码经测试可正常运行可借鉴设计思路撰写报告还可基于现有模型调整数据集或训练参数扩展识别更多目标类别。1. 电梯监控视角识别电动车和自行车难点不在模型而在数据把电梯监控视角内的电动车和自行车识别当成一个普通目标检测任务来做很多人的第一反应是直接挑一个现成模型、跑一遍公开权重就交差。实际上一旦把摄像头装到轿厢顶部角落画面就会变成超过一百度的广角俯视同一帧里既有轿厢内部又有候梯厅一角中间还夹着镜面不锈钢反光、LED 广告屏和不断开关的电梯门。公开模型在平视道路上学到的特征到了这种视角下经常把自行车认成箱子、把电动车后轮直接从反光里漏掉。做毕设、课设、实训、大作业和竞赛技术方案时最稳妥的路线是把这类项目拆成三个独立模块训练数据怎么采集和标注、模型怎么选和调、推理结果怎么变成一条能用的告警。我按自己做这类落地方案的习惯把每一步的命令、参数和翻过车的地方都写清楚跟着这套流程走至少能少走一大半弯路。2. 从监控视频到训练集抽帧、清洗、标注与格式转换训练数据是这类项目里最容易被低估的一环。电梯监控和常规道路监控的区别在于摄像头机位相对固定、画面视角单一但每个电梯的安装位置、轿厢材质、灯光条件都不一样。数据阶段如果只拿某一个电梯的几十段录像去标后面训练出来的模型大概率只能在这个电梯里工作换一栋楼就失效。先解决数据来源再谈模型。2.1 数据从哪来监控录像授权采集与手机模拟顶置视角正规一点的来源是学校宿舍楼、园区物业或自己实习单位的电梯监控录像这类素材的画质、压缩格式和真实部署环境完全一致是最理想的训练来源。拿到录像时要注意脱敏要求视频里出现的行人面部、楼层按钮区域最好在抽帧后做模糊处理避免后面答辩和展示时涉及隐私问题。如果拿不到真实录像常见替代做法是手机模拟采集。把手机支架固定在电梯顶部角落用广角镜头对着轿厢门的方向拍四五段视频每段三到五分钟包含有人进出、有电动车推进推出、只有行人这几种情况。手机镜头和监控镜头在畸变程度上会有差异但构图和拍摄角度足够接近作为毕设数据也能讲得通。数据量不建议只看帧数而是看有效目标数电动车和自行车各保留五百个以上的标注实例比较稳妥。采集时尽量覆盖不同电梯、不同时间段、开门和关门两种状态。公开数据集里虽然能找到大量自行车和摩托车的平视图像但电梯俯视角度的样本很少直接拿它们当主力训练集会带来比较明显的视角偏差所以公开数据集最多用来做预训练或当负样本不能替代自采数据。2.2 用 FFmpeg 从监控视频抽帧选帧策略与帧清洗流程拿到原始监控视频后第一步是用 FFmpeg 抽帧。电梯里人流量不大不需要像道路监控那样高帧率抽帧每秒一到两帧就够电动车进电梯是个缓慢的过程两秒一帧也能抓到关键状态抽得太密反而会产生大量几乎相同的图像让训练集出现严重的自相似过拟合。ffmpeg -ss 00:00:00 -to 00:05:00 -i elevator_rec.mp4 \ -vf fps1,scale1280:-1 -q:v 2 \ frames/frame_%05d.jpg逻辑说明-ss指定开始时间-to指定结束时间可以先截取有目标出现的路段fps1表示每秒抽一帧scale1280:-1把画面宽度统一到 1280高度按比例缩放避免电梯监控常见的 D1 分辨率画面尺寸不统一-q:v 2控制 JPEG 质量数值越小质量越高。抽帧完成后需要人工过一遍把完全没有目标的帧、画面卡在电梯门关闭状态的帧、被手或镜头遮挡产生的模糊帧删掉。如果样本量仍然不够还有一个小技巧对同一段视频做多档抽帧比如目标出现阶段用fps3多抽一些没有目标的阶段用fps0.5跳着抽。抽出来的帧按电梯编号分目录存放比如frames/ele_A、frames/ele_B后面划分训练集和验证集就直接按目录切而不是按帧随机切这一步对防止数据泄漏很关键。2.3 电动自行车和自行车的标注规范与 VOC 转 YOLO 脚本标注工具我习惯用 LabelImg 或 AnyLabeling输出格式保持 Pascal VOC XML。最关键的是标注规范必须在开工前定死否则两个人标出来的框会完全对不上。电梯俯视视角下电动自行车和自行车的区分依据有三个是否有明显的电池仓、车身长度是否明显更大、踏板上是否有脚蹬结构。标注时框住整车轮廓包含前后车轮不要只框车身主体目标被行人遮挡超过大概六成、无法分辨类别时直接不标。标注完成后训练用的是 YOLO 格式的纯文本标注文件所以需要写一个转换脚本把 VOC XML 转成 YOLO TXT。import os import xml.etree.ElementTree as ET from pathlib import Path CLASSES [bicycle, electric_bicycle] # 0: 自行车, 1: 电动车 def convert_voc_to_yolo(xml_path: str, out_dir: str): tree ET.parse(xml_path) root tree.getroot() img_w float(root.find(size/width).text) img_h float(root.find(size/height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in CLASSES: continue cls_idx CLASSES.index(name) box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) x_center ((xmin xmax) / 2) / img_w y_center ((ymin ymax) / 2) / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_idx} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) out_path os.path.join(out_dir, Path(xml_path).stem .txt) with open(out_path, w, encodingutf-8) as f: f.write(\n.join(lines))逻辑说明读取 XML 里的图片宽高把xmin/ymin/xmax/ymax换成 YOLO 要求的归一化中心点坐标和归一化宽高。注意所有坐标都必须除以原始图片宽高而不是缩放后的尺寸如果之前用 FFmpeg 统一缩放过图片XML 里的宽高也要跟着更新。转换完成后我会顺手跑一次检查脚本把所有标注里坐标小于 0 或大于 1 的行打出来这类错标在训练时会导致损失值异常跳动。3. 模型选型与训练YOLOv8 跑通电梯场景的最小流程数据集准备好之后模型层面的选择其实很明确用 YOLOv8 系列。电梯监控场景目标数量少、类别只有两类、推理设备往往是普通 CPU 或老旧 GPU用 YOLOv8n 或 YOLOv8s 就已经足够。更大的模型不是不能跑而是在显存和推理延迟上都会带来额外负担对这类小项目反而不好驾驭。3.1 为什么预训练权重只能当起点视角分布差在哪里COCO 或 Pascal VOC 里虽然有自行车和摩托车但这些目标大多是从平视角度拍的背景是马路、人行道、停车场目标形态和电梯俯视画面完全不同。电梯顶置摄像头看到的是车顶、电池仓、车筐和人的头顶车身的侧面轮廓被压缩成一个接近俯视的矩形再加上广角镜头带来的边缘畸变同一辆车在画面中央和画面边缘的宽高比差异很大。预训练权重在 COCO 上学到的特征依然有用尤其是对车轮、金属反光表面等基础视觉元素的理解但直接把没有微调的权重拿去做推理效果通常会比较差。正确做法是把预训练权重当初始化起点用自己的电梯样本做微调。这也意味着如果训练数据只有一两百帧微调之后模型仍然可能记不住电梯视角下的目标形态数据量不够时最值得投入的不是换模型而是补样本。模型选型参考这张表模型参数量COCO mAP50-95适合场景YOLOv8n约 3.2M约 37.3树莓派、CPU 推理、低延迟要求YOLOv8s约 11.2M约 44.9普通 GPU 或较高性能 CPU精度优先这个参数对比说明一件事电梯监控这类目标不算小、类别不复杂n 和 s 之间并没有明显的精度鸿沟如果部署端只是做离线检测或者告警联动s 会更稳n 更适合需要实时预警的场景。3.2 dataset.yaml 与训练命令先跑通一遍再谈调优训练前把数据集配置写成一个 YAML 文件放在项目根目录下。训练集和验证集最好已经按电梯分开比如训练集来自两个电梯验证集来自第三个电梯这样训练过程中的验证分数才有参考价值。train: ./datasets/elevator/train val: ./datasets/elevator/val nc: 2 names: 0: bicycle 1: electric_bicycle然后执行训练命令yolo detect train \ modelyolov8n.pt \ dataelec.yaml \ epochs100 \ imgsz960 \ batch16 \ device0 \ project./runs \ nameelec_v1 \ cacheTrue逻辑说明modelyolov8n.pt表示从官方预训练权重开始微调imgsz960是对电梯这类中近距离目标比较合适的训练分辨率比默认的 640 更能保留车轮、车筐等细节又不会像 1280 那样显著拉高显存占用epochs100对几百到一千张的样本量已经足够太多轮数反而容易过拟合batch16是 8G 显存能承受的范围显存更大可以加到 32但收益不大cacheTrue把图片提前缓存在内存里减少训练时的磁盘 IO 波动。训练完成后不要急着看验证集 mAP先打开runs/elec_v1/目录下的confusion_matrix.png和results.png。如果看到两类之间的混淆比较严重或者验证集损失在训练后期不降反升说明样本质量问题优先于继续增加训练轮数。3.3 真正要调的四组参数imgsz、增强强度、置信度和 NMS 阈值首先说imgsz。电梯监控的画面如果原始分辨率很低比如老旧小区的 704×576强行用 1280 训练不仅显存压力大还会让模型学到的目标尺度和实际推理不一致。我的习惯是先看原始画面里一辆电动车占的高度大概是多少像素如果只有三四十像素就把imgsz拉到 1280 并配合后面会讲的 ROI 方案如果电动车的目标高度超过一百像素960 就足够。其次是数据增强强度。YOLO 默认开启的scale0.5、hsv扰动等对电梯场景不能直接拉满。电梯轿厢空间固定车辆的尺度变化范围有限过强的缩放增强会制造出大量“现实中根本不可能出现”的样本。训练时可以手动压低增强参数yolo detect train \ modelyolov8n.pt \ dataelec.yaml \ epochs100 \ imgsz960 \ scale0.35 \ degrees0.0 \ hsv_v0.4 \ perspective0.0002参数说明scale0.35限制缩放扰动范围degrees0.0关闭旋转增强电梯监控画面永远保持水平和垂直旋转后的目标形态是无效样本hsv_v0.4保留亮度扰动用来模拟日光灯闪烁和白天黑夜变化perspective0.0002轻微模拟广角畸变数值不要超过 0.001否则图形变形太夸张。最后是推理参数conf和iou。训练结束后做测试时conf默认值是 0.25电梯场景建议提到 0.35 到 0.45。原因很简单电梯告警的误报代价比漏报高把反光里的影子误判成电动车会触发不必要的告警。iou0.5足够把同一辆车产生的多个重叠框合并掉不需要单独调。4. 电梯视角特有的精度优化畸变、反光、小目标与告警联动模型跑通以后真正把项目做到能演示、能交付的部分在于针对电梯场景做的定向优化。电梯监控和普通安防最大的区别是画面构图极度稳定目标运动路径也相对固定所以很多通用的通用检测技巧在这里需要反过来用。4.1 顶置俯视与墙角斜视先判断镜头位再决定训练策略不同电梯的摄像头安装位大致分成两类。一类安装在轿厢顶部角落镜头正对着斜下方画面上半部分是候梯厅下半部分是轿厢内部目标整体呈现接近垂直的俯视视角另一类安装在门框上方镜头斜向下倾斜四十五度左右目标在画面里保留了更多的侧面形态。这两类视角下的目标宽高比完全不同。如果训练数据全是顶置俯视推理画面却是门框斜视模型大概率会把车身拉长的形态当成异常目标处理。处理方法是先看镜头安装位如果拿到的都是同一种视角推理阶段遇到另一种视角时可以用 OpenCV 做透视校正把斜视画面近似转换成俯视构图再去检测但这个方法在目标距离变化大时效果有限。更稳的做法是在数据采集阶段就把两类视角都纳入训练集哪怕数量不平衡只要验证集能看见另一类视角的样本模型就不至于在部署时完全失明。这个点看起来基础却是换一个电梯就翻车的最常见原因。4.2 小目标与低分辨率imgsz 上限、ROI 裁剪与切块取舍电梯监控录像经过 DVR 压缩后画面细节损失往往比想象中严重。电动车在候梯厅里时离摄像头较远目标占画面面积可能只有三四个百分点一旦推进轿厢目标面积会瞬间增大几倍。这导致模型要么对远景小目标漏检要么对近景大目标的边框预测不稳定。处理小目标最直接的手段是把推理分辨率提到 1280但老旧 DVR 输出本身就是模拟信号转码来的硬提分辨率不会凭空恢复细节。更实用的是 ROI 裁剪电梯告警关心的是轿厢内部和门口那块区域候梯厅远端本身就不该触发告警。推理前直接把画面裁剪成感兴趣区域既减少干扰也变相放大了目标。import cv2 def crop_roi(frame, top_ratio0.2): h, w frame.shape[:2] return frame[int(h * top_ratio):, :]逻辑说明顶置摄像头画面里候梯厅通常集中在最上方top_ratio0.2表示裁掉顶部两成画面保留剩余轿厢区域这个比例需要根据自己监控画面的实际构图微调。注意裁剪之后模型输出的坐标要换算回原始画面的坐标再用于告警逻辑否则联动时定位会偏移。切块推理在这个场景里不推荐。电动车是运动目标切块会增加检测结果的拼接和跟踪复杂度收益远小于直接放大推理分辨率。4.3 由框到告警面积占比、连续帧确认与楼层联动检测模型输出的是目标类别和边界框但电梯告警逻辑不能只看“检测到了电动车”这个信号。一个典型的误报场景是这样的电梯停在一楼门外有人推着电动车等电梯候梯厅的画面上出现完整电动车模型当然会检出如果这时直接触发告警就会在电动车还没进轿厢时误报。所以我在告警逻辑里加两条约束目标框面积占整帧画面的比例以及连续帧确认。真正进入轿厢的电动车框的面积占比会快速变大通常超过百分之十五而在候梯厅等待时占比可能只有百分之几。连续帧确认则用来过滤光线闪烁、画面抽帧抖动导致的单帧误检。FRAME_MIN_AREA_RATIO 0.15 CONFIRM_FRAMES 3 class AlertConfirmer: def __init__(self, frame_area: int): self.frame_area frame_area self.count 0 def feed(self, box_area: int): if box_area / self.frame_area FRAME_MIN_AREA_RATIO: self.count 1 else: self.count 0 return self.count CONFIRM_FRAMES逻辑说明每次拿到检测结果时计算当前目标框面积和整帧面积的比值连续三次高于阈值才认为告警成立一旦中间出现一次不满足计数清零。代码很短但能挡掉相当大一部分“远距离目标干扰”和“单帧鬼影”造成的误报。如果项目还对接自动语音播报或电梯门禁把确认状态输出成一条 MQTT 消息或 HTTP 回调即可避免在检测脚本里写死硬编码联动逻辑。5. 避坑手册这个项目最容易翻车的五个场景这个章节的内容来自实际做过类似项目的血泪经验。很多问题在训练曲线上看不出来只有把模型拿到真实电梯环境里验证才会暴露。下面这五类问题出现频率最高。5.1 换一台电梯就失灵数据同源带来的过拟合现象训练和验证都是同一台电梯的录像验证集 mAP50 到了 0.9 以上看起来模型已经很好了但拿到隔壁楼另一台电梯的监控画面里跑漏检率突然变得很高。原因数据全部来自同一个电梯模型把轿厢的固定背景、灯光色温、地砖纹路都当成有效特征学进去了换一个视觉环境立刻失效。解决数据集至少覆盖两个不同电梯或者用其中一个电梯的数据抽出来当验证集观察分数是否明显下降。如果下降明显补数据是第一优先级调模型参数是第二优先级。5.2 白天能用晚上崩夜间帧不是简单加亮度扰动现象白天测试一切正常到了晚上只有微弱灯光或红外补光时电动车和背景的对比度大幅降低模型频繁漏检。原因很多项目偷懒只做亮度归一化和随机亮度增强但夜间电梯监控往往是黑白画面伴随红外噪点第二天白天的彩色特征被完全替代。解决实际采集夜间视频来补样本或者把当天晚上的监控录像单独抽帧分析。做数据增强时可以叠加高斯噪声和 CLAHE 局部对比度增强但真正的夜间帧无可替代。训练时把白天和夜间数据按比例混合不要全部分到同一个训练批次里。5.3 电动车和自行车互相认错标签体系与标注边界没定死现象验证集混淆矩阵里bicycle和electric_bicycle两类互相错认的比例居高不下手动看检测结果发现连人都不容易分清。原因俯视视角下电动车和自行车的侧面特征被压缩没有统一标注边界有人把踏板的电动自行车标成自行车有人把有脚蹬的两轮车标成电动车。解决一开始就写明标注规范脚蹬存在与否、电池仓位置作为分类依据如果项目验收不强制区分这两类更推荐的方案是合并成一个大类two_wheeler把识别问题简化成“有没有两轮车进电梯”这在实际消防场景里常常更好用。5.4 不锈钢反光和镜像把模型绕晕靠 NMS 阈值救不回来现象轿厢镜面不锈钢壁板上会出现车辆和行人的虚影模型在同一帧里检测到两三个重叠程度很高的目标框或者把虚影认成真实车辆。原因反光形成的边缘纹理和真实目标非常接近单纯提高置信度阈值会连真实目标一起过滤掉。解决一个有效的做法是把训练样本里明显是反光的区域做负样本挖掘也就是专门截取没有车辆但有反光纹理的画面标成 background推理时则可以配合 NMS 的 iou 阈值适当调低到 0.4把重叠框压掉。最根本的办法还是前面提到的 ROI 裁剪让检测区域避开最严重的反光区块。5.5 预训练模型在陌生视角下的误检投入数据之前先做一轮盲测现象刚开始接触项目时直接拿yolov8n.pt自带权重对电梯视频做推理结果把消防箱、灭火器、拖把、安全窗全部框出来。原因COCO 类别里有大量室内物品电梯画面里的柜子、箱子在平视视角下看起来确实和一些交通工具相似。解决在标注之前先跑一轮盲测把输出结果导出成视频人工看一遍哪些误检是真实常见干扰物。这一步能帮标注阶段提前圈定难例也能用来评估是否需要把某些反复误检的干扰物加进负样本集合。6. 评估集设计与落地告警从 mAP 到真实拦截6.1 评估集按电梯、时段、机位分层指标分开看评估阶段不要只给一个总 mAP。电梯项目的真实边界条件是安装位置和光照所以评估集至少要按“训练电梯之外的新电梯”“夜间时段”“开门关门两种状态”三个维度划分。每一层单独算 mAP50、误报率 FPR 和每类别的漏检率。这样的表格放在毕设或竞赛报告里比单张 PR 曲线有说服力得多。评估子集帧数mAP50电动车误报率说明同电梯白天3000.952.0%理想状态新电梯白天3000.786.3%观察泛化能力新电梯夜间3000.6111.0%夜间的问题所在重点关注新电梯夜间那一行多数项目的短板会在这里暴露。6.2 告警回调最小实现置信度、面积占比与连续帧确认部署时把检测、确认、告警三层拆开顺序是模型推理、面积占比过滤、连续帧确认、触发告警。前面给的AlertConfirmer已经覆盖了确认环节实际使用时还需要在处理每一帧时把原始坐标映射回显示画面。我一般会在回调函数里保存触发告警前三帧的画面拼接成一张三联图方便事后审计误报原因。这个项目值得做的原因也在这里数据采集、微调、告警联动三块工作要求明确难度适中技术细节足够支撑一场答辩。我最早做的一版直接拿 COCO 权重去跑电梯视频结果第二天就被反光里的拖把上了一课现在每次接到类似项目我都会先问一句数据从哪来、视角跟部署是不是同一个。先把这条搞清楚后面至少省一半返工时间希望帮到你。本文还有配套的精品资源点击获取