简介面向电梯监控中电动车与自行车识别需求该项目以深度学习与计算机视觉为核心提供从数据集准备、模型构建到训练评估、部署应用的完整毕业设计参考。针对非机动车违规进入电梯的安全隐患项目围绕卷积神经网络等模型实现监控画面自动检测并讨论了光照变化、遮挡等实际场景下的鲁棒性优化适合人工智能、计算机视觉方向的学生作为课题模板或课设参考。资源包共134个文件约16.96MB主要包含34个Python脚本、34个YAML配置文件、数十张JPEG与PNG训练图片以及Jupyter教程、容器化部署文件、Shell脚本、CSV结果和训练日志覆盖环境配置、模型训练与结果记录多个环节目录结构清晰。目前已有158人学习。借助附带的教程与源码读者可快速掌握电梯监控目标检测的工程实现思路并根据自身数据调整配置重新训练获得从算法到落地的完整经验。1. 电梯里的两轮车识别一场被低估的“赛博判官”硬仗小区物业和城市治理这两年都在密集上电动车进电梯的识别系统但真正跑过现场的人都知道最头疼的不是“识别电动车”而是“分清电动车和自行车”。电梯监控视角极其刁钻——俯视、近景、强反光、人车重叠同一个镜头里一辆雅迪和一辆捷安特在2D画面上的差异可能就只有一个踏板的有无。这个项目标题里点出的“电动车以及自行车”恰恰是整个识别任务里最难啃的一块不能只做“有没有车”的二分类得在极小目标、强遮挡、畸变严重的画面里给出可靠判断。这篇笔记不聊概念直接按我自己的落地路径走从数据怎么标、模型怎么选到训练参数怎么设、自行车和电动车怎么用后处理逻辑做区分最后收在部署端的置信度策略和踩坑记录上。做过三四个类似项目之后我的结论是这东西值得做但千万别一上来就套通用目标检测模型得先把场景捋清楚。2. 数据侧决定天花板采集、标注与电梯视角的三个独特难题2.1 电梯视角为什么让通用检测模型“翻车”通用目标检测数据集里车辆基本都是水平视角、目标占比大、遮挡少而电梯监控是自上而下的俯仰角镜头普遍装在轿厢顶部对角位置。这带来三个具体问题第一目标尺度剧烈变化。人站在轿厢门口时车身在画面里可能占到30%以上人推车往里走车辆迅速贴近镜头底部目标被截断且畸变严重。第二反光和暗光交替出现。不锈钢轿厢壁的镜面反光会让车身亮成一片白夜间楼道LED灯又会让整个画面偏暗偏黄。第三遮挡是常态而非例外。车身经常被人腿、购物袋、其他乘客挡住大半只露出车把和车轮。这些特性决定了第一件事必须做数据得自己采自己标不能指望公开数据集。通用模型在COCO上mAP再高拉到电梯这个极端视角下精度掉一半是正常的。2.2 接地气的数据采集方案摄像头怎么放、视频怎么截帧常见做法是在轿厢对角顶部装一个广角摄像头我一般会固定机位之后录三天以上的原始视频覆盖早中晚、晴雨天、不同楼层的光线变化。采集时只要保持真实业务场景就好不要刻意摆拍摆拍数据会让模型学到的都是“完美的正面车”真实环境里一推车进来就废掉。截帧别用固定间隔得做运动检测。电梯门开合的瞬间画面变化最剧烈车辆出入都在这个窗口期固定间隔截帧会漏掉大部分关键样本。我用的是OpenCV的帧差法import cv2 import numpy as np cap cv2.VideoCapture(elevator_raw.mp4) ret, prev_frame cap.read() prev_gray cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY) frame_id 0 save_id 0 motion_thresh 25 # 像素差阈值 while True: ret, frame cap.read() if not ret: break frame_id 1 gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) diff cv2.absdiff(prev_gray, gray) score np.mean(diff) # 整帧平均差分 if score motion_thresh and frame_id % 3 0: # 每3帧保存一帧避免冗余 cv2.imwrite(fcandidates/{save_id:06d}.jpg, frame) save_id 1 prev_gray gray cap.release() print(fprocessed {frame_id} frames, saved {save_id} frames)逻辑说明absdiff计算相邻帧像素差mean大于阈值说明画面在动此时截帧。加上frame_id % 3 0的抽帧限制避免连续保存几乎相同的帧。参数说明motion_thresh 25是经验值光线稳定时可以用 15~20夜间自动曝光导致整帧亮度波动大时这个值需要上浮到 30 以上否则纯背景闪烁就会触发大量无意义的保存。2.3 标注细节边界框怎么打类别怎么定标注工具用 LabelImg 或 X-AnyLabeling 都行我推荐后者带半自动预标注电梯这种重复场景能省不少时间。类别定义是第一个坑很多人把“电动车”“自行车”直接当两个独立类但镜头里大量出现的是“人推着车走”的状态——人车重叠车身只露出一半——如果只标完整车身模型学到的特征会非常偏。我一般定义三个类e_bike完整可辨识的电动车、bike完整可辨识的自行车、person_vehicle人与车严重重叠、无法区分车型的样本。前两类用于训练识别第三类单独处理要么在训练时当作ignore区域不参与损失计算要么单独训练一个“是否有人推车”的二分类头。这比强行标成电动车或自行车要诚实得多模型也不会因为标注矛盾而学歪。标注时的边界框规则也值得写清楚必须框住车把到后轮之间的完整车身前轮常因广角畸变被拉得特别大但不要为了“完全框住畸变”而把框扩得过大过大的框会把无关墙面和反光带入特征计算。车身被严重截断时比如只有半截车把露出来这个框的高度不要小于画面高度的 8%小于这个比例的检测目标后期很难在低算力设备上稳定检出。3. 模型选型与训练策略为什么 YOLOv8 在这个场景够用但要做三处改动3.1 为什么不用更重的模型算力上限与实时性权衡电梯识别盒子常见的算力水平是海思 Hi3516 系列或瑞芯微 RK3588跑不了太大的模型。我实测过YOLOv8n 在 RK3588 上用 RKNN 量化后能做到 30ms 以内一帧而 YOLOv8s 直接翻到 60ms 以上如果还要同时处理电梯门开关状态判断和语音播报CPU 会被拖垮。所以第一原则是能用 n 尺寸解决的绝不上 s。yolo detect train datadataset.yaml modelyolov8n.pt epochs120 imgsz640 batch16 device0逻辑说明epochs120是保守估计电梯场景相对固定80 个 epoch 左右基本收敛多出来的 40 个 epoch 是给夜间低照度样本补迭代的余地。imgsz640是精度与速度的折中再往上到 960 对小目标框有帮助但推理延迟会增加 40% 上下低端盒子可能扛不住。参数说明batch16取决于显存如果你的显卡只有 8GB调到 8 就行。另外这个命令默认加载了 COCO 预训练权重yolov8n.pt不要从零训练电梯场景虽然有特殊性但底层特征车轮纹理、金属反光、人的轮廓仍然能复用 COCO 学到的通用信息从预训练权重起步能少训练至少一半的时间。3.2 三个必须改的地方anchor、标签平滑和 mosaic 策略第一处是 anchor 配置。电梯视角的车辆尺度分布非常集中车身宽度通常在画面宽度的 20% 到 50%高度在 15% 到 60% 之间浮动而且没有特别大的“满屏车”场景。YOLOv8 的 anchor-free 机制已经对尺度变化比较鲁棒但训练时把imgsz从默认 640 临时改成 320 跑一个 autoanchor 流程再改回来训练可以让模型更贴合这个尺度分布。做法是在训练前先跑一次from ultralytics import YOLO model YOLO(yolov8n.pt) # 自动重新计算anchor大小适配项目中真实标注框的尺度分布 model.train(datadataset.yaml, epochs0, imgsz320)逻辑说明epochs0不会真实训练但 YOLO 校验环节会重新聚类 anchor。运行后会打印新的 anchor 尺寸如果和默认值差异在 15% 以内可以忽略差异超过 15%后续正式训练时模型收敛会更快。参数说明imgsz320时聚类出来的 anchor 偏小需注意这只是为了做校验不会真正影响训练权重。跑完这个命令正式训练时还是要用回imgsz640。第二处是标签平滑。电梯场景的标注噪声比较大尤其是人车重叠的样本“这是自行车还是电动车”连人眼都不一定瞬间判断准标签平滑能防止模型对某些硬样本过分自信。在 YOLOv8 中可以直接用label_smoothing参数控制yolo detect train datadataset.yaml modelyolov8n.pt epochs120 imgsz640 label_smoothing0.1参数说明label_smoothing0.1是常用值太大会让模型的预测置信度整体偏低后期做阈值过滤时会出现漏报。第三处是 mosaic 策略。YOLOv8 默认前 10 个 epoch 开启 mosaic 增强但电梯场景里车辆常被裁剪切断mosaic 进一步加剧了“残缺感”导致模型学到“车就是碎片”的错误先验。新版本 Ultralytics 支持在训练配置里直接关掉或缩短 mosaic 周期做法是在 yaml 配置中将mosaic的关闭时间提前到 epoch 5# augment.yaml 片段 mosaic: 0.5 close_mosaic: 5逻辑说明mosaic: 0.5表示一半的训练样本做 mosaicclose_mosaic: 5表示在第 5 个 epoch 后关闭 mosaic 增强保留更多原图特征。电梯这种场景不要开满整个训练流程后半程需要让模型专心学真实的遮挡结构和尺度关系。3.3 训练监控看哪几个指标而不是光盯着 mAP训练过程中我一般不用 mAP 做主要判断依据电梯场景的 mAP 在 0.9 以上可能很漂亮但实际部署时照样误报。我更关注两个东西一是val/box_loss和val/cls_loss的收敛曲线是否同步下降如果cls_loss已经压得很低但box_loss还在高位抖动说明模型对“位置”的认知还没到位直接表现是检测框飘来飘去二是每个类别的召回率YOLOv8 训练日志里可以按类别看bike类召回率如果比e_bike明显低通常是自行车样本太少回去补数据不要调参硬扛。4. 电动车与自行车的区分比模型更重要的后处理逻辑4.1 形态学差异为什么纯视觉分类容易出错电动车和自行车在 2D 画面上的核心差异在于电动车车身厚重、踏板位置有电池仓自行车车身纤细、有清晰的前三角车架。但电梯俯视角下这些特征全都会被压缩——车身长度、车轮大小、车架形状都变形甚至从正上方看电动车和自行车的俯视轮廓几乎都是“一横杠加两个圆”。此时单靠检测模型直接输出类别误检率很难压到 5% 以下。业内更稳的做法是检测模型只负责输出“两轮车”的框再用一个后处理模块结合额外信号判断具体类型。这个信号可以是车轮宽度与车身长度的比例、踏板位置是否有凸起物或者更直接地——车身侧面的高度信息。我的方案比较务实在电梯轿厢顶部装一个低成本的单点激光测距模块朝斜下方扫射当检测框触达时读取测距值。电动车的高度含后视镜/挡风板通常在 1.1 米以上自行车在 0.9 米左右两个信号融合做一个阈值判断。这个方案比单纯做端到端分类稳定得多而且成本低加一个模块也就几十块钱。4.2 后处理代码检测框与测距信号的融合逻辑import json def classify_vehicle(detect_boxes, laser_dist): results [] for box in detect_boxes: cls_id box[class_id] # 0: two_wheeler conf box[confidence] width box[x2] - box[x0] # 检测框宽度 height box[y2] - box[y0] # 检测框高度 area_ratio (width * height) / (frame_w * frame_h) # 置信度门槛低于0.35直接丢弃 if conf 0.35: continue # 用小目标过滤面积占比过小不可信 if area_ratio 0.03: continue # 融合测距信号dist单位cm if laser_dist is not None and laser_dist 110: vtype e_bike prob min(0.95, 0.7 (110 - laser_dist) / 200) else: # 无测距信号时退回纯视觉判断 # aspect_ratio: 宽度/高度电动车普遍更宽 aspect width / max(height, 1) vtype e_bike if aspect 1.4 else bike prob 0.6 if aspect 1.4 else 0.55 results.append({ type: vtype, confidence: prob, box: [box[x0], box[y0], box[x2], box[y2]] }) return results逻辑说明这个函数先做两轮过滤——置信度低于 0.35 的框丢弃避免夜间误检干扰后续判断面积占比低于 3% 的框丢弃因为极小目标在电梯广角里很可能是远处楼道里的模糊物体不该触发告警。随后如果能拿到激光测距值且小于 110cm直接判定为电动车置信度按距离加权——越矮越接近自行车阈值置信度越低。测距不可用时退回长宽比判断。参数说明laser_dist 110这个阈值要根据你实际安装的测距模块位置去标定我在自己的项目里标定出来的分离点一般在 105 到 115cm 之间。aspect 1.4是电动车与自行车在俯视角下的经验宽度比但这个值的鲁棒性一般所以只作为无测距模块时的兜底方案。4.3 误判率能压到多少实测边界的诚实预期诚实说纯视觉方案无测距融合的电动车/自行车区分准确率大约在 90% 到 93%听起来不错但你要知道 7% 的误判在小区场景里意味着什么——每天上百次进出其中七八次“自行车被误报成电动车”物业就要收到七八次投诉。加了测距融合之后误判率能压到 1% 以内这是几十块钱换来的巨大体验提升。如果你的项目不打算加额外传感器那就在后处理里加时间维度的判断连续 3 帧以上都判定为同一类型才触发告警靠时序滤波把偶发误判吃掉。5. 训练与部署的避坑指南三个让项目延期两周的血泪经验5.1 夜间低照度下检测框抖动得像“筛子”现象白天跑得很好一到夜间走廊灯熄灭后检测框在车辆周围来回跳动一帧偏左一帧偏右后处理里做面积过滤时目标一会达标一会不达标导致告警反复触发。原因低照度下画面噪声增加模型的边界框回归起点不稳定加上电梯内自动曝光调整会让目标边缘的梯度信息不稳定同样的输入每一帧提取到的特征都有细微偏移。解决先确认摄像头本身开启了宽动态WDR模式这个不开启的话后面都白搭。然后在推理侧加“先检测再跟踪”策略——最简单的做法是用 ByteTrack 或 DeepSORT但更省事的是自己做一个轻量的帧间 IoU 关联上一帧的框和当前帧框的 IoU 大于 0.6 就认为是同一个目标取两个框的加权平均作为输出位置。这样能把抖动幅度压掉 70% 以上。5.2 反光把不锈钢轿厢壁识别成“大面积白色目标”现象轿厢壁的镜面反光在阳光直射时会形成一道亮带模型偶尔会在这条亮带上给出一个高置信度的电动车框。原因反光区域里往往包含车轮的倒影或金属质感的纹理与车辆表面特征接近。模型没有“这里不可能出现车”的空间先验。解决最直接的是在推理前加一个“区域屏蔽”操作——电梯轿厢的出入口区域是重点检测区轿厢两侧墙壁区域直接置黑或忽略。具体做法是在检测前把图像左右两侧各裁掉 20%根据你的摄像头安装位置而定既减少了反光区域的干扰还降低了 20% 的推理耗时。这一招简单且有效比加样本硬扛靠谱得多。5.3 模型在 RK3588 上量化后精度骤降自行车直接漏检现象使用 RKNN-Toolkit 做 INT8 量化后电动车依然能检出但自行车大量漏检召回率从 90% 掉到 60% 出头。原因自行车在画面中的目标小、纹理稀疏量化后特征图的细节信息损失比电动车更大加上量化校准集里自行车的占比本来就不够。解决校准集不能随便从训练集里抽几百张图要专门挑包含小目标、低照度、远距离自行车的样本数量控制在 300 张左右。另外在量化配置里开启scale的逐通道量化而不是逐层量化虽然推理速度会慢一点点但小目标的精度会显著回升from rknn.api import RKNN rknn RKNN() # do_quantizationTrue且量化策略为逐通道 rknn.config(batch_size1, target_platformrk3588, quantized_dtypeasymmetric_quantized-8, quantized_algorithmnormal, qnt_strategychannel)参数说明quantized_dtype用非对称量化可以更充分地利用 8bit 的动态范围qnt_strategychannel是逐通道量化。如果烧录后速度不达标再退回逐层量化并搭配前面提到的区域裁剪而不是直接牺牲精度。6. 部署端的最后一个关键动作置信度阈值该设多少以及按场景动态调整的策略模型训完部署上墙之后最常被忽视的就是置信度阈值这个“最后一道闸门”。很多人直接沿用训练时的conf0.25但训练日志里的置信度分布和真实电梯场景差异很大——真实场景里有大量训练集没见过的“类车物体”轮椅、婴儿车、推拉的货架它们的特征和两轮车高度相似模型给它们的置信度往往落在 0.3 到 0.5 之间。我的做法是分时段设阈值白天7:00-22:00conf0.45夜间22:00-7:00conf0.55因为在夜间出现的“类车物体”更少可以把阈值拉高来压误报。这一条需要根据你现场的误报率再微调——如果白天误报还是多继续往上加到 0.5如果出现了漏检往下回落 0.05不要一次调整超过这个幅度。另一个值得做的技巧是检测框的“连续触发确认”机制在停车场和电梯场景都通用。不要单帧检测到就立刻告警连续 3 帧约 0.6 秒类型一致且置信度都超过阈值才触发告警语音播报。这个逻辑能直接吃掉前面提到的车辆进出时一帧扭曲变形导致的瞬时误判同时不牺牲真实灵敏度——正常推车进电梯的动作至少持续一两秒不会被这个机制误伤。最后说一句我的习惯每次改完阈值或后处理逻辑我都会拉一周的日志把误报和漏报分别截图归档下一轮调参直接对着截图看而不是只看数字指标。这是我从一次上线后误报率翻倍、查了半天才发现是改模型尺寸时顺手动了预处理代码的翻车经历里学到的教训。调参记录写清楚比模型本身更能救你的命希望帮到你。本文还有配套的精品资源点击获取
