简介面向目标检测与智能停车场景的停车位检测数据集基于 YOLOv8 标注格式构建适用于训练车位检测模型、评估算法效果及教学演示。共 1520 张图像已划分为训练集 1380 张、验证集 119 张、测试集 21 张所有图像均完成自动定向并统一缩放至 640x640并通过水平/垂直翻转、随机旋转、亮度调节、高斯模糊与椒盐噪声等增强策略为每个源图像扩展出 3 个版本可有效提升模型泛化能力。压缩包内共 2000 个文件以 txt 标注文件、jpg 图像文件及 yaml 数据集配置文件为主配置结构与 YOLOv8 训练要求直接对齐解压后即可接入训练流程。资源包约 164.36MB体量适中目前已有 167 人学习浏览适合目标检测初学者、算法工程师及自动驾驶/停车场智能化项目开发者快速获取规范数据并开展实验。1. 停车位检测不是“有空位就报”YOLOv8 数据集到底解决什么问题想想应用场景停车场出入口的车位引导屏、手机端找车位、园区道闸联动。这些系统真正要的不是“检测出车位在哪”而是“当前哪个车位空着”。所以这个数据集的标注如果只有车而没有车位框或者只有车位框没有状态训练出来就只能做一半活。把停车位检测数据集和 YOLOv8 放在一起本质是解决一个二分类目标检测问题——区分空车位和占用车位或者先检车位再叠加判断。适合谁做智慧停车、车位引导、园区管理的视觉工程师以及刚入门目标检测、想拿一个真实场景数据集练手的人。这一章先把这个数据集的结构、标注逻辑和模型匹配度讲清楚后面再给训练参数和踩坑记录。2. 数据集与模型选型这套停车位数据的标注格式和 YOLOv8 的匹配度2.1 标注格式从原始图片到 YOLO 标签文件常见的停车位检测数据集图片主要来自停车场闸口、高位枪机或车载环视相机。标注形式不外乎两种第一种只标车位框类别是 parking_space 一个第二种把空位和占用分开类别是 empty 和 occupied。用 YOLOv8 训练时第二种更实用因为模型直接输出车位状态后处理少一个步骤。拿到数据集后第一步是统一格式。YOLOv8 的训练标签是 txt 文件每行一个目标格式为class_id x_center y_center width height注意这里的四个坐标值都是相对于图片宽高的归一化小数不是像素值。我从别处看到过不少数据集的标注是像素坐标直接写在 txt 里的这种必须做转换否则训练时损失函数会震荡甚至跑到 nan。常见做法是写一个转换脚本读 COCO 的 JSON 标注或 VOC 的 XML 标注再输出为 YOLO txt。import os from PIL import Image def convert_to_yolo(bbox, img_w, img_h): # bbox: [x_min, y_min, x_max, y_max] 像素坐标 x_center (bbox[0] bbox[2]) / 2 / img_w y_center (bbox[1] bbox[3]) / 2 / img_h width (bbox[2] - bbox[0]) / img_w height (bbox[3] - bbox[1]) / img_h return x_center, y_center, width, height # 遍历每张图片读取标注并写出同名 txt # 注意txt 文件名必须与图片文件名一致 for img_file in os.listdir(images): if not img_file.endswith(.jpg): continue with Image.open(os.path.join(images, img_file)) as img: w, h img.size # 这里从标注文件中读取该图的所有 bbox逐一转换后写入 labels 目录脚本的逻辑就是把像素坐标转为归一化坐标关键点在于 img_w 和 img_h 必须取原始图片的实际尺寸。有些数据集附带的标注文件里记录了尺寸信息但和图片真实尺寸不一致建议训练前用 PIL 批量核对一遍。转出来的 txt 放到 labels 目录图片放到 images 目录目录结构在后面会给出。2.2 YOLOv8 的检测头与车位检测任务的适配点YOLOv8 相比 v5 把检测头换成了 anchor-free 的 decoupled head也就是分类和回归分成两个分支。这对停车位检测有实际意义车位框通常是长条形宽高比例跨度大anchor-free 方式不需要预设 anchor 尺寸训练时对长条形车位的回归更稳。另一个适配点是 YOLOv8 的 C2f 模块替换了原来的 C3它把梯度分流做得更细特征复用更充分。实测下来在遮挡较多的停车场场景C2f 对局部特征的利用更好漏检率比 v5 略低。不过这个结论只针对我手上的数据和场景不同停车场的光照、视角差异很大不能一概而论。训练时要注意输入尺寸的设定。停车位检测常用 imgsz640但如果你拿到的图像是高位俯视视角车位在图像中占比很小640 会导致小目标特征丢失。建议 imgsz 提到 960 或 1280。代价是显存占用上升GTX 1660 Ti 这类 6GB 显卡跑到 1280 会比较吃力我一般先用 640 跑通流程确认数据没问题再加大尺寸提精度。YOLOv8 的模型权重也值得说一下。n 是 nanos 是 smallm 是 mediuml 是 largex 是 xlarge。车位检测场景不复杂n 或 s 足够。我做过对比在同样的 5000 张训练图上n 的 mAP 大概比 s 低 3 到 5 个百分点但推理速度是 s 的两倍以上。如果部署端是 Jeston Nano 或 RK3588 这类边缘设备建议直接用 n省下的算力留给后续的连续帧后处理。2.3 数据规模与类别设计分不分“空/占”两类这套数据集如果是按 empty 和 occupied 两个类别标注的直接按两个类别训练即可。如果只有一个 parking_space 类别那后处理就要额外加一步对检测到的车位框做车辆存在性判断。推荐优先选择带状态标注的数据集端到端训练的泛化性比规则后处理好。真实停车场里车辆停歪、跨线的情况太常见规则后处理在边界情况下很容易误判。类别不平衡是这类数据集的通病。日常停车场场景下占用车位的比例可能高达 80% 以上直接训练会让模型偏向预测占用空位的召回率到 70% 就上不去。常见处理手段有三种按类别加权采样、对空位做复制增强、使用 YOLOv8 的 class weights 参数。我试下来最简单有效的方式是训练前统计类别数量然后对数量少的一类做简单的重复采样把比例拉近到 1:2 以内。数据集划分也影响结果。停车位数据的场景相似度很高同一个停车场的训练集和验证集如果总是同一批车位mAP 虚高很严重。建议按停车场场景划分比如 A 停车场的图片进训练集B 停车场进验证集这样模型面对新场景的表现才能测出来。如果数据集本身没有按场景分文件夹就要靠图片命名规律或拍摄时间来做划分。3. 把数据集跑进 YOLOv8环境、训练参数与损失曲线解读3.1 环境准备与数据目录组织环境搭建不复杂YOLOv8 的安装依赖比 v5 少很多。最省事的方式是用 pip 安装 ultralytics 包Python 版本建议 3.8 到 3.10PyTorch 用 2.0 以上。CPU 版本也能跑就是慢一张 640x640 的图在纯 CPU 上大约要 0.5 到 1 秒几百张图的数据集也能训只不过一个 epoch 要跑上好几分钟。pip install ultralytics # 验证安装跑通自带的预训练模型 yolo predict modelyolov8n.pt sourcehttps://ultralytics.com/images/bus.jpg如果 pip 安装慢可以使用国内镜像源具体做法是在 pip install 后面加 -i 参数指定镜像地址。装完 ultralytics 后它会自动拉起需要的依赖包括 torch、torchvision、opencv-python 等。如果机器上已有老版本 PyTorch建议先卸载再用 ultralytics 重新装老版本 torch 和新的库之间常有算子兼容问题训练时会报一些难懂的错。数据目录组织是训练前最重要的一步推荐这样安排parking_dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yamldata.yaml 是 YOLOv8 的数据集配置文件内容很简单path: /home/user/parking_dataset train: images/train val: images/val nc: 2 names: [empty, occupied]path 用绝对路径最省事相对路径有时会因为终端工作目录不一致而找不到图片。train 和 val 指向图片目录标签目录会自动按相同结构查找所以 labels 下面是 train 和 val级联关系不能错。nc 是类别数names 是类别名列表顺序必须和标注文件里的 class_id 一一对应这也是训练前必须核对的项目之一。3.2 训练命令参数含义与默认值训练命令本身不复杂复杂的是选对参数。下面是我跑停车位数据集常用的一组参数yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ patience20 \ device0modelyolov8n.pt 是预训练权重n 是 nano 版本参数量约 3M适合快速验证。精度不够就换成 yolov8s.pt 或 yolov8m.pt显存占用依次增大mAP 也会涨一些。epochs100 对停车位这种类别少、场景单一的任务够用我在几个数据集上观察过60 轮左右 mAP 涨势就明显放缓后面多是微调。patience20 是早停参数连续 20 轮验证集 mAP 没有提升就自动终止能省不少时间。batch16 在 8GB 显存下配合 imgsz640 比较稳显存小就降到 8。几个容易被忽略但很重要的参数weights 参数控制是否使用预训练权重的冻结部分cos_lr 控制学习率是否按余弦曲线下降YOLOv8 默认为 True我建议保持默认最后 20 轮学习率降到极低能把损失函数的浮动压住。mixup 和 mosaic 是数据增强默认为 True对车位这种小目标场景建议保持开启除非你的数据量特别小。有一部分工程师会把 lr0 直接调到 0.001 来“求稳”这是个常见误解。预训练权重已经在 COCO 上收敛过从头用低学习率微调会收敛得很慢正确做法是先用 0.01 跑 20 轮观察损失曲线如果震荡剧烈再考虑降到 0.005。提示如果训练过程中显存溢出优先减小 batch 而不是 imgsz。batch 减半对精度的影响远小于 imgsz 减半后者会直接改变所有标签的归一化尺度。3.3 训练过程监控损失曲线与验证指标训练时终端输出的信息包含 loss、GPU 利用率、mAP 等指标。我一般不看单轮的数字而是等训练结束看 runs/detect/train 目录下的 results.png里面包含 box_loss、cls_loss、dfl_loss、precision、recall、mAP50、mAP50-95 多条曲线。tensorboard --logdir runs/detect/train如果想实时看曲线YOLOv8 训练时默认开启 TensorBoard 日志上面这条命令可以打开面板端口默认 6006浏览器访问即可。实时监控的价值在于早停之后能快速判断是参数问题还是数据问题。判断标准我一般这样把控box_loss 前 10 轮如果不明显下降先怀疑学习率和标签归一化cls_loss 降不下来先怀疑类别不平衡mAP50 在 0.9 附近浮动而 mAP50-95 只有 0.5 左右说明定位精度够了但框的贴合度一般可以调大 imgsz 或者检查标注框是否偏大偏小。验证集的预测图也是重要排查材料。YOLOv8 会自动把 val 目录中的部分图片画上检测框保存到 runs/detect/train 的 val 子目录。我会专门挑几张有遮挡、光照差、车辆跨线的图看这几类图最容易暴露问题。如果验证图里空车位检测正常但占用车位频繁漏检基本就是训练样本里空位过多导致的。4. 避坑训练停车位数据集最常见的五个问题4.1 标注框坐标没归一化训练 loss 爆掉现象训练刚开始 loss 就显示 nan 或者几百几千的数值完全收敛不了。原因标签 txt 文件里的坐标是像素值没有除以图片宽高。YOLOv8 要求归一化坐标在 0 到 1 之间超出这个范围梯度计算就会出问题。解决训练前用脚本批量检查。遍历所有 label 文件只要任一行坐标最大值大于 1.0就判定为异常。import os def check_labels(label_dir): bad_files [] for f in os.listdir(label_dir): path os.path.join(label_dir, f) with open(path) as fp: for line in fp: parts line.split() for v in parts[1:]: if float(v) 1.0 or float(v) 0: bad_files.append(f) break return bad_files print(check_labels(labels/train))这个脚本在数据转换之后、训练启动之前跑一遍能省掉大量排查时间。我见过不止一次因为坐标没归一化导致训练几小时白跑的情况。4.2 类别不平衡导致空位检测不到现象验证集上 occupied 类别的 mAP 有 0.95empty 只有 0.6模型的输出几乎全部判定为占用。原因训练集中空位样本太少模型学会了“偷懒”把大部分框都预测为占用因为这样在训练集上损失仍然很低。解决先统计数据分布确认空位占比确实偏低后对空位样本做重复采样或复制增强把比例拉近。另外也可以在 data.yaml 后面加一个 class_weights 配置给类别加权但这个参数在部分版本中没有开放最稳妥的办法还是数据层面的重采样。4.3 图片文件名和标签文件名不匹配现象训练能正常跑完但验证集的 mAP 一直在 0 到 0.1 徘徊看起来像模型完全没学到东西。原因YOLOv8 通过文件名前缀匹配图片和标签。如果图片是 0001.jpg 而标签是 1.txt或者图片是 IMG_20240101_123456.jpg 而标签文件被重命名过就完全对不上。解决训练前写脚本检查 images 目录下每个文件的主干名是否能在 labels 目录下找到同名 txt。找不到就统一重命名最好的做法是在数据准备阶段做一次全量校验把不匹配的文件名打印出来。4.4 车位框倾斜矩形框拟合不准现象模型检测出的矩形框同时包含两个车位或者框偏移到车位一半的位置看起来“大了一圈”。原因部分停车场的车位是斜列式或弧线排列矩形框无法准确表达倾斜的车位边界标注人员在画框时也容易把斜向车位画得偏大。解决一种做法是接受矩形框只取框中心点作为车位位置做状态判断另一种做法是换用 YOLOv8-OBB 分支它支持旋转框检测但标注文件要改成带旋转角度的格式转换成本不低。我个人的建议是只要输出是“车位状态”而不是车位轮廓先用矩形框中心点方案部署简单且稳定性足够。4.5 光照变化导致白天可用晚上失灵现象白天测试效果不错晚上或逆光时检测框抖动明显甚至完全漏检。原因训练集中缺乏夜晚、黄昏、地下车库等光照条件的样本模型把“亮度”当成了一个隐藏特征来用光照一变就失效。解决数据增强里把 HSV 扰动幅度调大hsv_h、hsv_s、hsv_v 三个参数分别控制色相、饱和度和亮度变化范围。更根本的解决方式是补充夜晚数据网上能找到的停车场数据集大多是日间采集如果有条件可以自己做夜晚采集或者对现有数据集做亮度通道的随机压暗增强。5. 从检测框到车位状态连续帧投票与 IoU 阈值的后处理技巧检测框本身不是最终交付物停车位检测系统的输出应该是“哪个车位空着”。这里分享一个我常用的后处理思路把停车场里每个车位的固定区域预定义好检测模型只负责判断这些区域里有没有车。具体做法是在图像坐标系里手动标定所有车位的矩形区域保存成一个 JSON 文件。运行时把 YOLOv8 检测出的车辆框与车位框做 IoU 计算IoU 大于阈值的判定为该车位被占用。这样做的好处是车位位置固定不变模型只负责找车误检率比直接检测车位要低。def check_parking_status(vehicle_boxes, space_boxes, iou_threshold0.6): status {} for space_id, space_box in space_boxes.items(): max_iou 0.0 for box in vehicle_boxes: iou compute_iou(box, space_box) if iou max_iou: max_iou iou status[space_id] occupied if max_iou iou_threshold else empty return status这里两个关键参数需要注意。IoU 阈值取 0.5 时车辆跨线停在两个车位中间两个车位都会被判定为占用实际只有一个车位被占。把阈值提升到 0.6 以上能减少这种双重占用。另一个是连续帧确认逻辑单帧偶尔会误检我一般在工程里加一个 3 帧投票连续 3 帧中至少 2 帧判定一致才更新车位状态这个简单策略能把闪烁率降一半以上。从那以后我每次做这类车位检测系统都会把后处理逻辑单独写成函数模块不在主流程里堆条件判断。测试时先跑一遍纯模型输出再跑一遍带后处理的完整流程对比两者的差异基本能定位到问题出在模型还是后处理。这套停车位数据集配合 YOLOv8能把训练推进到“系统能直接给车位状态”这一步希望帮到你。本文还有配套的精品资源点击获取