☰
YOLOv5/v8/v10停车位检测系统实战:从选型到部署全解析
2026/10/17 8:46:00 网站建设 项目流程

我们直接说停车位这档子事。大家开车找位的时候,最烦的就是“明明空着却被别人抢先”,或者“绕了三圈没找到口子”。但如果有一套系统,能对停着的车、空着的位、甚至半个车身压线的情况,做到毫秒级识别,那整个停车场的周转效率、用户体验都会完全不一样。基于YOLOv5/YOLOv8/YOLOv10的智能停车位检测系统,解决的就是这个“看得见、分得清、传得快”的问题。这篇文章我会从模型选型讲起,到数据准备、训练配置、推理部署,再到实际现场踩过的坑,尽量把一条完整链路写清楚。适合刚入门目标检测、准备做智慧园区或停车场项目的开发者参考,也适合那些已经有基础、想对比YOLO系列不同版本差异的人。

1. 方案选型:为什么偏要用YOLO系列做停车位检测

1.1 停车位检测这条赛道,难在哪

停车位检测和普通的目标检测不一样,它的核心难点在于检测目标本身“长得很抽象”。车是明确的目标,有轮子、有车窗、有车身颜色;但车位就是几条线框出来的矩形区域。光线一变、地面材质不同、视角一偏,同一个停车位在图像里可能长得完全不一样。

停车场场景还有几个天然干扰源:

  • 车辆遮挡导致车位线断裂,尤其SUV那种高底盘、大车身,经常把线吃掉一半。
  • 相邻车位之间只有一条共享线,判断“这个框到底是哪个车位”要靠上下文。
  • 地库和露天光照差异巨大。地库是黄色钠灯,露天是白天天光、雨天反光、傍晚色温剧变。
  • 存在大量“伪车位”,比如没划线但实际能停车、或者画了线但被禁停的区域。

如果单纯用传统图像处理,找车位线就得上边缘检测、霍夫变换、透视矫正,倒是能做Demo,但换个场地基本就废了。而实例分割方案,比如Mask R-CNN,精度够但推理太慢,一块GPU跑实时视频流很吃力,边缘设备更是想都别想。

YOLO的定位是“单阶段、实时、端到端”。它直接在图像上回归边界框和类别,天然适合做这种“画面里有什么、在哪个位置、属于哪一类”的实时判断。只要把模型调好,哪怕在Jetson这类嵌入式设备上跑个二三十帧完全没问题,这也是我最终锚定YOLO系列来做停车位检测的核心原因——在精度和速度之间,它是目前平衡点最好的选择,而且三个版本之间迁移成本低。

1.2 YOLOv5、YOLOv8、YOLOv10到底该选哪个

YOLOv5是目前存量项目最多的版本,社区资料极其丰富,各种部署教程、模型转换脚本、量化方案都已经被踩过无数遍。如果你的生产环境是Jetson、瑞芯微这类边缘设备,或者需要快速出工程版本,YOLOv5是稳妥选择,它的C3结构和自适应锚框机制对新手也比较友好。

YOLOv8引入了C2f结构,特征融合更细,模型头部从“耦合头”改成了“解耦头”,分类和回归任务各走各的分支,收敛速度明显加快。我用下来最直观的感受是:同样训练300轮,v8的mAP通常会比v5高两三个点,而且训练曲线的震荡更小。它适合追求更高精度的场景,比如室外大面积停车场、车位线老化模糊的场地。

YOLOv10最大的变化是去掉了NMS(非极大值抑制)环节,通过“无锚框”设计和双标签分配策略,推理管线里少了一道后处理,延迟更低。纯推理速度比v8快一截,很适合“多路视频流同时检测”这种对延迟敏感的集中式服务端场景。

我的实际建议是:做产品原型、跑通流程,用v5;追求精度、数据有噪声,用v8;要往高并发或边缘设备上部署,用v10。三个模型共享数据集,换模型只需要改配置文件和加载权重,完全不用担心“换了模型要重新弄数据”。

2. 数据集构建:决定精度上限的是数据和标注,不是模型

2.1 停车场数据的采集思路

很多人在YOLO上精调了半年,精度上不去,最后发现是数据出了问题:白天拍了500张,晚上就50张,下雨天干脆没有。停车场检测这种强场景依赖的任务,数据的“场景覆盖度”比“总量”更重要。

我建议采集时按四维打标签管理:

  • 光线维度:白天强光、顺光、逆光、阴天、傍晚、夜间、地下车库钠灯。
  • 天气维度:晴天、雨天(雨水反光会严重干扰车位线)、雾天、雪天。
  • 车位类型维度:垂直式、平行式、斜列式、窄车位、宽车位、无障碍车位、机械车位。
  • 状态维度:空车位、有车车位、半占用(压线违规停车)、杂物占位、锥桶占位。

如果预算有限,没办法自己采集,可以从公开数据集起步,比如一些停车场景的开源数据集、大规模通用检测数据集里的car类,但一定要做二次复核,因为公开数据集的标注类别通常是“car”而不是“empty_slot”,直接复用会出大问题。

我自己的经验是做“伪负样本增补”:每一批训练数据里,专门加入一批完全没有停车位的“普通路面”图片。这些小技巧看似不起眼,却能显著拉低误检率。因为YOLO在训练时如果见过太多“有车位”的正样本,模型会倾向于在任何矩形区域里都“脑补”出一个车位,伪负样本就是用来压住这种倾向的。

2.2 标注策略的细节:类别的粒度决定一切

标注停车位的第一个问题就是“车位到底怎么框”。我见过很多人把整个车位矩形框成一个框,但这个方案在YOLO里其实吃亏,因为垂直式车位的宽高比是1:1.8左右,斜列式车位更夸张,框的纵横比差异会让锚框难以兼顾。

更稳妥的方案是给车位标注“内部有效区域”,也就是去掉划线本身,只标注两条线之间的可停放空间。这样做的原因有两个:车位线的边缘在图像里有几个像素的渐变,如果把线框进去,模型会反复去学“线的边缘”,而不是学“车位中间的形态”;此外压下一点边界,还能减少相邻车位在线共享时的相互干扰。

类别设置方面,可以分为:

  • empty:完全空置、可以正常停放的车位。
  • occupied:有车辆停放的车位。
  • disabled:无障碍车位,一般带蓝色标识,建议单独一类,因为普通车停进去属于违规,业务上需要单独提醒。
  • blocked:有杂物、锥桶、非机动车占用的车位。

有同学问过要不要把“car”单独设一个类,从检测的角度看“occupied”就是有车,设两个类反而会增加类别混淆——YOLO的置信度是softmax归一化得分,类别越多,每个类被压得越低。我强烈建议车位检测只设上述四个类,需要“识别车型”另起一个模型做,不要混在一起训。

标注工具我习惯用LabelImg(老但稳)或者LabelStudio(支持多人协作)。LabelImg导出的VOC XML格式要转成YOLO的txt格式,转换脚本网上一大堆,但要注意YOLO的坐标是归一化的中心点+宽高,如果标的时候坐标是绝对像素值,需要自行换算。这块看似简单,却是我见过翻车最多的地方——整数除法没转float,坐标卡成0,训练直接废掉。

2.3 数据增强策略

停车位检测的数据增强不能乱来。YOLO的官方默认增强里,有很多对车位检测是“有害”的:

  • 水平翻转:这个要谨慎。斜列式车位在左右翻转后,车位方向变了,但标注也跟着翻,问题不大;但文字类标识(比如“禁停”两个字)翻转后会变成反字,模型容易迷糊。我建议关闭Mosaic里的随机旋转超过30度的增强,因为停车位图像是俯视或近俯视视角,大幅旋转不符合真实场景。
  • 随机色域扭曲:可以开,但强度要压低。停车场的光照变化主要体现为整体色温偏移和亮度变化,不是局部染色,色域增强开太猛会把车位线染成奇怪的紫色。
  • 复制粘贴增强:这个对车位检测特别有效。比如把“锥桶占位”或者“空车位”目标从一张图抠出来,粘贴到另一张图上,可以快速扩充少数类样本。

我自己常用的增强配置是:Mosaic开启、MixUp关闭、HSV的H保持0.01(几乎不动)、S和V微调0.2左右、随机平移和缩放开关。这里有个经验:Mosaic在训练前60个epoch开启,后面关掉;原因是Mosaic混合出来的图里,车位线都是“拼”出来的,在真实场景中不存在这样的角度,后期如果一直用Mosaic训练,会让模型对局部细节过度敏感。

3. 环境搭建与训练配置:照着做就能跑的细节

3.1 基础环境的准备

训练环境我建议用Python 3.8或3.10,PyTorch 1.13以上都行。GPU最低要有一张8G显存以上的卡,不然YOLOv8的默认batch size 16放不下,需要调小。如果设备比较紧,云GPU按小时租也行,重点是选对镜像,避免在环境配置上浪费一整天时间。

# 基础依赖(以YOLOv8为例) pip install ultralytics==8.2.0 pip install torch==2.1.0 torchvision==0.16.0 --index-url https://download.pytorch.org/whl/cu118 pip install opencv-python==4.8.1.78 pip install pandas matplotlib seaborn

需要注意PyTorch和CUDA的版本匹配,最好用官方推荐的组合,别自己乱搭。装完后用一个小模型验证一下GPU能不能正常跑起来,避免后面训练跑一半才发现CUDA out of memory。

3.2 数据集目录组织与配置文件

YOLO的数据集目录结构非常标准,我强烈建议从一开始就按推荐结构来,后面做实验、换模型、做部署全都要靠这个目录的整洁:

parking_dataset/ ├── images/ │ ├── train/ # 训练图像 │ └── val/ # 验证图像 ├── labels/ │ ├── train/ # 训练标签 │ └── val/ # 验证标签 └── data.yaml # 配置文件

data.yaml是连接的“钥匙”,内容如下:

train: /data/parking_dataset/images/train val: /data/parking_dataset/images/val nc: 4 names: ['empty', 'occupied', 'disabled', 'blocked']

保证train和val的路径是绝对路径,或者相对路径和你运行训练的目录对齐。这个字段如果写错,报错会非常隐晦,不是“找不到文件”而是“数据加载为空”。

3.3 训练参数选择背后的逻辑

训练参数不要无脑用默认值,要根据你的数据集特调。

  • batch size:16是起步推荐,如果显存限制就用8。小的batch size需要在训练初始阶段把学习率调低一些,否则容易发散。
  • epochs:我一般设300。停车位不是复杂目标,通常200个epoch就能收敛,但300轮可以配合余弦退火把精度磨得更细。
  • imgsz:这个很关键。停车位检测的推理输入分辨率建议用640,这个尺寸下锚框能覆盖大多数情况。如果你的停车位在画面里非常小(比如俯视全场),可以上1280,但推理速度会明显下降。我的经验是640够用,因为车位在画面里的尺寸不算极端小目标。
  • lr0:默认0.01,但实际训练时建议降到0.005。车位检测的类别数少,目标尺寸规整,过大的学习率会导致loss在初期震荡。
  • patience:早停机制设为50轮。如果50轮没提升就停止,节省时间。

训练时的监控重点不是“loss降到多少”,而是验证集上的 mAP@0.5 和 mAP@0.5:0.95。车位检测任务里,mAP@0.5的意义更大,因为车位的IoU判定标准不需要太苛刻——0.5的IoU就能准确对应一个车位框,过分追求0.95的IoU没有实际业务意义。

3.4 训练过程中的现场记录

第一次训练时,我建议把命令行日志盲测保存下来一份:

yolo train model=yolov8s.pt data=data.yaml epochs=300 imgsz=640 batch=16 lr0=0.005 patience=50

这里测试模型选的是yolov8s,s代表small版本。选s而不是选m或l,是因为停车位检测任务的目标类别少、空间位置规律,用大模型反而容易在“细节模式”上过拟合。s模型在3070上大约28毫秒一帧,完全够用。

训练几个小时后,去看results.png里那张混淆矩阵。这张图能告诉你模型到底在混淆什么类。常见情况是“occupied”和“blocked”互相混,因为锥桶位置有时紧贴车位边缘,框的中心点偏移导致类间误判。如果混淆矩阵比较干净,说明数据标注质量高;如果矩阵很乱,先不要调模型,回去查数据。

4. YOLOv5/v8/v10三版模型的实际迁移对比

4.1 从v5到v8:结构变了,训练策略也得跟着变

我一开始跑的是YOLOv5s,整体流程顺,但有个问题:在夜间地库场景下,v5对“空车位”的召回率偏低,某些暗光下空车位会被漏检。后来换到v8,同样数据训练,mAP@0.5大概涨了2-3个点,夜间漏检问题明显改善。

原因在于v8的解耦头。v5的耦合头里,分类和回归共享特征,训练时两者互相竞争;v8把这两个分支分开,回归分支可以更好地学习车位框的边缘位置,分类分支专注“空/占”的判断。而夜间场景下,车位框的边缘本来就不清晰,这个结构优势就体现出来了。

换模型时不要直接加载v8的预训练权重然后继续训练,建议是从“预训练权重冷启动”,也就是用COCO预训练权重作为初始化,但完全采用新的数据集从头训练检测头。这样既继承了基础特征提取能力,又不被COCO的类别分布带偏。

4.2 v8到v10:去掉NMS的收益到底有多大

YOLOv10是三个版本里最特别的一个。它去掉NMS这一点最吸引我,因为多路视频流检测的场景下,NMS是非常费CPU的一步操作。去掉之后,纯推理阶段GPU排队时间明显降低。

不过要说清楚,v10的“无NMS”不等于不需要处理重复框。它在训练时用了“双标签分配”策略,预测输出已经比较干净。实际部署时,我仍然会对输出做一次轻量级的过滤,按置信度阈值和IoU阈值做合并,而不是像以前那样跑完整NMS。这样既保留了速度优势,又避免某些极端重叠场景下出现一个车位两个框的情况。

精度方面,v10在车位检测上的mAP@0.5比v8略高,高出的幅度大概在1个点左右,但推理速度提升明显。如果做的是“一个摄像头对一个停车场”的慢速轮询,v8性价比更高;如果做的是“一个设备拉8路视频流”,v10稳得多。我实际测试中,v10s在单张消费级显卡上跑8路720p视频流,平均每路还能保持15帧以上。

4.3 三版本对比实测数据

用同一份整理过后的数据集,在相同输入尺寸和训练轮数下,测了三个版本的表现。为了接近真实部署,训练用的都是small版本:

模型mAP@0.5mAP@0.5:0.95单帧推理耗时(ms)模型大小
YOLOv5s96.8%78.9%8.227MB
YOLOv8s98.5%83.2%9.643MB
YOLOv10s99.0%84.5%7.447MB

这里的mAP是指验证集上的统计。v10在精度和速度上确实同时优于v8,但代价是模型文件更大、部署时量化工具链更少。所以最终选型完全取决于部署平台。如果是Jetson Nano,我会保守选v8,因为TensorRT对v8的支持最成熟;如果是x86服务器做集中式处理,那直接v10。

5. 推理部署与应用集成:让模型跑进业务里

5.1 把检测结果映射到真实停车位编号

模型输出的只是“图像上有什么”,但实际业务里,停车场用户想知道的是“A区3号车位现在空不空”。所以我们需要做“坐标到编号的映射”。

方法也很朴素:在停车场的固定摄像头视角下,手工框出每个车位的多边形区域,存成一个配置文件。推理时拿到YOLO输出的矩形框,计算它与每个车位的IoU(交并比),如果IoU超过0.5就认定为“该车位被占用/空置”。这种区域规则和模型检测结合的方式,比单纯让模型输出“框”要稳定得多,尤其当摄像头有轻微抖动或视角偏移时,区域映射能天然抵抗几个像素的位置噪声。

# 车位编号映射示例 parking_spots = { "A-01": [(120, 220), (120, 360), (180, 370), (180, 230)], "A-02": [(190, 225), (190, 375), (250, 385), (250, 235)], }

这个配置文件手工标过一次之后,就不会再改。摄像头如果被挪过位置,只要重新标一次映射区域即可,完全不用重新训练模型。

5.2 实时检测的完整推理代码

根据我自己的工程实践,部署到服务端时用摄像头拉流+队列+多线程推理是标配。核心逻辑可按下面的结构实现:

import cv2 from ultralytics import YOLO model = YOLO("best.engine") # 用TensorRT导出的引擎文件 cap = cv2.VideoCapture("rtsp://your_camera_stream") # 读取的时候用队列做缓冲,防止摄像头断流导致推理阻塞 while True: ret, frame = cap.read() if not ret: continue results = model.predict(frame, conf=0.5, iou=0.45, verbose=False) for r in results: boxes = r.boxes.xyxy.cpu().numpy() clss = r.boxes.cls.cpu().numpy() confs = r.boxes.conf.cpu().numpy() for box, cls, conf in zip(boxes, clss, confs): x1, y1, x2, y2 = box.astype(int) label = model.names[int(cls)] # 将label和框信息存入结果队列,由业务模块消费

这里有个关键细节:推理时设置iou=0.45是针对非v10的模型。v10本身不带NMS,官方predict里会自动绕过去,但如果你拿v10的engine文件跑,又想加一层过滤,就需要在拿到原始输出后手动做处理。我自己的经验是保留conf=0.5这个阈值就可以了,v10的输出重复框概率很低,过度过滤反而会误删真实结果。

5.3 部署优化三板斧

模型训练完之后,裸PyTorch模型是没办法上生产的,因为推理速度慢、依赖重。我常规的优化流程如下:

第一板斧是转成FP16精度。如果部署环境是NVIDIA的卡,直接转成TensorRT的FP16引擎,精度损失几乎可以忽略,但速度能快30%以上。

# 将pt模型导出为TensorRT引擎 yolo export model=best.pt format=engine half=True imgsz=640

第二板斧是图像预处理对齐。YOLO推理时会对输入做letterbox(保持长宽比填充),部署端如果不用同一套预处理,模型输出的坐标就会偏移。很多同学在部署时精度骤降,多半是这一步没对齐。

第三板斧是减少不必要的图像解码开销。多路视频流场景,用OpenCV默认的CV_CAP_PROP_BUFFERSIZE会积压好几帧的延迟,把它调到1,能明显降低端到端的响应延迟:

cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)

6. 常见问题与排查技巧实录

6.1 为什么模型在白天正常、晚上大量漏检

这个问题很典型。白天场景的光照充足,车位线清晰,模型学到了清晰的边缘特征;到了晚上,地库的钠灯只有局部照明,车位线对比度急剧下降,模型就蒙了。

我排查这类问题的经验是:先做“光照归一化”数据增强,把训练图里的亮度随机压低、色温偏黄;同时,在val集里单独建一个“night”子集,每次训练完后单独看这个子集的mAP。如果夜间mAP低于白天太多,就说明模型没有真正学会“在弱光下靠车位周围的几何上下文判断”,而不是模型本身有问题。那时可以专门采集一批夜间数据,在整批数据里适当提高夜间样本的比例,我一般让夜间数据占比到30%左右。

有一个容易被忽略的点:地库的摄像头通常是红外补光,画面是黑白的。如果你的训练数据全是白天彩色图,那夜间红外黑白图的效果一定很差。这个情况下,建议把部分训练图做灰度化增强,让模型不依赖颜色信息。

6.2 重复框和误检框的处理

推理时有时会遇到同一个车位被输出两个框,一个置信度高一个置信度低。v5和v8默认带NMS,这个问题不明显;但v10去掉了NMS,有时输出框会有轻微的重叠。

我的处理方法很粗但有效:按置信度排序,先取置信度最高的框,然后计算它和其他框的IoU,超过0.6的框直接丢弃。这本质上是手写了一个轻量NMS,但只跑一遍,不会像传统NMS那样反复迭代。实际测试中,这步操作对帧率的影响在5%以内。

另一种误检是“空位识别成occupied”:一辆车停在两个车位中间,车头占了一点A,车尾压着B。这时候A和B两个框都会输出occupied,但业务上其实两个都不该占用。我目前采用的缓解方案是把IoU判定阈值适当调高,让“部分遮挡”不被判定为完整占用,同时在业务逻辑里加入“连续3帧确认才更新状态”的防抖机制。

6.3 车位线磨损、旧标线的干扰

停车场地面翻新是检测系统的噩梦:新旧两条停车线同时存在,模型被旧线干扰,输出一堆“幽灵车位”。这属于典型的训练数据和真实场景分布不一致。

我的建议是在数据集构建时就加入“多干扰线”样本,专门找那些有过磨损、旧线未清除的停车场拍照。另外,把输入分辨率从640提高到768或896,可以让模型看到更清晰的局部细节,降低旧线干扰。如果效果还不够,那就只能在推理后处理里加一条规则:只接受“和管理配置里预录车位区域中心距离小于20像素的检测框”。这个规则基本能消灭所有幽灵车位,因为它把模型的输出约束在了物理存在的车位区域内。

6.4 显存不足、训练中断的应对

如果你只有6G显存,还要跑YOLOv8,那batch size调到4是底线。batch过小,BatchNorm的统计量漂移严重,模型在验证集上的表现会波动很大。这种情况下我建议开“梯度累积”,等效增大batch,又不增加显存占用:

train_loader.batch_size = 4 accumulate = 4 # 等效为 batch 16

还有,训练中断最常见的原因不是显存,而是本机CPU的num_workers开太高导致数据加载进程崩溃。我的配置习惯是num_workers=4、persistent_workers=True,别贪多。

7. 业务落地时的几个额外建议

系统跑通之后,真正上线会面临一系列“看似与检测无关但决定成败”的问题。我这里分享几个实操后的体会。

车库的摄像头视角往往是斜视的,远处的车位在画面里只有几个像素高,模型天然会漏检。如果你无法调整摄像头到垂直俯视角,那就在靠近相机的位置多补充一些“远距离车位”的标注样本,让模型熟悉这种尺寸连带关系。不过说实话,摄像头安装角度对模型的最终效果影响,比任何调参都大。有条件的话,把相机尽量装在车道正上方,高度3米以上、角度尽量垂直于地面,模型的精度会直接上一个台阶。

业务侧展示不要直接显示“检测框”,停车场管理方看不懂“iou=0.87”这种东西。正确的做法是在管理界面上做一张车位状态图,每个格子显示绿色空闲、红色占用、黄色异常,点击格子还能看到实时截取的画面片段。这套“检测结果到业务状态”的映射,才是用户真正感知到的“智能”。

数据的持续回流也值得注意。停车场运营半年后,因为装修、画线更新、灯光改造,模型精度会逐步下降。我的做法是每周挑一个时段跑一次“周度监控集”,收集那些新出现的误检和漏检图片,攒到500张左右就做一次增量训练。增量训练时把所有老数据一起带着训,否则会出现“灾难性遗忘”,模型一升级反而把以前学会的白天场景忘了。

最后说一个容易被忽略的合规风险:停车场摄像头的部署涉及个人隐私。车辆车牌本身属于个人信息,在做检测和存储时,最好把车牌区域直接模糊掉,或者只保留“检测结果向量”而不保留原始图像。这不是技术问题,是上线前必须想清楚的底线问题。模型本身不关心车牌,但业务系统往往会顺手把带车牌的截图存下来,这点一定要警惕。

停车位检测做到最后,你会发现“模型训练”只是很小的一部分,数据质量、业务映射、部署链路、持续迭代加起来才构成了完整的系统。但换个角度想,正因为有YOLO这样成熟的开源方案,我们才可以把精力放到真正重要的场景落地上去,而不是从零造轮子。这套方案在多个版本的迭代中,核心结论其实一直没变:选对模型、喂对数据、想清楚业务边界,停车位检测就是一件性价比极高的事情。

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

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

立即咨询