恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
YOLOv5电动车违停识别实战:从VOC数据转换到边缘部署全流程
首页
资讯中心
/
YOLOv5电动车违停识别实战:从VOC数据转换到边缘部署全流程
YOLOv5电动车违停识别实战:从VOC数据转换到边缘部署全流程
发布时间:2026/8/31 13:28:53
简介本资源是面向智能交通与城市管理场景的YOLOv5目标检测训练数据集专为非机动车违规停放识别任务设计适用于计算机视觉初学者及算法工程师开展模型训练与部署实践。压缩包内含853张爱玛品牌电动车实拍图像JPG及对应PASCAL VOC格式标注文件XML共1694个文件总容量89.18MB标注规范、图像清晰、类别明确可直接用于YOLOv5的训练、验证与测试流程。已有1311人学习下载反映出该细分领域数据资源的高需求度。用户获取后即可构建完整的电动车检测 pipeline涵盖数据预处理脚本适配、labelimg标注复核、train/val划分逻辑、YOLOv5模型配置修改及mAP评估基准尤其适配城市非机动车违停监管系统中的关键识别环节。 做了好几年机器视觉相关的落地项目智慧城市和非机动车管理这个方向接触得尤其多。电动车在楼道口、消防通道、盲道上随手一停既影响通行又埋隐患光靠人工巡查根本跑不过来。所以很多项目方都在问能不能用摄像头自动识别违规停放的电动车答案是可以而且技术方案已经很成熟。用YOLOv5做机器视觉识别配合一套已标注的数据集比如这里用的E_bicycle10_images_xmls训练一个电动车检测模型再叠加业务判定逻辑就能实现非机动车违规停放的自动识别。这个项目看起来不复杂但真正落地时坑不少数据集格式怎么适配、训练超参数怎么调、模型怎么部署到边缘设备、违停判定逻辑怎么设计每一环都能写一篇长文。这篇文章就把我实际做过的方案、用过的脚本、调过的参数、踩过的坑全部摊开讲。适合正在做智慧城市、智慧社区、安防监控项目或者准备用YOLOv5做目标检测落地的朋友参考尤其是那些项目刚起步、还在纠结数据格式和训练配置的同学。1. 项目整体设计不止是训练一个模型更是打通一条检测流程1.1 需求场景到底要解决什么问题非机动车乱停放是城市治理里的高频难题尤其是电动自行车。它们体积小、数量大、停取方便但管理难度很高。楼道内违规停放、消防通道被占、盲道被堵这些场景仅仅靠人工巡检效率很低而且做不到全天候覆盖。机器视觉识别的价值就在这里摄像头24小时在线能同时盯多个点位检测到异常直接触发告警还能留存图片和视频证据。不过我在做这个项目时发现一个很容易混淆的点目标检测只是让计算机看到电动车它并不能直接回答是否违规停放这个问题。检测模型输出的是一堆边界框和类别标签比如电动车而违规是一个业务判定需要你额外叠加规则。所以从架构上我把整套方案拆成了三个独立的子模块图像采集与预处理模块基于YOLOv5的电动车目标检测模型违停判定与告警业务逻辑模块三者各司其职前两个是通用能力第三个才是业务核心。这样的好处是如果后面想把检测模型换成更新的YOLOv8或者想把判定逻辑从禁停区域改成超时停留改动范围都很小不会牵一发动全身。1.2 为什么是YOLOv5而不是YOLOv8、Faster R-CNN或SSD选题型这块我纠结过一阵。当时YOLOv8已经在社区火起来了Faster R-CNN和SSD也是经典方案但最终我还是选了YOLOv5核心原因有三点生态最成熟踩坑成本最低。YOLOv5从2020年开源到现在社区积累了大量文档和实战经验。你在训练、部署过程中遇到的绝大多数问题搜索一下都能找到解决方案。新版模型虽然性能更好但很多部署文档和工具链还是v5这套最齐全。部署链路完整能跑到边缘设备。这个项目最终要部署到RK3568、RV1106这类带NPU的边缘设备上。YOLOv5支持导出ONNX、TensorRT、RKNN等多种格式模型转换和量化调优的案例非常多这是它在边缘侧落地的关键优势。精度和速度的平衡刚刚好。非机动车检测不追求极致精度用yolov5s或yolov5m就足够。在摄像头实时画面里跑帧率完全够用没必要为了一两个点的mAP牺牲部署成本和推理速度。那为什么不用Faster R-CNN或SSDFaster R-CNN精度不差但推理速度在边缘端是硬伤两阶段检测器做实时监控太吃力SSD则是精度偏低在电动车这种小目标密集的场景下容易漏检。所以综合下来YOLOv5是当前场景下最省心的选择。1.3 整体技术链路设计从原始图像到最终告警完整流程是这样的摄像头画面 / 上传图片 → 图像预处理 → YOLOv5模型推理得到检测框 → 结合ROI区域和停留时间做违停判定 → 结果叠加 → 触发告警或保存记录在目标检测这一层核心就是模型的输入输出。输入是一张普通的RGB图像输出是每个检测目标的类别、置信度和边界框坐标。后面要做的违停判定就是在这些检测框的基础上叠加业务规则。这里我建议从一开始就预留好接口把检测模块和判定模块解耦后面接不同摄像头、不同业务场景都方便。2. 数据集E_bicycle10_images_xmls格式转换与质量清洗2.1 先摸清images_xmls到底是什么格式拿到E_bicycle10_images_xmls这个数据集第一件事不是急着训练而是先把数据结构和质量彻底搞清楚。数据集名字已经说得很直白images是图片xmls是对应的标注文件两者组合在一起就是Pascal VOC格式这是目标检测领域最常见的标注格式之一。Pascal VOC格式里每张图片对应一个同名的XML文件XML里记录了图片尺寸、通道数以及若干个object节点。每个object节点里面有类别名称name和边界框bndboxbndbox包含xmin、ymin、xmax、ymax四个坐标值。下面就是一个典型的实例annotation folderimages/folder filename000001.jpg/filename size width1280/width height720/height depth3/depth /size object namee_bicycle/name bndbox xmin320/xmin ymin180/ymin xmax610/xmax ymax465/ymax /bndbox /object /annotation这里有个细节要提醒不同数据集的类别名可能不一样。有的叫e_bicycle有的叫electric_bicycle有的直接叫ebike。做格式转换之前先确认类别名列表和你业务上需要的类别是否一致。如果发现类别名混乱要么批量修改标注要么在转换脚本里做映射否则训练出来的模型类别会错乱。2.2 VOC转YOLO格式的脚本一次跑通YOLOv5训练时用的不是XML标注而是YOLO格式的txt文件。每个txt文件对应一张图片每行表示一个目标格式是类别id 中心点x 中心点y 宽度w 高度h所有坐标都是相对于图片宽高的归一化值取值范围0到1之间。所以第一步就是把VOC格式转成YOLO格式。下面这个Python脚本我一直在用直接改一下路径和类别列表就能跑import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, out_txt_path, class_names): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size).find(width).text) img_h int(root.find(size).find(height).text) lines [] for obj in root.findall(object): name obj.find(name).text.strip() if name not in class_names: continue cls_id class_names.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_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(out_txt_path, w) as f: f.write(\n.join(lines)) if __name__ __main__: class_names [e_bicycle] # 改成你数据集的类别 xml_dir E_bicycle10_images_xmls/xmls out_dir E_bicycle10_images_xmls/labels os.makedirs(out_dir, exist_okTrue) for xml_name in os.listdir(xml_dir): if not xml_name.endswith(.xml): continue xml_path os.path.join(xml_dir, xml_name) out_txt os.path.join(out_dir, xml_name.replace(.xml, .txt)) voc_to_yolo(xml_path, out_txt, class_names)这个脚本很基础但我在实际项目中都会在它基础上做扩展。比如转换完后统计一下每个类别的数量、标注框的尺寸分布甚至把标注框画回原图人工检查一遍。这些前置工作看起来琐碎却能帮你省掉后面好几个小时的排错时间。2.3 数据划分与增强别让一个坑毁掉整个训练数据划分我一般按8:1:1或者9:0.5:0.5来切train、val、test。有两点特别重要一是图片不能有重叠二是如果数据来自视频连续帧一定要按场景分组再划分否则同一辆车既出现在训练集又出现在验证集指标会虚高部署到真实场景就打回原形。数据量方面如果E_bicycle10_images_xmls总共只有几百张图片直接训练yolov5s很容易过拟合。我的建议是使用预训练权重yolov5s.pt做迁移学习不要从零训练开启YOLOv5内置的Mosaic、MixUp、HSV颜色增强这能显著扩充样本多样性如果效果还是不够就去补充更多实际场景的图片最好是从准备部署的摄像头里抽帧还有一个容易忽略的点标注框的边界。转换脚本里如果发现某个标注框坐标异常比如xmin xmax、坐标超出图片边界一定要单独筛选出来处理否则训练时loss会莫名其妙变成nan。3. YOLOv5环境搭建与训练配置3.1 安装与数据集目录组织YOLOv5的安装没什么玄学Clone仓库、装依赖、下载预训练权重三步走git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt需要注意Python和PyTorch的版本匹配官方仓库的README里写得很清楚。我用的是Python 3.9 PyTorch 1.12的组合跑得很稳。有CUDA环境的记得装对应版本的torch纯CPU训练实在太慢了不推荐。数据集的目录结构要按YOLOv5的要求来组织图片和标签分开放dataset/ images/ train/ val/ labels/ train/ val/同时还需要一个yaml配置文件声明数据集路径和类别信息。这里是我项目的data.yamltrain: dataset/images/train val: dataset/images/val nc: 1 names: [e_bicycle]nc是类别数量names是类别名称列表顺序必须和标签文件里的类别id对应。如果顺序搞反了训练出来的模型预测结果就全部错位。3.2 训练超参数一组能直接上手的配置初次训练直接用默认超参数基本能跑通但想要效果更好下面几个参数值得认真调img-size默认640。如果监控画面里电动车占的面积很小可以试试1280小目标检测效果会明显提升但显存占用和推理耗时都会增加需要平衡。batch-size取决于显存大小一般设16或32。显存不够就降batch不要硬扛。epochs100轮起步300轮在场景相对固定的数据集上会更稳定。重点看loss曲线和验证集指标不要盲目加轮数。lr0和lrf初始学习率默认0.01最终学习率衰减到0.01倍。如果loss在训练前期震荡得厉害可以降到0.005试试。我在这个项目里实际用的配置是yolov5s预训练权重、输入尺寸640、batch-size 16、epochs 150、优化器用SGD初始学习率0.01。单张常规显卡上训练了大约3个小时最终模型在验证集上mAP0.5超过了0.85对电动车违停检测场景来说已经够用。训练命令长这样python train.py --data data.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 150 --name e_bicycle_train如果你用的是E_bicycle10_images_xmls这种几百张图的小数据集更建议在训练时加上--cache属性把图片提前缓存到内存里能省不少磁盘IO时间。3.3 训练过程监控别等训完才发现问题训练过程中我最常盯三个东西loss曲线、mAP、PR曲线。YOLOv5在runs/train目录下会自动生成results.png包含训练和验证过程的各项指标曲线。重点关注两条mAP0.5和mAP0.5:0.95。前者判断检测到了没有后者判断框得准不准。mAP0.5到0.8以上一般就能用mAP0.5:0.95则能反映边界框的定位精度。如果发现val loss和train loss差距越来越大说明过拟合了。处理方法就三条增强数据、加大权重衰减、减少训练轮数。反过来如果两个loss都在高位下不去那就要考虑学习率是不是太大了或者标注数据本身质量不行。另外还有一个实操技巧训练到一半如果中断了YOLOv5会自动保存last.pt可以用--resume参数接着训不用从头再来。4. 模型推理与违停判定逻辑4.1 用训练好的权重做推理训练完之后用自带的detect.py就能快速验证效果python detect.py --weights runs/train/e_bicycle_train/weights/best.pt --source test.jpg --conf 0.5加上--save-txt可以导出检测结果txt加上--project可以指定输出目录。但我在实际项目里很少直接用detect.py更多是写一个Python推理脚本方便把检测结果接入到自己的业务系统里。一个最简单可用的版本如下import torch import cv2 # 加载模型 model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/e_bicycle_train/weights/best.pt, force_reloadTrue) model.conf 0.5 model.iou 0.45 # 推理 img cv2.imread(test.jpg) img_rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB) results model(img_rgb) # 解析结果 boxes results.xyxy[0].cpu().numpy() for box in boxes: x1, y1, x2, y2, conf, cls_id box print(f类别: {int(cls_id)}, 置信度: {conf:.2f}, 坐标: ({x1:.0f}, {y1:.0f}, {x2:.0f}, {y2:.0f}))这个脚本虽然短但已经覆盖了加载模型、推理、解析结果三个核心步骤。实际项目中你可以在解析结果之后接上自己的业务逻辑比如判断检测框是否落在某个禁停区域内。4.2 从检测结果到违规停放判定这是整个项目里业务逻辑最核心的部分也是很多人容易忽略的地方。检测出电动车之后怎么判断它违规了我常用的判定方法有三种ROI区域判定提前在画面里标出禁停区域用多边形坐标表示。检测到电动车后取目标框中心点坐标然后用openCV的pointPolygonTest判断这个点是否落在多边形内部。如果是就判定为违规。停留时间判定电动车可能只是路过不能一检测到就告警。需要结合多帧检测和跟踪算法比如DeepSORT记录同一个目标在画面中的停留时间。如果超过设定阈值比如2分钟才判定为违停。两者结合先判断是否落在禁停区域再判断停留时长两个条件都满足才触发告警。这种组合在实际项目中误报率最低。用OpenCV做点在多边形内的判断代码非常简单import cv2 import numpy as np def point_in_polygon(point, polygon): # point: (x, y), polygon: [(x1,y1), (x2,y2), ...] return cv2.pointPolygonTest(np.array(polygon, dtypenp.float32), point, False) 0为什么把判定逻辑单独拎出来讲因为我见过太多人训练完模型就直接上线把检测到电动车直接等价于违规停放结果误报率暴涨根本没法用。检测是手段业务判定才是最终要交付的东西两者之间的关系一定要理清楚。4.3 部署到边缘设备的补充参考现在很多非机动车违停识别项目要求部署到边缘设备比如RV1106、RK3568这类带NPU的板卡上。YOLOv5在边缘侧部署的链路是先把模型导出为ONNX再用RKNN-Toolkit转换成RKNN格式量化成INT8模型这样在NPU上推理速度可以跑到几十毫秒一帧完全能满足实时监控需求。部署时我踩过的坑主要有三个模型转换前先检查算子兼容性。YOLOv5某些结构在NPU上可能不支持转RKNN时直接报错需要简化解码部分或者升级工具链。INT8量化需要准备校准图片。不要随便挑几张图最好用和实际场景分布接近的一批图来做校准否则量化后的精度损失会很严重。如果精度掉得多可以尝试部分层保留FP16精度混合精度量化往往能在速度和精度之间找到更好的平衡点。边缘部署的具体细节一篇文章讲不完但如果你在这个项目里需要走到这一步提前知道这三个坑能省不少时间。5. 常见问题与排查技巧实录5.1 训练阶段的典型问题现象常见原因处理办法CUDA out of memorybatch过大或分辨率过高调低batch-size降低img-size开启梯度累积loss前几轮就变成nan学习率过大、标注框越界调低lr0检查转换后的txt是否有坐标异常训练集指标很好、验证集很差过拟合增加数据增强、加大权重衰减、减少epochs分类不准电动车认成自行车样本不均衡、标注错误补充对应类别样本重新清洗标注数据遇到loss为nan的情况第一反应不要怀疑模型有问题先检查数据。我之前碰到过一次就是因为某个标注框的xmax比图片宽度还大归一化后坐标超过了1训练直接崩了。转换脚本里加个范围判断就能避免。5.2 检测结果不理想先别急着调模型检测漏检和误检是高频问题。我遇到最典型的就是电动车和普通自行车外形相近模型经常把两者搞混。排查思路分三路第一检查数据集里有没有把自行车样本标成了电动车第二增加电动车外形差异大的样本比如不同颜色、不同坐姿、不同角度的车第三如果摄像头位置固定尽量用和实际场景相近的图片进行微调不要只用公开数据集。误报率高还有一个常见原因我之前已经强调过违停判定逻辑没做好而不是模型本身。把检测到电动车直接当成违规停放误报一定多。在项目里判定逻辑的优先级不亚于模型精度花时间把ROI区域和停留时间规则设计好比花时间刷mAP更值。5.3 部署阶段的排错思路部署到RK3568这类设备时最容易遇到两个问题模型转换失败和量化后精度下降。转换失败基本是算子兼容问题。YOLOv5的解码部分有些自定义算子NPU工具链可能不支持。我的经验是升级RKNN-Toolkit到最新版或者把模型中不支持的层替换成等效的普通卷积、全连接结构再不行就换yolov5s这类更轻量的模型通常能绕开问题。量化后精度下降的话第一步重新选择校准集确保它覆盖实际场景的亮度、角度和车型分布第二步尝试混合精度量化只量化敏感度低的层保留部分层为FP16。这两招用下来大多数精度下降问题都能缓解。最后说点实在的回过头看整个项目YOLOv5在这套方案里的角色其实只占一小半真正决定项目成败的反而是那些看起来不起眼的环节数据格式转换时有没有把质量关、违停判定的业务逻辑设计得是否合理、部署时有没有提前考虑算子兼容性。我个人在实际操作中的体会是非机动车违规停放识别这类项目模型训练本身并不是最大瓶颈数据整理和业务逻辑设计才是。很多项目组花了两周训练模型却花了一个月处理误报问题就出在没把业务规则和技术能力对齐。所以我建议后面再做类似项目的人动手前先把场景问题拆清楚你检测的目标是什么、违规的判定标准是什么、在哪个设备上跑、实时性要求有多高。这些问题想明白了YOLOv5的配置和训练反而是水到渠成的事情。如果你正准备用E_bicycle10_images_xmls这类数据集做非机动车检测建议按照这篇文章的顺序一步步来先做格式转换和数据清洗再配置训练然后叠加违停判定逻辑最后再考虑边缘部署。每一步都踩实了整个项目推进起来会顺畅很多。本文还有配套的精品资源点击获取