基于YOLOv8的电梯电动车禁入识别系统实现与部署
2026/9/14 2:13:28 网站建设 项目流程

简介:基于YOLOv8的智慧社区电梯电动车禁入识别系统,是一套面向深度学习与计算机视觉方向毕业设计、课程设计的完整方案,专为电梯场景中电动车禁入需求设计。压缩包共8个文件,以代码脚本、模型权重和说明文档为主,其中三个脚本文件覆盖可视化界面、视频检测与模型训练,三份权重文件可直接用于推理,另附说明文件便于快速启动,整体仅约16MB,部署轻量;目前已吸引41人次学习下载。项目代码经完整测试,附带完整数据集、可视化页面与部署教程,能够输出混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果及标签分布图等核心指标,功能完善且操作简单。尤其适合计算机相关专业学生直接作为毕设或课设使用,也便于在此代码基础上扩展其他目标检测功能,满足答辩与项目演示需求。

1. 从电梯里的“禁止入内”贴纸到 YOLOv8 识别闭环,这个毕设项目在解决什么

电梯轿厢里贴“禁止电动车入内”的告示,物业天天擦,天天有人推。真正起作用的是在电梯启动前拦住人的设备。基于 YOLOv8 的智慧社区电梯电动车禁入识别系统,要做的就是在一台接在电梯监控后端的计算设备上,用 YOLOv8 模型实时判断画面里有没有电动自行车,命中后通过可视化界面弹出告警,并联动语音播报或门控。作为毕设或课程设计,这类项目的价值在于把目标检测、数据处理、界面开发和软硬件联动放进一个小框架里,单人一两个月就能完成,演示效果直观。

拿到压缩包后最省事的路径是先把权重跑通,再把训练数据和摄像头视角对齐,而不是直接调网络结构。目标检测在这类场景里的难点并非“有车没车”,而是车把、车座、反光板只要出现局部,界面上要不要响警报。这个问题不解决,后面所有界面和报警都是空转。

2. 电梯场景的 YOLOv8 识别基础:预训练模型、网络结构与数据标注

做这个系统第一件事,往往不是训练,而是把预训练模型放进电梯视觉里看一眼。看过之后会得到两个结果:要么大多数目标都能框住,但把轮椅、童车、乘梯人的反光衣也框进来;要么稍微侧一点的电动车完全漏检。这背后是数据分布差异,不是模型本身的问题。

2.1 电梯监控下的电动车:俯拍、小目标与红外夜视带来的干扰

电梯摄像头通常装在轿厢顶部一角,以 45 度到 60 度的视角俯拍整个轿厢。电动自行车出现在画面里时,多数是斜侧面或尾部,透视压缩后宽高比不稳定,车把和车座在画面中占的比例远小于室外场景。加上广角镜头边缘畸变,同一个目标在画面中心和角落的特征差异很大,模型在 COCO 这类户外数据上学到的“整体轮廓”经验会失效。

夜间低照度时,摄像头切换红外模式,画面转成黑白,颜色特征几乎不可用,车身金属和地板高光会形成大面积反光。电梯门开启瞬间,走廊里的电动车只有车头探进来,目标面积小,且很快被门框截断。这些因素决定了数据采集方式:从真实电梯监控录制视频,按帧提取图像,而不是去网页找一堆电动车照片混合训练。

观测项电梯监控中的典型表现对检测的影响
车身完整度被电梯门或人体遮挡,常露出 50% 以下阈值不宜过高,标注应保留部分遮挡样本
目标像素面积640 分辨率下约 60~220 像素imgsz 保持 640 即可,加到 960 收益有限
光线白天高亮、夜间红外黑白训练集要同时包含两种模式
视角俯视加广角畸变增强参数应关闭大角度旋转,避免学到错误的姿态偏置

这四种情况在电梯项目里几乎同时出现,所以不能只看模型在公开数据集上的 mAP。数据分布对结果的影响,远大于骨干网络换大一号或者训练轮数多加 100 轮。

2.2 YOLOv8 网络结构:C2f、SPPF 和 anchor-free 检测头如何处理这类目标

YOLOv8 的核心结构经常被问到的有两点。第一是 C2f 模块通过跨层分支让信息在骨干网络里更充分融合,对局部被遮挡的目标有更好的语义恢复能力。第二是检测头从 anchor-based 改成 anchor-free,回归分支直接预测中心点和宽高,在目标尺寸变化大但长宽比相对集中的场景下,少了一层 anchor 匹配的调参负担。

对于“yolov8 head 改进”这个方向,建议放到项目后期。如果漏检集中在画面远处的小目标,可以在原有三个检测头前面加一个 P2 小目标头,但这会把特征图放大到输入尺寸的 1/2,训练显存和推理耗时都会明显上升。对于毕设级别项目,一开始用 yolov8s 原装模型配 640 输入,已经比大多数人期望的效果好。真正要改的是数据,不是网络。

保存网络结构图也是答辩时会被问到的一步:

yolo export model=runs/detect/train/weights/best.pt format=onnx imgsz=640

这行命令把训练好的 best.pt 导出为 ONNX 格式。导出成功后,用 Netron 打开 onnx 文件就能看到每一层张量的形状。导出前要注意:imgsz=640必须和训练时的输入尺寸一致,否则模型输入输出 shape 对不上;导出的节点是推理图,不含训练用的 loss 分支。如果不想用命令行,也可以直接调用model.export(format="onnx"),效果相同。

2.3 数据标注规范:单类还是多类,局部遮挡样本要不要标

常见做法是只定义“e-bike”一个类别。电梯禁入针对的是电动自行车和电动轻便摩托,这两类在监控画面里的差异远小于它们与普通自行车的差异,拆成多类会增加标注工作量,报警界面却不需要区分它们。真正容易混淆的是轮椅、大号婴儿车、装有挡风被的电动车,这些应该在训练集的背景类别里多出现,模型才能把它们和电动自行车区分开。

标注时约定这几条规则:

  • 车体或推行状态下目标占画面候选框一半以上时标注;
  • 车头已经进入轿厢、车身大部分在走廊时,露出部分超过四分之一就标;
  • 婴儿车、轮椅、拉杆箱不标,但要在验证集里保留一定数量来观察误报;
  • 同一段连续视频每隔 5~10 帧截取一帧,避免训练集和验证集来自同一段连续帧,否则验证精度虚高。

数据标注后的目录结构通常写成这样:

path: /data/elevator_ebike train: images/train val: images/val names: 0: e-bike

这个 YAML 文件同时给训练脚本标注数据路径和类别名。names必须从 0 开始,类别顺序一旦确定不要在训练过程中修改,否则模型预测的类别索引和标签 txt 对不上。第一次训练前可以跑一遍yolo detect train data=elevator.yaml model=yolov8s.pt epochs=1,正常启动时会有标注数量提示;如果提示找不到标签,优先检查标注文件是否和图片同名、是否放在对应的labels目录下,而不是怀疑数据集本身。

3. 训练自己的数据集:YOLOv8 环境配置、超参与损失曲线

训练阶段大部分坑集中在环境装配、显存超限和 loss 曲线看不懂。先给一套省事的环境配置,再讲参数怎么设,最后落到损失曲线怎么看。

3.1 YOLOv8 环境配置:conda、CUDA 与依赖库的对齐

我一般用 conda 创建独立的 Python 3.10 环境,再安装 ultralytics 和 opencv:

conda create -n ebike python=3.10 -y conda activate ebike pip install ultralytics opencv-python nvidia-smi

ultralytics 会一并带起 torch、torchvision、onnx 等依赖。nvidia-smi用来确认本机显卡驱动状态,驱动正常时 torch 自带的 CUDA 运行库基本都能直接工作。遇到无法在线安装的环境,先在有网络条件的机器上执行pip download ultralytics opencv-python -d wheel_cache,再把整个 wheel 目录拷贝到目标机器,用pip install --no-index --find-links=wheel_cache ultralytics opencv-python完成安装,整个过程不需要访问外部源。GTX1660Ti 这类 6GB 显存显卡上,这套组合可以直接跑训练;纯 CPU 机器只建议做推理演示,不建议训练。

3.2 训练关键参数与损失曲线:一份可以直接抄的参数表

核心训练命令如下:

yolo detect train data=elevator.yaml model=yolov8s.pt \ epochs=300 batch=8 imgsz=640 device=0 \ patience=40 lr0=0.01 close_mosaic=10 \ project=runs/elevator name=train_ebike
参数建议值为什么这样给
epochs200~300电梯电动车场景样本量小,后段训练仍会缓慢提升 AP,不建议低于 150
batch8(6GB 显存)GTX1660Ti 这类 6GB 卡上 8 是安全值,显存不足就减到 4 并关闭 cache
imgsz640目标占画面比例大,640 足够;平均目标小于 40 像素时再试 960
patience30~50前 50 轮不触发早停,防止训练初期 loss 震荡就提前中断
lr00.01(SGD)/ 0.001(AdamW)手动改学习率时要注意和优化器匹配,否则收敛慢
close_mosaic10最后 10 轮关闭 mosaic 增强,让模型适应真实分布,否则验证集指标偏低

训练结束后,runs/elevator/train_ebike/下会生成weights/best.ptlast.ptresults.pngresults.csv。选模型不能只看 val box_loss,还要结合混淆矩阵观察误报类型。热词里经常有人搜“yolov8 画损失函数曲线图”,官方 results 图里已经包含,如果想自己复现:

import pandas as pd import matplotlib.pyplot as plt df = pd.read_csv("runs/elevator/train_ebike/results.csv") df.columns = [c.strip() for c in df.columns] for col in ["train/box_loss", "val/box_loss"]: plt.plot(df[col].dropna(), label=col) plt.legend() plt.savefig("loss_curve.png")

results.csv的列名在不同版本里可能带空格,所以先用列表推导式统一 strip。曲线横轴是 epoch,看 loss 是否持续下降;如果 val loss 在某个 epoch 后反弹而 train loss 继续下降,说明进入过拟合,回退到 val loss 最低点对应的权重即可,这也是选择 best.pt 而不是 last.pt 的原因。

3.3 电梯场景专属的数据增强:旋转要关,黑白样本要真

常见误区是打开所有增强项让模型“更泛化”。电梯监控摄像头位置固定,视角不会有大的旋转和多尺度变化,所以degrees要调小甚至关闭,translate保持默认。flipud也没有意义,车辆不会倒立,开着反而增加错误特征;fliplr可以保留,因为电梯左右两侧都可能进车。

夜间样本不足时,不要靠调 HSV 模拟黑白红外图。红外图像不是简单去色,而是对比度变化和噪点增加,最直接的办法是录一段夜间电梯监控视频,抽 100~300 帧补充标注。如果项目要求只用白天数据,就需要在界面层做两套置信度阈值:夜间模式把 conf 从 0.45 提高到 0.55,用于压制金属反光。

4. 可视化界面与部署闭环:RTSP 接入、推理线程与报警联动

模型训完只是第一步。交付物里“可视化界面”的意义是让非技术人员能看到画面里的框,也让报警动作有据可查。常见做法是把程序拆成取流、推理、界面、告警四个独立部分。

4.1 部署架构拆分:为什么界面和推理要分线程

用 PySide6 或 Tkinter 做界面的项目,最容易翻车的点是把推理直接写到界面的 while 循环里。摄像头一卡,界面就无响应;推理一慢,画面也卡。常见做法是开一个抓帧线程专门读 VideoCapture,检测结果通过队列传递,界面只负责把最新帧和框画出来。如果项目要求远程查看,可以用 Flask 加定时推帧,后端把带框的 JPEG 推到页面,前端用 img 标签刷新即可。

报警联动是这个系统的重点。识别到电动车之后,至少要有两个动作可选:语音播报“电动自行车禁止入梯”和通过 USB 继电器阻断电梯关门。毕设环境里推荐 USB 继电器,串口速率 9600 即可工作;如果对接已有楼宇系统,则需要看对方给出的是干接点还是电平信号,接口方式稍有不同。

4.2 一个最小可运行的可视化界面代码:防抖、冷却与画框

import time import cv2 from ultralytics import YOLO model = YOLO("best.pt") cap = cv2.VideoCapture("elevator_room.mp4") # 换成 RTSP 地址即可 COOLDOWN = 30 # 两次告警最小间隔(秒) HIT_FRAMES = 5 # 连续命中多少帧判定为一次有效告警 CONF = 0.45 hit_count = 0 last_alarm = 0.0 while cap.isOpened(): ok, frame = cap.read() if not ok: break res = model.predict(frame, conf=CONF, imgsz=640, verbose=False) boxes = [b for b in res[0].boxes if int(b.cls) == 0] if boxes: hit_count += 1 else: hit_count = max(hit_count - 1, 0) now = time.time() if hit_count >= HIT_FRAMES and now - last_alarm >= COOLDOWN: print("trigger alarm: door keep open + voice broadcast") last_alarm = now hit_count = 0 for b in boxes: x1, y1, x2, y2 = map(int, b.xyxy[0]) cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.imshow("elevator e-bike detection", frame) if cv2.waitKey(1) & 0xFF == ord("q"): break cap.release() cv2.destroyAllWindows()

hit_count采用递增递减而不是布尔值,单帧误检只会让计数加一,不会立刻触发。HIT_FRAMES=5表示连续命中 5 帧,在 25fps 视频里大约是 0.2 秒,可以滤掉闪烁式误检,又不会让推行电动车的人跑出画面。COOLDOWN=30是告警冷却时间,防止电梯门反复开关时不停触发。CONF=0.45是置信度阈值,部署后如果反光误报多,优先调它而不是改模型。cap = cv2.VideoCapture处可以直接换成摄像头 RTSP 地址,此时cap.isOpened()的成功与否取决于网络和设备响应速度。

4.3 RTSP 断线重连与边缘设备上的推理加速

摄像头偶发断电是常态,原生的 VideoCapture 在断流后往往表现为isOpened()为 True 但read()一直返回 False。需要写一个带重试的打开函数:

def open_capture(url, retries=3, timeout_s=10): cap = None for attempt in range(retries): cap = cv2.VideoCapture(url, cv2.CAP_FFMPEG) cap.set(cv2.CAP_PROP_OPEN_TIMEOUT_MSEC, timeout_s * 1000) cap.set(cv2.CAP_PROP_READ_TIMEOUT_MSEC, timeout_s * 1000) if cap.isOpened(): return cap if cap is not None: cap.release() time.sleep(2 * (attempt + 1)) return None

CAP_PROP_OPEN_TIMEOUT_MSECCAP_PROP_READ_TIMEOUT_MSEC决定 OpenCV 等待设备响应的时间,单位是毫秒,对于网络摄像机不能设太短,否则网络抖动一次就会触发重建。重试间隔按 2、4、6 秒递增,避免摄像头重启过程中反复握手。推理加速方面,如果部署机器有一张 GTX1660Ti,torch 半精度推理下 640 分辨率单帧大约 20ms 到 40ms,足够覆盖电梯门开合周期。真正容易成为瓶颈的是取流缓冲,CAP_PROP_BUFFERSIZE应设为 1,让推理拿到最新画面而不是积压的旧帧。

5. 验收测试与误报压制:三个场景、两个阈值、一个复位条件

跑通部署只算完成一半。最后要做的验收很简单:准备三段视频。第一段是空电梯,有人进出但不推车,允许 0 次误报;第二段是推行电动车进入轿厢,要求从车头进入画面到车门关闭前至少触发一次告警;第三段是婴儿车、轮椅、大件行李依次经过,记录误报次数。用同一套防抖逻辑统计:

import cv2 from ultralytics import YOLO model = YOLO("best.pt") cap = cv2.VideoCapture("test_01_empty_elevator.mp4") frames = 0 false_alarm = 0 hit_count = 0 while cap.isOpened(): ok, frame = cap.read() if not ok: break frames += 1 res = model.predict(frame, conf=0.45, imgsz=640, verbose=False) hit_count = hit_count + 1 if res[0].boxes else max(hit_count - 1, 0) if hit_count >= 5: false_alarm += 1 hit_count = 0 print("total frames:", frames, "false alarms:", false_alarm)

这个脚本把第 4 章的防抖逻辑原样搬到统计端,得到的误报次数可以直接写进答辩材料。空电梯场景允许 10 分钟最多 1 次;有人无车场景允许 10 分钟不超过 2 次,因为条纹外套和反光条偶尔会骗过模型。

5.1 置信度阈值和连续命中帧数的联动调整

先看训练日志里的PR_curve.png,取 precision 和 recall 交点附近的阈值作为起点,再在 0.4、0.5、0.6、0.7 四个值上分别跑 5.1 的三段视频,统计“空梯误报次数”和“真实目标触发时长”。漏报多时把 conf 降到 0.35,同时把 hit_frames 提高到 8;误报多时把 conf 抬到 0.6,hit_frames 降到 3。电梯场景里有个反直觉的点:降低连续命中帧数不一定增加误报,因为模型单帧误报往往是闪烁式的,hit_count 涨到 3 又跌回去,而真实推行车会连续命中 20 帧以上。

5.2 最后建议:把参数放到配置文件里,而不是改代码

把模型路径、置信度阈值、连续命中帧数、冷却时间和摄像头地址全部挪到 config.ini:

[detection] model_path = weights/best.pt conf = 0.45 hit_frames = 5 cooldown = 30 iou = 0.45 [source] rtsp_url = rtsp://user:pass@ip:554/Streaming/Channels/1

程序启动时用 configparser 读入,界面另外提供夜间模式按钮,一键把 conf 切换到 0.55。后续换摄像头、换电梯都不需要改代码。第一次安装时先在白天光线下连续跑两小时,确认空电梯不误报,再开启夜间模式重新跑一遍夜视视频,两个时段都通过后,这套系统才算真正可交付。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询