ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

YOLOv8_seg实例分割:路边非标准停车位识别与数据集训练全流程

YOLOv8_seg实例分割:路边非标准停车位识别与数据集训练全流程 简介面向智能交通与城市停车管理场景的路边非标准停车位识别方案适用于需要处理复杂道路环境的研究人员与开发者。系统基于改进YOLOv8_seg实例分割模型能针对公交站、免费停车位、垃圾箱、禁停标志、物业入口、侧街、商店及其入口、商店保留停车位、寺庙等多类目标进行检测与分割适配印度等地非标准化路边停车位识别需求。资料包含源码与配套数据集源码覆盖模型训练、验证、推理及交互界面等功能模块数据集提供大量预标注图像可直接用于模型训练与效果评估。压缩包共27个文件以png图片、py脚本、docx文档、txt说明及md文档为主整体大小5.85MB。已有72人学习下载适合作为停车管理、城市规划及智能交通系统相关课题的参考实现。1. 路边非标准停车位识别YOLOv8_seg 实例分割源码与数据集能解决什么路边免费停车位大多没有标准划线公交站旁的空地、寺庙院墙外的斜向区域、商店门口被地锁圈出的保留位这类目标用矩形框检测根本框不明白车和障碍物互相遮挡时一个框里会同时装进两类目标。YOLOv8_seg 实例分割把这些目标切成像素级掩码公交站、垃圾箱、禁停标志、物业入口、侧街、商店及其入口、商店保留停车位、寺庙都能分开表达停车位识别从有没有框变成这块区域能不能停。这份资源把改进版 YOLOv8_seg 源码和九类数据集打包在一起训练命令可以直接复现适合做路侧感知、智慧停车管理或实例分割毕业设计的工程师新手跟第 2、3 章走通全程熟手重点看第 4、5 章的掩码后处理和部署避坑。2. 数据集构成与标注规范九类目标的边界定义与格式转换拿到这个 zip 之后我第一个动作不是解压看模型而是先把 labels 目录里的原始标注翻了一遍。实例分割的数据集质量决定训练下限网络改进只决定上限顺序不能颠倒。这份包的九类目标全是路侧空间线索类与类之间边界容易打架所以先把标注规范对齐再谈训练。整体标注思路和自动驾驶数据集里的路侧感知标注意图是一致的每个目标独立成实例多边形贴外轮廓。2.1 九类目标的场景定义哪些算非标准停车位这九类的共同点是它们都能直接或间接影响路边某块区域能不能停、什么时候能停。我一般会先按下面这张表把每个类的边界在标注时定死不然标注员或者你自己回头补标时会在侧街和 free_parking 之间犹豫很久。类别场景含义多边形标注边界bus_stop公交站台及候车区域站台外轮廓加候车区地面free_parking无划线但实际在用的免费停车位地面可停区域外轮廓trash_bin路侧垃圾桶或垃圾收集点箱体加地面投影范围no_parking_sign禁停、禁止临时停车标志牌牌面多边形property_entrance小区、写字楼车辆出入口门岗到路面的过渡区域side_street与主干道相连的支路入口路口地面区域shop_entrance沿街商店及其入口店门向外延伸的区域shop_reserved_parking商店自营或地锁围挡的保留位围挡内完整区域temple寺庙院墙及入口广场院墙外轮廓及广场地面每一类都要写进标注规范尤其是遮挡时的处理目标被树木或车辆挡住一半多边形按可见边缘收边不脑补外推同一目标被间断遮挡成两段我一般按两个实例标而不是硬连成一个多边形。这样模型学到的是可见部分也能识别而不是把遮挡噪声学进去。禁停标志这类小目标更要留意牌面必须单独成多边形不能把整根杆子圈进去杆子会让类内形状方差变大掩码 IoU 直接掉。2.2 标注格式转换labelme JSON 转 YOLO 分割 txt数据集里原始标注通常是 labelme 的 JSON 格式shapes 字段存的是每个实例的多边形坐标。YOLOv8_seg 训练要的是 txt 文本每行一个实例class_id x1 y1 x2 y2 ...坐标归一化到 0-1。每次拿到这类包第一步就是跑转换脚本把 JSON 批量转成 YOLO 能吃的格式import json import os from glob import glob CLASSES [bus_stop, free_parking, trash_bin, no_parking_sign, property_entrance, side_street, shop_entrance, shop_reserved_parking, temple] def labelme_to_yolo_seg(json_path, out_txt): with open(json_path, r, encodingutf-8) as f: data json.load(f) img_w, img_h data[imageWidth], data[imageHeight] lines [] for shape in data[shapes]: label shape[label] if label not in CLASSES: continue cls_id CLASSES.index(label) pts [] for x, y in shape[points]: # 归一化并截断到 0-1防止多边形越界 nx max(0.0, min(1.0, x / img_w)) ny max(0.0, min(1.0, y / img_h)) pts.append(f{nx:.6f} {ny:.6f}) lines.append(f{cls_id} .join(pts)) with open(out_txt, w, encodingutf-8) as f: f.write(\n.join(lines)) for jf in glob(labels_json/*.json): out os.path.join(labels_txt, os.path.basename(jf).replace(.json, .txt)) labelme_to_yolo_seg(jf, out)几个关键点说明一下。CLASSES 的顺序必须和后面训练 yaml 里的 names 完全一致YOLO 只用数字索引顺序错了整批数据全废这是最容易翻车的地方。归一化要以 JSON 里的 imageWidth/imageHeight 为准不要自己去读原图尺寸有些标注工具这两个字段和原图文件头不一致读错坐标整体偏移。多边形的首尾闭合交给 YOLO 内部处理不需要手动把首点再追加到末尾重复点反而可能在极端缩放时产出零面积多边形。转完先挑两张图做可视化验证不要直接开训。用 PIL 把 txt 里的多边形画回原图肉眼比对轮廓贴合度这一步能拦下八成标注事故。2.3 数据处理样本划分与增强策略YOLOv8_seg 训练自己的数据集时划分和增强直接决定 mAP 上限。先做一件事统计每个类的实例数量确认长尾分布再决定补样本策略。from glob import glob stats {i: 0 for i in range(9)} for txt in glob(labels_txt/*.txt): for line in open(txt, r): cid int(line.split()[0]) stats[cid] 1 print(stats)这份包里寺庙、商店保留停车位样本通常偏少属于可预期的长尾。我的处理方式是对 temple 和 shop_reserved_parking 做复制粘贴增强从标注好的图上抠出实例多边形随机贴到没有同类目标的路面背景上而不是简单做随机旋转——旋转对停车位语义不敏感上下翻转更是直接禁用车位和道路的朝向关系是强先验翻转过后的样本会教坏模型。数据划分有一个关键点按场景划分而不是按文件名随机划分。同一个路口连续拍摄的帧背景高度相似一部分进训练集、一部分进验证集mAP50 会虚高到 0.9 以上换到没见过的路段立刻打回原形。我一般把同一道路场景的图片分到同一集合train:val:test 按 8:1:1。注意同一场景的帧必须进同一数据集合否则验证集等于开卷考试。mosaic 增强保留但最后 10 个 epoch 要关掉让模型在接近真实分布的输入上收敛这个参数就是训练命令里的 close_mosaic10。3. 改进 YOLOv8_seg 的训练流程网络改动点与关键参数数据集处理完接下来要搞清楚改进版到底改在哪。很多人拿到源码包直接跑跑完也不知道改了啥我拆包的习惯是先看 model 配置和 loss 相关代码确认改进点和自己的场景是否匹配再决定要不要沿用。3.1 实例分割与语义分割的区别为什么这里选 YOLOv8_seg先理清一个基础问题也是平时被问得最多的语义分割给每个像素贴类别标签路口的两个公交站、三个垃圾箱在语义分割结果里是连成一片的区域分不清谁是谁实例分割则把每个目标单独建模两个公交站就是两份独立掩码。对停车位识别来说公交站、垃圾箱、禁停标志这些空间线索需要逐个计数、逐个计算和停车区域的遮挡关系实例分割才是对的粒度。这一区分在 YOLO 后续版本里依然成立只要场景需要目标计数而不是区域分类就走实例分割路线。YOLOv8_seg 是单阶段方案分割掩码由原型掩码和实例系数线性组合生成速度和显存开销都比两阶段 Mask R-CNN 小一截路侧摄像头这类边缘设备基本带得动。输出里每个检测框附带一个二进制掩码掩码分辨率由 Segment 头的 npr 参数控制默认 256×256后处理时再上采样到原图。3.2 改进点拆解注意力模块、损失函数与分割头这类改进版资源最常见的改法集中在三处拿到包先看这三个位置确认走的哪条路线。第一处是 backbone 的 C2f 模块很多改进版会替换成带轻量注意力的版本比如在 Bottleneck 残差分支里插入 SimAM 或 CBAM第二处是损失函数把默认的 CIoU 换成 WIoU v3对小目标和遮挡目标更宽容第三处是分割头调大原型掩码分辨率或者加一层上采样。源码包里改动的就是这些文件训练入口不变。以注意力改法为例yaml 里大概长这样# yolov8se-seg.yaml 片段C2f 换成带注意力版本 backbone: - [-1, 1, Conv, [64, 3, 2]] - [-1, 1, C2f_SimAM, [128, True]] - [-1, 1, Conv, [128, 3, 2]] - [-1, 1, C2f_SimAM, [256, True]] head: - [-1, 1, Segment, [nc9, nm32, npr256]]nc9 对应九类目标nm32 是每个实例的掩码系数数量npr256 是原型掩码分辨率。改完第一件事是打印参数量对比原始 yolov8s-seg.pt差异应该在预期范围如果参数量暴涨说明注意力模块选重了路侧部署会吃显存。我判断这类改动是否有效的做法是消融同一份数据原始模型训 100 epoch改进模型训 100 epoch比对 mAP50 和掩码 IoU 两条曲线。注意注意力改进对这类小目标数据收益通常体现在 mAP50-95 而不是 mAP50——mAP50 对掩码边缘不敏感掩码质量的提升往往只在 50-95 指标上反映出来只看 mAP50 会误判改进无效。3.3 训练配置与启动命令参数怎么设数据 yaml 放在数据集根目录下路径用相对路径避免换机器后全部失效# road_parking_seg.yaml path: ./datasets/road_parking train: images/train val: images/val names: 0: bus_stop 1: free_parking 2: trash_bin 3: no_parking_sign 4: property_entrance 5: side_street 6: shop_entrance 7: shop_reserved_parking 8: temple训练命令yolo segment train \ modelyolov8s-seg.pt \ dataroad_parking_seg.yaml \ epochs150 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ mosaic1.0 \ close_mosaic10 \ optimizerAdamW \ device0关键参数取舍按这张表记参数取值说明imgsz640路边场景小目标多640 是性价比起点显存够就上 960batch16以单卡显存能放下为准batch 太小 BN 统计量不稳lr00.01用预训练权重时的常规起点改太大 loss 直接发散close_mosaic10最后 10 epoch 关闭 mosaic收敛更稳optimizerAdamW小数据集上比 SGD 收敛快mAP 上限略高训练过程盯 runs/segment 下的 results.csv 和 confusion_matrix.png。mAP50 过 0.8 不算难真正要看的是 mAP50-95 曲线是否随 epoch 持续上升如果 100 epoch 后 50-95 还在 0.4 附近横盘回到第 2 章检查小目标样本量而不是继续加 epoch。训练完用 best.pt别用 last.pt最后一个 epoch 通常没过拟合边界。4. 推理与后处理从分割掩码到停车位可用性判定训练完成只是第一步非标准停车位识别的价值在判定一块区域能不能停。这一章把推理脚本和掩码后处理拆开讲这也是从目标检测升级到实例分割后的核心差异输出从坐标框变成可计算的几何区域。4.1 单图推理参数与掩码输出的读法先看最基础的推理脚本from ultralytics import YOLO model YOLO(runs/segment/road_parking/weights/best.pt) results model.predict( samples/street_a.jpg, imgsz640, conf0.35, iou0.45, retina_masksTrue, saveTrue, ) for res in results: print(res.boxes.cls.tolist()) if res.masks is not None: # (N, H, W)N 为实例数H/W 为原图尺寸 print(res.masks.data.shape)conf0.35 是经验值禁停标志、垃圾箱这类小目标置信度天然偏低阈值拉到 0.5 会漏掉一半如果业务上宁可误报不可漏报可以降到 0.25把风险目标留给后处理规则去过滤。retina_masksTrue 是血泪经验换来的参数不开它掩码从 256×256 原型分辨率直接上采样到原图边缘锯齿和 10-20 像素偏移会吃掉后处理精度开了它返回的是原图分辨率掩码。注意 masks.data 的 shape 是 (实例数, 原图高, 原图宽)和框坐标的归一化表示不同读数据时别混。4.2 掩码后处理重叠面积计算与冲突判定识别系统不能只输出九类掩码要把它们转成可停/禁停的结论。我一般把掩码转成 shapely 多边形再算两两交叠比import cv2 import numpy as np from shapely.geometry import Polygon def mask2poly(mask): mask (mask 0.5).astype(np.uint8) contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if not contours: return None cnt max(contours, keycv2.contourArea) pts cnt.reshape(-1, 2) return Polygon(pts) if len(pts) 3 else None def overlap_ratio(a, b): if a is None or b is None: return 0.0 inter a.intersection(b).area return inter / a.areamask2poly 里的 0.5 是掩码二值化阈值超过一半概率的像素才算目标内部调太低会把边缘噪声带进多边形。轮廓取最大外轮廓因为实例掩码理论上只有一个连通区取最大能滤掉零星误检碎片。拿到多边形后按规则表做判定组合关系判定结果free_parking 与 no_parking_sign 重叠 5%区域不可用标记为风险位free_parking 与 bus_stop 重叠 30%判定为公交站占用禁停free_parking 与 side_street 重叠 30%路口区域禁止停放shop_reserved_parking 与 trash_bin 重叠 50%保留位受垃圾清运影响提示清理阈值写成配置文件而不是硬编码在脚本里业务方调参不用动代码。这套规则就是实例分割相对目标检测的增量价值矩形框只能告诉你附近有禁停标志掩码能告诉你禁停标志区域和候选停车位具体重叠了多少后者才能支撑告警和派单这类下游动作。5. 训练与部署避坑五个高频翻车现场跑这份资源的人多翻车的姿势也高度集中。下面五条是我反复踩过、也帮人排查过的高频问题每条按现象、原因、解决三步给全。5.1 训练 loss 下降慢mAP50 卡在 0.2 附近现象训练了 60 个 epochbox_loss 还在 1.2 以上掉不动mAP50 在 0.2 附近横盘。原因九类样本严重不均衡。垃圾箱和禁停标志占掉七成样本寺庙和商店保留停车位只有几十个实例少样本类的梯度被大样本类淹没。解决先用第 2 章的统计脚本确认分布对长尾类做复制粘贴增强把少样本实例贴到无冲突背景上把每个类有效样本补到 200 个以上同时把 lr0 降到 0.005小数据下默认学习率容易震荡。改完再训mAP50 一般能到 0.6 以上。5.2 掩码边缘锯齿严重与原图目标错位现象推理保存的可视化图里掩码边界锯齿明显且整体往某个方向偏移 10-20 像素。原因推理时没开 retina_masks掩码从 256×256 原型分辨率上采样到原图细节丢失或者训练 imgsz960、推理 imgsz640尺度不一致导致掩码投影错位。解决predict 加 retina_masksTrue推理 imgsz 必须和训练一致想换尺度就重新训练不要在推理时改仍没解决就把 Segment 头的 npr 从 256 提到 320 重训代价是训练显存增加约 15%。5.3 mAP50 高而 mAP50-95 低现象mAP50 到 0.85mAP50-95 只有 0.35两个指标差了一倍多。原因小目标占比高。禁停标志、垃圾箱在远距离下只有几十个像素框和掩码的 IoU 波动大mAP50 对边缘不敏感掩盖了掩码质量问题。解决imgsz 从 640 提到 960小目标特征保留更多如果换了注意力模块但 mAP50-95 没有明显变化说明改进没作用到掩码分支检查改动是否只加在了分类路径上。验收以 mAP50-95 为准这是和实际遮挡场景最接近的指标。5.4 显存 OOMbatch 一调小就训练不稳现象batch16 直接 CUDA out of memory改成 batch4 后 loss 剧烈震荡。原因数据集里原始照片是 4000×3000 的高清图训练时虽然会 resize 到 imgsz但数据加载和缓存环节仍吃显存batch 过小导致 BN 统计量不稳定。解决训练前把原图统一缩到最长边 1280 以内再进数据集batch4 时把 cache 关掉或改 cachediskultralytics 会自动按目标 batch 64 做梯度累积batch8 通常比 batch4 稳得多先用 batch8 而不是硬顶 batch16。5.5 换机器后推理输出和源码包 demo 对不上现象同样的权重和图片在自己机器上跑出来的掩码数量、类名顺序、掩码 shape 都和 demo 输出不一致。原因ultralytics 版本不一致不同版本对 Segment 头输出的组织方式有调整或者加载权重后类名顺序被本机 yaml 覆盖。解决先按源码包 requirements 锁版本别用最新版硬跑加载权重后打印 model.names 核对九类顺序掩码 shape 对不上时检查是不是用了不同尺寸的 imgsz 推理。版本问题是这类源码包最大的黑匣子锁定依赖是第一步也是最后一步。6. 模型部署进阶ONNX 导出与批量推理的落地路径模型要在真实路侧设备上跑一般不走 PyTorch 推理先导出 ONNX 再做 TensorRT 或 OpenVINO 加速。导出命令很短坑在参数yolo export modelruns/segment/road_parking/weights/best.pt \ formatonnx imgsz640 dynamicTrue opset12dynamicTrue 让输入宽高可变适配不同分辨率的摄像头opset12 是兼容性和算子支持之间的平衡点opset 拉太高老设备上的推理引擎会报不支持的算子。导出后别急着部署先用 onnxruntime 跑一张测试图把输出的框、掩码和 torch 推理结果逐项比对掩码 IoU 差 1% 以内才算过。分割模型的 ONNX 输出比检测模型多一组 mask 系数和原型图解析顺序错了会得到全黑掩码这是部署环节最容易翻车的地方。批量推理直接用 onnx 权重加载数据源换成目录或视频流后每帧掩码交给第 4 章的规则引擎做判定结果落成 JSON 行供上层派单系统消费。单帧耗时在 Jetson 这类边缘设备上fp16 的 engine 通常能压到 30ms 以内具体看输入分辨率和原型掩码的 npr 配置。这套源码和数据集的打包文件放在下载区解压后按第 2 章的转换脚本、第 3 章的数据 yaml 和训练命令一个下午能跑通全流程。从那以后我每次交付这类系统都强制走一遍导出 ONNX → onnxruntime 跑测试图 → 比对掩码差 1% 以内 → 再上设备的流程这四步能拦住九成部署事故。希望帮到你。本文还有配套的精品资源点击获取
返回列表