
简介一套基于YOLOv8的智慧社区电梯电动车禁入识别系统源码包面向计算机视觉方向的学生和开发者尤其适合毕业设计、课程设计等场景。系统围绕电梯场景下的电动车目标检测展开采用YOLOv8模型训练与推理搭配可视化界面与视频检测模块可帮助使用者从数据准备、模型训练到结果评估完整走通一条检测项目链路。压缩包共8个文件包含3个Python脚本分别对应可视化界面、视频检测、模型训练、3个模型权重文件含预训练与训练所得及2个txt说明文档整体仅15.91MB结构简洁、部署门槛低。项目代码已经过运行验证训练后可生成核心指标曲线、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果与标签分布图为答辩汇报提供直观数据支撑。当前已有42人学习浏览适合初学者上手复现也可在现有代码基础上修改扩展用于其他目标检测任务。1. 电梯口那台旧电脑也能跑起的电动车禁入识别小区电梯口贴着「禁止电动车入内」保安盯监控根本盯不过来真正把车堵在楼道里充电的往往是推车进电梯的那一批人。《基于YOLOv8的智慧社区电梯电动车禁入识别系统》要做的就是让摄像头自己认出一辆电动车联动语音告警甚至阻止关门。这个方案不是多高深的算法研究而是一条完整链路YOLOv8负责检测数据集负责让模型认识「电梯里的两轮车」可视化界面负责让人看得见结果部署教程负责把模型放到真实环境跑起来。它最打动人的是上手门槛低——一台消费级显卡就能训练CPU 也能推理特别适合要交毕设的本科生、想练目标检测全流程的初学者以及物业智能化改造前的技术验证。2. 电梯场景的电动车识别难点不在模型在数据2.1 从「能检测」到「认得准」电梯监控的三种真实干扰马路场景的车辆检测模型看到的基本是完整车身。电梯场景完全不是一回事。人推车进电梯时车身被人体挡住一半是常态后面再跟进来一个人车尾也被挡住检测器面对的经常是「半个电动车」。这是第一种干扰也是最常见的误检来源——车身中段被完全遮挡时模型会把人的腿部特征和车轮特征混在一起。第二种干扰来自安装角度。电梯摄像头通常装在轿厢顶部广角俯视车头朝里、朝外、侧放三种姿态下电动车在画面里的形状差异非常大。广角边缘的畸变还会让车把手和车筐变形车轮可能被拉成椭圆。很多公开数据集里的电动车图片是平视角度拍的模型在俯视角度下直接掉点这就是「训练集看着挺好一上真实监控就翻车」的主要原因。第三种干扰是光照。电梯内顶灯加不锈钢门反光车身高光区域会直接吃掉车轮和车架轮廓镜面反射还会把周围环境映进车身区域。夜间低照度下监控画面噪点变大小目标更难识别。这些干扰叠加在一起决定了「完整数据集」不应该只是网上拼凑的图片包而必须包含与电梯摄像头视角、遮挡、光照分布一致的样本。动手前的数据体检从目标小区实际监控导出 10 段视频每段抽 20 帧按下面三个维度过一遍观察项判断标准不达标时的动作目标完整度车身可见比例是否超过 50%补充遮挡样本而不是盲目加数据量最小目标宽度画面中车身最窄处是否大于 40 像素提高采集分辨率或降低检测距离光照分布高光、暗光、夜间样本是否都有分时段采集夜间单独补充这个体检做 15 分钟比先标注 1000 张图再发现方向错了要划算得多。2.2 YOLOv8 的选型理由精度、速度与复现成本的平衡点目标检测模型可选范围很广但毕设和课设项目有一个共性约束时间有限显卡一般还要能在答辩现场讲清楚。YOLOv8 是当前这个约束下的最佳平衡点。相比 YOLOv5YOLOv8 把 C3 结构换成了 C2f梯度流更丰富对小目标和遮挡目标的特征提取更充分检测头从 anchor-based 换成 anchor-free省去了调 anchor 参数的环节默认参数就能跑出不错的结果损失函数采用 DFL 加 CIoU框回归更精确特别适合电动车这种长宽比不规则的物体。很多同学纠结 YOLOv8 和 YOLOv7 怎么选实际落地中 v8 的部署生态更活跃RK3588、Jetson 这类边缘设备上都有现成案例遇到问题能搜到解决方案这对单兵作战的学生项目来说比那一点精度差异更重要。对比维度YOLOv5YOLOv7YOLOv8网络结构C3E-ELANC2f检测头anchor-basedanchor-basedanchor-free默认参数稳定性需要调 anchor需要调 anchor开箱即用部署教程丰富度丰富一般最活跃对遮挡/小目标一般较好较好具体选哪个尺寸看训练和推理的硬件。YOLOv8n 体积最小适合边缘设备实时推理YOLOv8s 精度更高显存占用和速度都在消费级显卡可接受范围。我的建议是先用 n 跑通全流程再用 s 做最终版本两个模型的训练代码完全相同只是换一个权重文件的事。YOLOv8 的网络结构图和训练自己的数据集这两个话题网上教程非常多这也从侧面说明选 v8 能把踩坑成本降到最低。3. 把环境先跑通YOLOv8 推理链路的最小闭环3.1 环境配置显卡不是必需品但显存决定训练深度不少同学一开始就卡在环境上。YOLOv8 的环境配置其实很简单核心就一个ultralytics包。我自己习惯先用 conda 建独立环境避免和系统 Python 相互污染conda create -n ebike python3.10 -y conda activate ebike pip install ultralytics python -c from ultralytics import YOLO; print(YOLO(yolov8n.pt))最后一行会首次加载预训练权重如果输出一段模型结构信息而不是报错说明安装成功。ultralytics会自动装好对应版本的 PyTorch不需要手动安装 CUDA 工具链。这里有个常被忽略的点默认装的是 CPU 版 PyTorch训练会很慢。确认 GPU 是否可用用一行命令python -c import torch; print(torch.cuda.is_available())输出True说明 GPU 可用输出False说明装成了 CPU 版。解决办法是到 PyTorch 官网按自己的 CUDA 版本重新安装 torch然后再装ultralytics。环境配置这一步卡住的人多半是没确认 PyTorch 和 CUDA 的对应关系而不是ultralytics本身的问题。如果你用的是 GTX 1660 Ti 这类 6GB 显存的显卡把训练参数里的 batch 设为 8 到 16 之间完全跑得动不要被网上「大显存才配玩 YOLO」的说法吓退。3.2 用预训练权重做第一次推理跑通的最小验证环境装好后先用 COCO 预训练权重跑一张图验证整个推理链路。这一步很重要它能提前暴露路径、依赖、中文乱码等一堆后续会反复出现的问题from ultralytics import YOLO model YOLO(yolov8n.pt) results model.predict( sourceelevator_frame.jpg, # 电梯实拍图或任意图片 conf0.25, # 置信度阈值低于该值不显示 iou0.45, # NMS 的 IoU 阈值控制重叠框合并 imgsz640, # 推理分辨率越大越慢但小目标越准 saveTrue, # 保存带标注的结果图 projectruns/detect, # 输出根目录 namefirst_try, # 本次输出子目录 ) for r in results: for box in r.boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) print(fclass{model.names[cls_id]}, conf{conf:.2f})跑通的标志是runs/detect/first_try下生成一张带框的图片。conf和iou这两个参数在后续调试中会频繁用到conf调低能减少漏报但增加误报iou调高会让密集重叠的框被合并。预训练模型只认识 COCO 的 80 类物体其中bicycle和motorbike和电动车有一定相似性所以第一次推理可能会把电动车识别成自行车——这是正常的恰恰说明模型迁移学习有基础。source参数不止支持图片直接传入视频文件路径或摄像头 ID 也能跑这就是后面可视化界面的原型。4. 凑一套能训的电动车数据集公开盘点、自采与 VOC 转 YOLO4.1 公开数据集盘点哪些能用哪些是坑标题里写了「完整数据集」但说实话网上能直接下载的公开数据集几乎没有专门针对「电梯内电动车」的。很多同学第一反应是找 CCPD 数据集但 CCPD 是车牌检测数据集里面的「车」是车牌而不是电动车HRSC2016 是遥感船只数据集CrowdHuman 是密集行人数据集和电梯场景差得很远。我见过有人拿这些数据集硬训结果模型学会了检测车牌和船完全不认识电动车。数据集实际内容对电梯电动车项目的价值COCO80 类日常物体含 bicycle做预训练权重迁移学习起点CCPD中国车牌不适用类别完全不同CrowdHuman密集行人大量遮挡遮挡样本的标注思路可参考HRSC2016遥感船只不适用自采数据模拟电梯监控角度核心决定检测效果上限结论很直接这个项目的数据集主体应该是自采的。COCO 的 bicycle 和 motorbike 图片可以作为辅助迁移数据但最终训练集必须包含大量俯视、遮挡、电梯光照环境下的电动车图片。数据量不用贪多质量合格的 500 张图配合数据增强效果比网上下载 5000 张角度不符的图好得多。数据集的「完整」不是说数量大而是覆盖了电梯场景的主要干扰形态。4.2 自采数据手机就够了但角度要模拟电梯摄像头没有真实电梯监控权限时用手机就能完成采集。关键是把手机摆在正确的位置——电梯轿厢顶部角落模拟 2.2 米左右高度的俯视视角打开广角模式。拍摄时覆盖这些形态人推车进电梯、车头朝里、车头朝外、车身侧放、前后遮挡、夜间和白天各一半。拍摄原则是「模拟真实安装位置」而不是像拍商品图那样把车完整摆正。采集到的图片不需要全部进训练集。把模糊的、目标占比过小的、和现有样本高度重复的图删掉剩下 300 到 500 张做初始训练集就够了。考虑到隐私尽量避开可清晰识别的人脸区域这也是工程落地的常识。原始图片统一重命名为纯数字文件名避免后面脚本处理时遇到中文路径问题。4.3 标注与格式转换LabelImg 手把手以及边界框的四个边界坑标注工具用 LabelImg导出格式选 PascalVOC。标注原则有一条必须执行框住电动车车身不要把人框进去。人推车进电梯时人和车是粘连的框住车身意味着主动舍弃被遮挡的部分让模型学习「车身特征」而不是「人体特征」。标注完成后拿到的是 XML 文件YOLOv8 训练需要的是 TXT 格式。转换脚本不长但边界情况很值得注意import xml.etree.ElementTree as ET from pathlib import Path CLASSES [e-bike] # 类别名必须和标注时完全一致 def convert_voc_to_yolo(xml_path, out_dir, classes): tree ET.parse(xml_path) root tree.getroot() size root.find(size) width int(size.find(width).text) height int(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 / width y_center (y1 y2) / 2 / height box_w (x2 - x1) / width box_h (y2 - y1) / height lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) out_txt Path(out_dir) / (Path(xml_path).stem .txt) out_txt.write_text(\n.join(lines)) # 用法遍历 annotations 目录把结果写到 labels/train代码逻辑是按 XML 里的size节点拿到图片宽高把绝对像素坐标归一化到 0 到 1 之间。这里最容易踩的坑有四个第一类别 ID 从 0 开始CLASSES.index(name)得到的就是训练时用的类别编号如果 yaml 里的类别顺序和这里不一致模型会学到错误的对应关系。第二归一化必须用 XML 里的图片原始宽高不能用缩放后的显示尺寸否则框全部偏移。第三某些标注工具允许框超出图片边界导致归一化后坐标大于 1 或小于 0训练时会出现 loss 为 NaN转换时要做一步clip把坐标限制在 [0, 1] 内。第四一张图如果没有可转换的目标不要生成空 TXT 文件YOLOv8 读到空标签会报警告虽然不致命但会干扰判断。转换完成后整理目录结构YOLOv8 的 data yaml 直接引用即可dataset/ images/ train/ val/ labels/ train/ val/ e_bike.yaml5. 训练调参与避坑让 mAP 从生涩到能看5.1 训练脚本参数拆解epochs、imgsz、batch 与预训练权重数据集准备好之后训练本身不复杂但参数设置会影响最终效果和训练时长。先写数据集配置文件e_bike.yamlpath: ./dataset train: images/train val: images/val nc: 1 names: [e-bike]然后用预训练权重做迁移学习from ultralytics import YOLO model YOLO(yolov8n.pt) # 加载 COCO 预训练权重 model.train( datae_bike.yaml, epochs80, imgsz640, batch16, # GTX 1660 Ti 6G 建议 8~16显存溢出就减半 device0, # CPU 训练改 devicecpu但会慢很多 patience15, # 验证集损失 15 轮不下降就早停 lr00.01, # 初始学习率 lrf0.01, # 最终学习率 lr0 * lrf ampTrue, # 混合精度训练省显存 workers4, # 数据加载线程数 )几个参数按实际硬件调整参数作用调参建议epochs训练轮数数据量小于 500 张时80 轮足够imgsz训练分辨率640 是速度和精度平衡点小目标多可试 960batch每批样本数显存溢出就减半不要硬撑patience早停耐心值15 到 20 比较稳防止过拟合amp混合精度6GB 显存建议开启几乎不损失精度batch是显存不够时第一个要动的参数。6GB 显存跑imgsz640, batch16是安全的如果报 CUDA OOM先降 batch再考虑关amp。千万不要为了凑 batch 把imgsz降到 320那样模型学到的是模糊特征部署到真实监控上会漏检。训练日志会实时打印 box_loss、cls_loss、mAP50 等指标即使不看曲线图也能从训练过程中初步判断是否收敛。5.2 从损失曲线到验证集判断训练有没有跑偏训练结束后runs/detect/train目录下会自动生成results.png和results.csv。results.png已经画好了损失曲线和 mAP 曲线但有些人觉得图太小看不清趋势用脚本自己画更直观import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/detect/train/results.csv) df df.rename(columnslambda x: x.strip()) plt.figure(figsize(10, 4)) plt.subplot(1, 2, 1) plt.plot(df[epoch], df[train/box_loss], labeltrain_box_loss) plt.plot(df[epoch], df[val/box_loss], labelval_box_loss) plt.xlabel(epoch) plt.ylabel(loss) plt.legend() plt.subplot(1, 2, 2) plt.plot(df[epoch], df[metrics/mAP50(B)], labelmAP50) plt.xlabel(epoch) plt.ylabel(mAP50) plt.legend() plt.savefig(train_curve.png)看图时抓住三个判断点第一训练集和验证集的 box_loss 是否都在下降如果训练集下降但验证集开始上升说明过拟合了早停参数会在 15 轮后自动停止不用手动干预。第二mAP50 的趋势是否还在上升如果在最后几轮还在明显上升可以增加 epochs 继续训练。第三训练过程中如果 loss 出现大幅抖动通常是学习率过高或标注数据有误需要停下来检查标签文件。搞清楚这些细节之后你的项目验收时就能准确回答「为什么不在 50 轮就停止」这类问题这比拿着模型傻跑 300 轮要有说服力得多。5.3 避坑记录五条血泪经验与排查步骤训练阶段是整个项目最玄学的部分问题往往不是模型结构而是数据和环境。整理几条我实际踩过的坑现象 1CUDA OOM训练到一半直接中断。原因batch 太大或 amp 被关闭6GB 显存撑不住 640 分辨率。解决batch 减半开启ampTrue如果还不行把workers降为 2减少数据加载时的显存峰值。现象 2训练 loss 为 NaN。原因标签文件里坐标越界或类别 ID 大于nc。解决写脚本扫描所有 TXT检查每个cls_id nc、坐标值在 [0, 1] 内越界的数据重新标注或删掉。现象 3train loss 正常下降但 val loss 越来越高。原因训练集和验证集分布不一致比如验证集里夜间样本占比过高或者数据量太少模型记住了训练集。解决重新划分数据集保证 train/val 的时段和姿态分布一致增加数据增强。现象 4训练正常但推理检测不到视频里的小目标。原因推理imgsz用的 640目标本身只有 30 像素宽特征太小。解决推理时把imgsz提到 960检测率会明显提升代价是单帧耗时增加实时性要求高的场景需要权衡。现象 5训练中断了不想从头再来。原因断电、显存被其他程序占用等意外。解决训练过程中会自动保存last.pt和best.pt用model YOLO(runs/detect/train/weights/last.pt)加载后在train()中加resumeTrue继续训练不用从头开始。6. 可视化界面与部署验收别让模型死在 .py 里6.1 PyQt 界面核心循环图像、视频与实时摄像头模型训练好以后要让它变成「能演示的系统」可视化界面是必选项。用 PyQt 写检测界面时核心是把模型推理放进独立线程避免阻塞界面刷新from PyQt5.QtCore import pyqtSignal, QThread from PyQt5.QtGui import QImage class DetectThread(QThread): frame_ready pyqtSignal(QImage) def __init__(self): super().__init__() self.model YOLO(best.pt) self.running True def run(self): cap cv2.VideoCapture(0) # 0 为摄像头也可以是视频文件路径 while self.running: ok, frame cap.read() if not ok: break results self.model.predict(frame, conf0.4, imgsz640, verboseFalse) # 在 frame 上画检测框、显示告警状态 self.frame_ready.emit(QImage(frame.data, frame.shape[1], frame.shape[0], QImage.Format_RGB888))QThread负责循环读帧和推理通过frame_ready信号把结果帧传回主线程更新界面。注意conf参数在界面演示阶段可以调低到 0.3提高召回率避免演示时漏检太尴尬真实部署时再调回 0.4 以上减少误报。6.2 部署三步走与验收指标别急着上 RK3588部署路径我建议按三步走先在训练用的电脑上跑通「摄像头 界面」的完整链路这是第一关然后把模型导出为 ONNX用 onnxruntime 替代 ultralytics 做推理单帧速度会明显提升最后才考虑 RK3588、Jetson Orin 这类边缘设备移植时重点重新测conf阈值边缘设备的算力差异会改变最佳置信度设置。不要一上来就在嵌入式设备上折腾环境问题会淹没模型问题。验收时用一张表量化项目是否合格这是答辩和方案汇报里最有说服力的部分指标合格线测试方式单帧推理耗时本机 ≤ 30ms统计 1000 帧平均耗时误报次数每天 ≤ 3 次用无车录像加速回放漏报次数真实推车基本不漏分别测白天、夜间、遮挡场景连续运行稳定性8 小时不崩溃长时间运行记录日志这三个指标里误报和漏报是跷跷板conf调高漏报变多conf调低误报变多。我现在的习惯是先拿一段真实录像反复调conf直到漏报为零、误报可接受再固定参数跑一晚上验证而不是训练完就直接接摄像头。把这一步做扎实项目交付才有底气和说服力希望帮到你。本文还有配套的精品资源点击获取