简介:面向电梯监控场景的目标识别项目资源,用于识别电梯内视角的电动车与自行车,适合毕业设计、课程设计、实训及学科竞赛使用。项目基于电梯内视角数据集微调 YOLO 预训练模型,涉及迁移学习、目标检测与多目标跟踪等知识点,并提供检测与跟踪两种技术路线:检测方法对包含目标实例的每一帧返回标注图像,跟踪方法在检测结果上做去重处理,便于按需选用。压缩包共 134 个文件,以 Python 源码(34 个)、YAML 配置(34 个)及 JPG/PNG 图像样本(41 个)为主;其中 Python 脚本承载训练、验证与推理逻辑,YAML 用于配置模型与数据参数,图片样本来自电梯视角标注场景。另含 Dockerfile 环境配置、Markdown 说明、Jupyter Notebook 示例及辅助脚本,整体仅 16.96MB,目录结构清晰,可快速复现。已有 64 人学习浏览,代码经严格测试可直接运行,覆盖数据准备、模型训练与推理等环节,适合作为毕设、课设或竞赛项目的模板,也可基于现有流程做二次开发,或参考其中的设计报告组织项目方案。
1. 电梯监控视角下的电动车识别:一个看起来常规、落地上手才知道门道多的检测项目
电梯监控里识别电动车,这几年已经成了不少小区物业的刚性需求:电动车进电梯上楼充电,安全隐患大,摄像头看到的又是俯视的轿厢画面。这类项目落到毕设、课设或竞赛里,任务一句话就能说清——在电梯监控画面中把电动车和自行车框出来。很多人以为拿现成检测模型跑一遍就完事,真正动手才发现,俯拍、广角畸变、反光、小目标这些因素堆在一起,通用模型的准确率直接掉一截。这篇笔记顺着这个方向,从方案选型、数据集整理、训练调参到现场排错,给出一套能复现、能在答辩和竞赛里站得住的完整做法,适合手头只有一块消费级 GPU 的学生。
2. 方案选型:为什么电梯场景首选 YOLO,以及模型版本怎么定
电梯电动车识别在毕设和竞赛里,绝大多数做的是目标检测,不是图像分类,也不是实例分割。这个决定不是拍脑袋,而是和任务需求强绑定的。分类网络只输出一个全局标签,告诉你这一帧有电动车,但物业报警系统要的是目标的具体位置,否则没法联动后续的语音提醒和告警上报。实例分割能给出像素级轮廓,标注成本却比框高了一个量级,课设和竞赛周期通常只有两三个月,大量时间被标注吃掉,模型和论文都来不及打磨。目标检测的边界框输出,恰好落在“信息够用、成本可控”的位置上。
2.1 电梯轿厢场景和普通道路检测差在哪
电梯是一个机位极稳定的监控场景,视角固定、高度俯视、画面里通常只有一个人和一辆车,但稳定不代表简单。广角镜头产生的畸变会让车身在画面边缘被拉长,同一个目标在不同位置的宽高比差异很大;人推车进电梯时,身体会大面积遮住车把和车座,完整车身出现的有效时间往往只有一两秒;不锈钢壁的反光和地砖倒影,还会让车身颜色和轮廓在连续帧里剧烈变化。这些因素叠在一起,通用检测模型直接拿来跑,很容易出现“人遮挡时检不出、反光时误检出”的两头翻车。
和道路车流检测不同,电梯场景不存在普遍的小目标问题。人推车进电梯,目标在 640×640 的输入下通常占几十到上百像素,真正的难点是遮挡、畸变和光照,不是尺度。这意味着数据增强的重点应该放在模拟遮挡、仿射畸变和亮度抖动上,而不是反复做多尺度缩放。先把这个场景特点想清楚,后面的增强策略和训练参数才有依据。我一般会先录几段真实电梯视频,观察模型在哪里漏、在哪里误,再决定数据集怎么搭,这样比盲目加数据更省时间。
2.2 模型版本不追新:按毕设时间和显存选 YOLOv8n 还是 YOLOv5s
社区里做电梯电动车识别,主流还是 YOLOv5 和 YOLOv8 两个系列。版本新不代表适合你,我选型的标准很直接:显卡显存有多大、答辩前还剩多少时间、出了问题能不能快速搜到答案。手头是 6GB 显存的 RTX 3060,首选 YOLOv8n。n 是 nano 版本,参数量小,COCO 预训练权重加载后,640 输入下训练一个 epoch 只要几分钟,800 张图的数据集跑 100 轮,两三个小时能完成。这个训练节奏意味着你有多做几组对照实验的余量,对毕设论文的实验章节帮助很大。
如果项目偏课设、时间紧,只想快速跑通一条完整流程,YOLOv5s 也是稳妥选择。YOLOv5 资料更老更全,训练报错时排查答案的速度快很多。至于 YOLOX 或 DETR 这类模型,我不建议作为主线。YOLOX 的标注格式和训练脚本需要额外适配,DETR 在几百张数据的小数据集上收敛慢,训练时间翻倍,性价比太低。竞赛做方案对比时可以额外跑一个 Faster R-CNN,用一阶段和双阶段的差异支撑选型理由,主线仍然放在 YOLO 上。
2.3 加载 COCO 预训练权重:能迁移什么,不能迁移什么
COCO 数据集里有 bicycle 类,但没有电动自行车这个细分类,也没有踏板式电动车。因此预训练权重的迁移效果是不对等的。加载 COCO 权重后,模型对自行车的特征是熟悉的,轮毂、辐条、车架三角这些结构在俯拍里依然可辨,bicycle 类只需要很少的标注样本就能学到不错的特征。电动车是一个没有预训练语义的新类,模型只能从零学,样本量不够或场景单一,很容易学到背景纹理而不是车身结构,这是很多项目精度上不去的隐藏原因。
所以流程上我一般先加载 COCO 预训练权重,再把数据集类别数改成本项目的 2 类做迁移训练,而不是随机初始化。随机初始化在 100 轮内很难收敛到可用 mAP,预训练相当于把模型已经学会的视觉特征搬过来,只需要在电梯场景上微调。这部分迁移学习分析也能直接写进论文的“关键技术”章节,讲清哪一类受益、哪一类需要更多数据,比贴一张网络架构图有内容得多。
3. 数据集整理:电梯视角下电动车与自行车的采集、标注与增强
数据质量直接决定这个项目能不能用,模型和参数反而排在后面。电梯电动车识别项目最常见的问题,是训练集来自网络下载的平视图片,验证集 mAP 不错,一到真实电梯俯拍就漏检,本质是训练和测试分布不一致。数据整理的第一原则,是用贴近真实摄像头视角的图做训练,而不是下载一堆背景干净的商品图。
3.1 数据来源怎么配:自采为主、公开数据为辅
最可靠的数据是自己拍。找一处电梯,手机横屏贴近轿厢内壁顶部模拟监控位置,分别拍空电梯、人推自行车、人推电动车进出的视频。拍摄时覆盖几个变量:白天、晚上、照明偏暗的时刻;电梯门开和关的状态;人站在车左侧、右侧、后方等不同位置。视频按每 3 到 5 帧抽一张图,人工挑目标清晰、遮挡程度不同的帧,30 分钟视频通常能筛出三四百张,起步够用。
公开数据集在电梯场景上很稀缺,室外街道的自行车图可以少量补充,用来增加车体角度和外观多样性,但比例要克制。我的经验是俯拍自采和室外补充按 4:1 混合,室外图超过这个比例,会把模型带偏,让它在俯拍下变得迟钝。网络图片用于课设和竞赛的非商业用途一般问题不大,但不要在论文里放来源不明的图,答辩评委对图片来源敏感,这是容易翻车的细节。
3.2 标注规则:两类目标为什么比十类更容易标乱
这个项目只有两个类,但标注起来反而比十类的通用数据集更容易乱。电动自行车从外形上和普通自行车几乎没区别,只是多了电池盒、电机或仪表盘,不同人对“这算电动车还是自行车”的判断可能完全不同,类别语义一旦乱了,模型再强也学不出稳定边界。
我给这类项目定规则时,先写一份简短标注规范:车身上有明显电池盒、电机凸起或仪表盘的标 ebike;车身干净、看不出电动部件的标 bicycle;当前帧无法判断的直接丢弃,不要硬标。少一张存疑的图,好过让模型多学一个错误样本。标注工具用 labelImg 或 X-AnyLabeling 都可以,导出格式统一成 YOLO 的 txt,每行是类和归一化坐标,这个细节直接决定下一章训练能否跑通。
3.3 针对性增强:用 Albumentations 模拟电梯光照与运动模糊
电梯场景的噪声集中在光照、反光和运动模糊,增强的目标不是把图搞花,而是让模型对亮度变化和轻微模糊不敏感。我用 Albumentations 做训练增强时,保留下面这几个算子就够了:
import albumentations as A train_transform = A.Compose([ A.LongestMaxSize(640), A.PadIfNeeded(min_height=640, min_width=640, border_mode=0), A.HorizontalFlip(p=0.5), A.RandomBrightnessContrast(brightness_limit=0.25, contrast_limit=0.25, p=0.8), A.RandomGamma(gamma_limit=(80, 120), p=0.5), A.MotionBlur(blur_limit=5, p=0.3), A.Mosaic(p=0.4), ], bbox_params=A.BboxParams( format="yolo", min_visibility=0.3, label_fields=["class_ids"] ))逻辑说明:LongestMaxSize 和 PadIfNeeded 先把输入统一到 640,避免直接拉伸变形。HorizontalFlip 在电梯场景是安全的,轿厢画面左右对称,翻转后目标仍是合理视角;不要加 VerticalFlip,电梯画面里目标不会上下颠倒。RandomBrightnessContrast 和 RandomGamma 模拟灯频闪和不同时段亮度差,是整个增强里对现场泛化帮助最大的部分。MotionBlur 模拟人快速推车进梯产生的拖影,Mosaic 把四张图拼成一张,平衡目标比例分布,代价是部分框被边缘切掉,所以 min_visibility=0.3 表示切掉超过七成的框直接丢弃。
参数说明:brightness_limit 不建议超过 0.3,电梯画面再暗也不会暗成剪影,拉太猛会让模型学到“暗处就是车身”这种错误关联。blur_limit 用 5 就够,3 到 5 的核能模拟手持抖动和快速移动,更大的核反而破坏车架轮廓。增强代码接在 PyTorch Dataset 里即可,不需要把增强图落盘,每轮在线生成变体,相当于把数据集放大了几十倍。
4. 训练与调参:让检测器在电梯俯拍视角下真正收敛
数据集就位后,训练部分相对机械,但也最考验耐心。电梯电动车识别项目在训练阶段的失败,大多不是模型选错,而是配置文件不规范、参数没按数据量调整、日志看不明白。下面按完整流程讲一遍。
4.1 数据集配置文件与目录结构,先写清楚再动手
YOLO 系列对目录结构有固定要求。项目根目录下建 datasets/elevator 文件夹,里面分 images 和 labels,各自再分 train 和 val。图片和标签必须一一对应,图片是 images/train/001.jpg,标签就是 labels/train/001.txt,文件名一致、扩展名不同,这一步出错训练会报警告并丢数据。
数据集配置文件用 YAML,内容如下:
path: ./datasets/elevator train: images/train val: images/val names: 0: ebike 1: bicycle逻辑说明:path 是数据集根目录的相对路径,train 和 val 是相对根目录的图片子目录,YOLO 会去同名 labels 目录下找标签。names 的顺序必须和标注时输出的类别 id 完全一致,0 是 ebike、1 是 bicycle,配置写反会出现 loss 正常下降但推理类别全部错位的情况。配置文件不需要写 nc 类别数,Ultralytics 会根据 names 自动推断。
4.2 训练命令和关键超参数:这些参数按什么逻辑调
Ultralytics 框架下训练命令很短,但每个参数要有调整依据。以下是我常用的命令,初学者可先复制,再按显存调整 batch:
yolo detect train \ data=datasets/elevator.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ lr0=0.01 \ patience=30 \ device=0参数说明:epochs 设 100,对几百到一千张的电梯数据集足够,再多大概率过拟合。如果曲线第 80 轮还在稳定上升,可以用 last.pt 追加训练,不必一开始就设 200。batch 设 16 是 6GB 显存下的保守值,显存不够优先降 batch 到 8,其次是 imgsz 从 640 降到 480,不要同时降太多,否则 BN 统计不稳定。lr0 默认是 0.01,数据集小于 500 张时建议改成 0.005,小数据集上过大的初始学习率会让 loss 前期震荡,后续难以收敛到好的局部最优点。
device=0 表示用第一张 GPU,只有 CPU 或 Mac 的 MPS 时换成 cpu 或 mps,但训练时间会拉长很多,条件允许还是借一块显卡。不建议一开始就上自动调参工具,先把一组合理参数跑通全流程,再根据日志局部调整,更符合课设和竞赛节奏。训练结果在 runs/detect/train 下,best.pt 是验证集上 mAP 最高的权重,last.pt 是最后一轮的权重,实战一律用 best.pt。
4.3 训练日志怎么读:判断模型是真收敛还是假收敛
训练结束后,Ultralytics 会生成 results.png,包含 train/val 的 box loss、cls loss、dfl loss 和 mAP50、mAP50-95 曲线。不要只看 mAP 最终值,要把 loss 曲线和 mAP 曲线放一起看。
判断原则:val/box_loss 和 val/cls_loss 持续下降,说明模型在学;如果 train loss 一直降而 val loss 在第 60 轮开始上翘,是典型过拟合信号,此时 mAP50 可能还在缓慢上升,但继续训现场泛化只会变差,应该取第 60 轮附近的权重,而不是最后一轮。如果 val loss 从第 10 轮开始横走不降,先检查标签格式和类别 id 是否错位,再抽几张训练图做可视化推理,确认标注框有没有对到目标上。
一个容易误导人的细节是 mAP50 和 mAP50-95 的差距。电梯俯拍下边框定位容易出现几个像素偏差,mAP50 到 0.9 以上而 mAP50-95 只有 0.5 左右是正常现象,答辩展示 mAP50 就好,同时补一段现场视频推理结果,比硬拉 mAP50-95 更有说服力。
注意:训练中看到大量 skip 或 label correction 提示,说明标签有越界或空文件。越界坐标通常来自手工标注时拖框超出图片边缘,解决办法是批量扫描标签目录,把超出 0 到 1 区间的坐标截断到边界。
5. 避坑记录:电梯电动车检测项目里最容易翻车的 5 个问题
这个项目表面是普通检测任务,实际踩坑很多在场景理解和工程细节。下面 5 个问题按现象、原因、解决写成排查清单,每一条都是真实环境里会遇到的情况。
5.1 现象:电梯门反光区域频繁出现假检测框
现象:模型在不锈钢电梯门上检出 ebike,置信度还不低,报警框在视频里来回跳。原因:电梯门反光把车身倒影映在金属表面,训练数据里如果混有反光较强的图,且反光区域被标注成目标,等于主动教模型去认倒影。解决分两步,先清理训练集,删掉标注框落在反光倒影上的图;再加入一批“空电梯但有强反光”的负样本图,这些图没有任何标注框,让模型学会对反光纹理输出低置信度。推理端再加连续帧确认逻辑,同一目标连续 3 帧以上检出才触发报警,能压掉大部分瞬时误检。
5.2 现象:自行车与电动自行车互相误识别
现象:验证集两类都能检出来,到现场后电动自行车被报成 bicycle,或自行车被报成 ebike。原因:两类外观在“车身干净”和“有电池盒”之间是连续过渡的,标注规则不统一,类别边界就歪了。解决:重新审核标注规则,统一按“车身中段是否有明显凸起”判断,有凸起一律 ebike,没有一律 bicycle,并在规范里配典型图例;拿不准的图宁可丢弃。训练后看混淆矩阵,交叉项偏高时,把两类中外观最接近的样本挑出来各增加一倍再训,比调模型参数更直接。
5.3 现象:测试集 mAP50 很高,现场视频却漏检
现象:训练集和验证集从同一段视频抽帧,验证 mAP50 到 0.9,换个电梯录 30 秒视频,漏检一半。原因:训练、验证数据同源,背景几乎一样,模型把“电梯轿厢的具体纹理”当成判别特征,换一台电梯光照、地砖、白平衡全变,模型就失效了。解决:验证集不能从训练视频里随机抽帧,单独录一段不同时间、不同电梯的视频只做验证;更严格的做法是 70% 视频抽帧训练,剩余 30% 完全不参与训练,作为最终现场测试集。竞赛中能展示一段从未参与训练的真实电梯视频检测效果,说服力远大于一张 mAP 曲线图。
5.4 现象:训练 loss 不下降或直接变成 NaN
现象:前 10 个 epoch,loss 在初始值附近波动不下降,或某一步直接跳成 NaN。原因:最常见是标签文件出现负数或大于 1 的坐标,其次是 images 目录里有损坏图片,读出来是纯色块,导致 loss 计算异常。解决:训练前写一个校验脚本,遍历 labels 目录,凡是坐标不在 0 到 1 区间、或宽高小于 0.001 的 txt 全部列出,配合图片修掉;出现 NaN 不要先调学习率,先把标签和图片完整性过一遍,多数情况是数据的问题,不是模型的问题。空标签文件也会触发警告,统一删掉。
5.5 现象:现场推理速度达不到实时
现象:用 CPU 跑 best.pt,FPS 只有 2 到 3,说不清电梯报警延迟多久。原因:直接跑 PyTorch 模型在 CPU 上本身就慢,又没有做模型导出优化。解决:先导出成更轻的推理格式。常见做法是导出 OpenVINO 或 ONNX,命令一条就能完成:yolo export model=best.pt format=openvino,导出后在 CPU 上跑,FPS 通常能提升 3 到 5 倍;目标设备是树莓派或 Jetson 时,再考虑 NCNN 或 TensorRT。答辩时写清 CPU 型号、推理框架、输入分辨率三个条件,FPS 数据才站得住。另一个经验是别为了 FPS 盲目把 imgsz 从 640 降到 480,提速换来的小目标漏检在电梯场景得不偿失。
6. 现场置信度阈值校准:用一段没参与训练的视频定模型使用参数
模型训练完,best.pt 不能直接拿去用。训练默认置信度阈值是 0.25,在干净测试集上看着合理,换到现场电梯通常不是误报多就是漏检多。我会在最后做一次阈值校准,方法很直接:录一段 1 分钟、没参与过训练的真实电梯视频,遍历不同阈值跑推理,找漏检与误报的交叉点。
6.1 用脚本统计预测框置信度分布
from ultralytics import YOLO import cv2 model = YOLO("runs/detect/train/weights/best.pt") cap = cv2.VideoCapture("elevator_test.mp4") scores = [] while cap.isOpened(): ret, frame = cap.read() if not ret: break results = model(frame, conf=0.05, imgsz=640, verbose=False) for r in results: for box in r.boxes: if int(box.cls[0]) == 0: # ebike 类别 scores.append(float(box.conf[0])) cap.release() print(sorted(scores))把阈值压到 0.05,让模型把犹豫的预测也放出来,打印所有 ebike 框的置信度,对齐视频时间点人工观察漏检和误报落在哪个区间。通常会出现两个簇:真目标集中在 0.6 到 0.9,误报散布在 0.1 到 0.4,阈值取两个簇之间的低谷,就是当前场景的甜点值。反光严重的现场,这个值经常要提到 0.4 以上。
6.2 阈值调整逻辑与答辩验证标准
校准完阈值再完整回放一遍,记录两个数:漏检目标数和误报框个数。1 分钟视频里出现 3 辆电动车,全部检出且无误报,这就是能写进答辩材料的结果。我习惯把 30 秒现场视频连同推理结果录成展示视频,置信度阈值、帧率、模型版本以字幕形式打在角落,评委看到的是可复现的实验条件,而不是一个孤立的高 mAP 数字。这个项目的核心价值不在于用了多新的模型,而是把电梯视角的特殊性吃透,让模型在真实监控条件下稳定工作。我现在的习惯是拿到任何检测任务,第一步先录一段现场视频当测试基准,再决定训练集怎么搭,顺序颠倒过来,后面大概率要重做。希望这份笔记能帮你在电梯电动车识别这个方向上少走几步弯路。
本文还有配套的精品资源,点击获取