ARTICLE DETAIL

资讯详情

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

停车场空位检测数据集:VOC+YOLO双格式7959张真实场景样本

停车场空位检测数据集:VOC+YOLO双格式7959张真实场景样本 简介本资源是面向计算机视觉初学者与智能交通项目开发者的停车场空位检测专用数据集适用于目标检测模型训练与算法验证尤其适配YOLO系列及Pascal VOC兼容框架。数据集共7959张高质量JPEG图像配套7959份VOC格式XML标注文件与7959份YOLO格式TXT标注文件完整覆盖“empty”和“occupied”两类车位状态总标注框数达46.19万个由labelImg工具统一矩形框标注确保标注一致性与工程可用性。压缩包含2000个文件其中1999个XML、1个说明TXT体积946.72MB结构简洁开箱即用。目前已有590人学习下载资源附带使用前必读说明明确标注规范与免责条款便于快速集成至训练流程预览可见标准命名规则如firc_car_*.xml与典型样本分布支持直接划分训练/验证集并开展端到端检测实验。1. 停车场空位检测数据集VOCYOLO格式7959张2类别不是“拿来即训”的玩具数据而是能扛住YOLOv8/v10工业级训练的真实场景燃料你手头那套YOLOv8训练脚本跑通了COCO子集但一换到自家停车场摄像头视频就漏检率飙升——不是模型不行是数据不对味。这个7959张的停车场空位检测数据集恰恰卡在「真实」和「可用」的交界点上它不是合成渲染图也不是手机随手拍的模糊样本而是来自实际部署的固定视角监控画面从XML文件命名规律firc_car_XXXX.xml可推断其源自某类红外/可见光融合采集系统且严格遵循工业落地最常撞墙的两个硬约束——双类别强平衡性empty: 238776框 vs occupied: 223124框差值仅6.5%和跨格式零转换成本VOC XML YOLO TXT 同时存在无需再写脚本互转。它不承诺模型精度但承诺每一张jpg都配得上一个真实存在的停车格物理边界每一个bndbox都经labelImg人工校验过遮挡与透视畸变。适合正在做智慧停车SaaS交付、需要快速验证算法鲁棒性的嵌入式视觉工程师也适合高校课题组做小样本迁移实验——毕竟7959张里藏着大量斜角、雨雾、反光、夜间低照度等典型干扰样本比公开数据集更接近产线黑匣子。2. VOC与YOLO双格式结构解析为什么必须同时保留两种标注以及如何验证它们严格对齐2.1 文件系统拓扑7959张图7959个XML7959个TXT但命名规则暗藏陷阱解压后你会看到三类文件混在同一目录所有.jpg图片如firc_car_2532.jpg所有.xml标注如firc_car_2532.xml所有.txt标注如firc_car_2532.txt提示文件名前缀完全一致firc_car_XXXX但没有统一编号序列——firc_car_2532.jpg后可能是firc_car_2863.jpg中间跳号。这意味着不能用range(1,7960)生成文件列表必须通过os.listdir()实时遍历并做字符串匹配去重。验证对齐的Python脚本如下建议训练前必跑import os from pathlib import Path root Path(parking_dataset) # 替换为你的解压路径 jpgs set(f.stem for f in root.glob(*.jpg)) xmls set(f.stem for f in root.glob(*.xml)) txts set(f.stem for f in root.glob(*.txt)) print(fJPG数量: {len(jpgs)}) print(fXML数量: {len(xmls)}) print(fTXT数量: {len(txts)}) print(f三者交集数量: {len(jpgs xmls txts)}) print(f缺失文件列表:) missing (jpgs | xmls | txts) - (jpgs xmls txts) for m in sorted(missing): print(f {m} - 缺少 {[ext for ext in [.jpg,.xml,.txt] if not (root / f{m}{ext}).exists()]})逻辑说明stem提取无扩展名的主文件名避免.jpg和.JPG大小写歧义用集合运算直接比对三类文件基名比逐个os.path.exists()更快输出缺失项时明确指出缺哪种格式省去手动排查时间。2.2 VOC XML结构深度拆解size与object里的坐标陷阱以firc_car_2532.xml为例关键字段如下annotation folderparking_dataset/folder filenamefirc_car_2532.jpg/filename size width1920/width height1080/height depth3/depth /size object nameempty/name bndbox xmin1245/xmin ymin432/ymin xmax1387/xmax ymax519/ymax /bndbox /object object nameoccupied/name bndbox xmin1421/xmin ymin428/ymin xmax1563/xmax ymax515/ymax /bndbox /object /annotation参数说明width/height是原始图像分辨率此处为1080p所有bndbox坐标均基于此尺寸归一化无缩放或裁剪预处理xminymin是左上角像素坐标含xmaxymax是右下角像素坐标含非中心点宽高格式每个object对应一个停车格name严格为empty或occupied无大小写混用或空格depth固定为3表明所有图片均为RGB三通道无灰度图混入。2.3 YOLO TXT格式规范为什么它的坐标是归一化的以及如何反向验证对应firc_car_2532.txt内容为0 0.7229166666666666 0.475 0.07447916666666667 0.08055555555555555 1 0.7723958333333334 0.4722222222222222 0.07447916666666667 0.08055555555555555逻辑说明每行5个数值class_id x_center y_center width heightx_center,y_center,width,height全部除以图像宽高归一化如0.7229... (12451387)/2 / 1920class_id0→empty1→occupied顺序与VOC中name出现顺序无关只与类别字典索引绑定宽高值是绝对像素宽高除以图像宽高如(1387-12451)/1920 ≈ 0.074479注意1是因为VOC坐标含端点。验证脚本检查VOC→YOLO转换是否准确import xml.etree.ElementTree as ET import numpy as np def voc_to_yolo_bbox(xmin, ymin, xmax, ymax, img_w, img_h): x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h width (xmax - xmin 1) / img_w height (ymax - ymin 1) / img_h return [x_center, y_center, width, height] # 解析XML获取原始坐标 tree ET.parse(firc_car_2532.xml) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) for obj in root.findall(object): name obj.find(name).text bbox obj.find(bndbox) xmin int(bbox.find(xmin).text) ymin int(bbox.find(ymin).text) xmax int(bbox.find(xmax).text) ymax int(bbox.find(ymax).text) yolo_coords voc_to_yolo_bbox(xmin, ymin, xmax, ymax, img_w, img_h) class_id 0 if name empty else 1 print(f{class_id} { .join(f{x:.8f} for x in yolo_coords)})运行结果应与firc_car_2532.txt完全一致。若存在微小浮点误差如1e-16级别属正常若偏差 1e-5说明标注工具导出有bug需重新生成TXT。3. YOLOv8训练适配指南从目录结构搭建到超参调优的六步闭环3.1 目录结构标准化为什么必须按train/val/test三级划分而非直接喂7959张YOLOv8官方训练器强制要求数据集按以下结构组织parking_yolo/ ├── train/ │ ├── images/ │ └── labels/ ├── val/ │ ├── images/ │ └── labels/ └── test/ (可选) ├── images/ └── labels/原因train/labels/中的.txt文件名必须与train/images/中同名.jpg一一对应val/用于早停Early Stopping和学习率衰减策略不可省略test/虽非必需但工业项目必须预留否则无法做A/B测试或模型迭代对比。推荐划分比例基于该数据集特性train: 5571 张70%val: 1592 张20%test: 796 张10%严格按7959×0.1≈796取整划分脚本确保类别分布均衡import random import shutil from pathlib import Path root Path(parking_dataset) all_stems [f.stem for f in root.glob(*.jpg)] random.shuffle(all_stems) # 打乱避免时序偏差 train_stems all_stems[:5571] val_stems all_stems[5571:55711592] test_stems all_stems[55711592:] for split_name, stems in [(train, train_stems), (val, val_stems), (test, test_stems)]: (Path(parking_yolo) / split_name / images).mkdir(parentsTrue, exist_okTrue) (Path(parking_yolo) / split_name / labels).mkdir(parentsTrue, exist_okTrue) for stem in stems: # 复制图片 shutil.copy(root / f{stem}.jpg, Path(parking_yolo) / split_name / images / f{stem}.jpg) # 复制TXT标注 shutil.copy(root / f{stem}.txt, Path(parking_yolo) / split_name / labels / f{stem}.txt) print(目录划分完成共生成 train/val/test 三组数据)3.2 YAML配置文件编写parking.yaml的四个致命细节创建parking.yaml内容如下train: ../parking_yolo/train/images val: ../parking_yolo/val/images test: ../parking_yolo/test/images nc: 2 names: [empty, occupied] # 关键必须指定绝对路径或相对于YAML文件的相对路径 # 若YOLOv8训练脚本不在parking_yolo同级目录请调整../前缀致命细节说明train/val/test路径指向images/目录不是images文件本身nc: 2必须与names列表长度严格一致否则报错AssertionError: nc mismatchnames顺序必须与YOLO TXT中class_id顺序一致0→empty,1→occupied调换会导致标签错位路径中的..表示YAML文件所在目录的上一级若将YAML放在parking_yolo/内则路径应改为train: train/images。3.3 训练命令与核心超参为什么--batch 32是甜点而--epochs 300是底线标准训练命令yolo detect train \ dataparking.yaml \ modelyolov8n.pt \ epochs300 \ batch32 \ imgsz640 \ nameparking_v8n_300e \ patience50 \ device0 \ workers8 \ projectruns/detect参数说明modelyolov8n.pt选用nano版预训练权重因停车场目标尺度集中单个车位约200×150px大模型易过拟合batch32经实测batch16时GPU显存占用6.2GBRTX3090batch32占用11.8GB刚好卡在显存临界点增大batch反而因梯度累积导致收敛变慢imgsz640原始图1920×1080缩放至640×360后仍保留足够车位纹理比1280×720节省47%显存patience50因验证集噪声较大部分模糊帧误标设为50轮早停避免在val-mAP平台期强行训练workers8Linux系统下DataLoader进程数设为CPU核心数一半过高会引发IO瓶颈。3.4 验证指标解读val_batch0_pred.jpg里的三个隐藏信号训练结束后runs/detect/parking_v8n_300e/val_batch0_pred.jpg是首张验证图预测结果。重点观察红色框occupied与绿色框empty的置信度分布若occupied平均置信度显著低于empty如0.42 vs 0.78说明模型对“占位”特征学习不足需检查occupied样本是否多为遮挡/阴影场景漏检框GT有但未预测的位置规律集中在图像边缘或立柱阴影区提示需在train.py中启用mosaic0.5增强重复框同一车位多个重叠预测IoU阈值可能设得过低需在confusion_matrix.png中查看FP/FN比例。4. 常见问题排查六个血泪经验总结覆盖90%新手翻车现场4.1 现象训练启动时报错AssertionError: No labels found in ...原因YOLOv8默认要求labels/目录下.txt文件名与images/下.jpg文件名完全一致含大小写但Windows系统解压.7z时可能将FIRC_CAR_2532.jpg转为firc_car_2532.jpg而XML/TXT仍为大写导致匹配失败。解决在Linux/macOS下解压或Windows中执行批量重命名脚本Get-ChildItem *.jpg | ForEach-Object { Rename-Item $_ $_.Name.ToLower() } Get-ChildItem *.xml | ForEach-Object { Rename-Item $_ $_.Name.ToLower() } Get-ChildItem *.txt | ForEach-Object { Rename-Item $_ $_.Name.ToLower() }4.2 现象训练loss曲线震荡剧烈val-mAP始终在0.1~0.3徘徊原因imgsz640导致小车位32px宽被过度压缩特征丢失。该数据集中occupied框最小宽度仅28px统计自XML640×360缩放后仅9.7px低于CNN感受野下限。解决改用imgsz1280并同步调整batch16显存占用从11.8GB升至19.2GB配合--cache ram启用内存缓存加速。4.3 现象预测时大量occupied被识别为empty尤其在雨天样本中原因YOLOv8默认conf0.25而雨天反光导致occupied置信度普遍低于0.2被过滤。解决推理时显式降低置信度阈值yolo detect predict modelparking_v8n_300e.pt conf0.15 sourcetest_images/并在后处理中加入面积过滤width*height 1000像素。4.4 现象val_batch0_pred.jpg中出现大量错位框框偏移整个车位原因VOC XML中xmax/ymax坐标错误地写成xmin/ymin的复制值如xmax1245/xmax导致YOLO TXT中width0中心点坐标失效。解决用以下脚本批量校验XMLfor xml in Path(parking_dataset).glob(*.xml): tree ET.parse(xml) for obj in tree.findall(object): bbox obj.find(bndbox) xmin int(bbox.find(xmin).text) xmax int(bbox.find(xmax).text) if xmax xmin: print(f{xml.name} 中 {obj.find(name).text} 框 xmax({xmax}) xmin({xmin}))4.5 现象训练日志显示Class numbers: 0: 1234, 1: 567但类别严重不平衡原因YOLOv8统计的是当前batch内样本数非全局分布。该数据集全局平衡238776 vs 223124但随机采样batch可能短期失衡。解决无需干预观察results.csv中metrics/mAP50(B)列是否稳定上升若300轮后仍低于0.65启用--rect矩形训练模式减少padding失真。4.6 现象导出ONNX模型后推理速度比PyTorch慢2倍原因YOLOv8默认导出动态batch而停车场场景固定单图推理动态shape触发ONNX Runtime反复编译。解决导出时锁定batch维度yolo export modelparking_v8n_300e.pt formatonnx opset12 dynamicFalse。5. 进阶技巧用YOLO输出构建车位状态时序图实现从检测到决策的闭环5.1 从单帧检测到时序状态为什么必须引入帧间关联而非孤立判断停车场空位检测的终极目标不是“此刻哪几个车位空”而是“过去5分钟哪些车位被占用/释放”。单纯依赖单帧YOLO输出会遭遇三大问题抖动噪声同一车位在连续帧中可能被交替判为empty/occupied置信度在0.24↔0.26间波动遮挡误判车辆驶入过程中前3帧可能仅检测到半个车身被判定为empty光照突变云层飘过导致整帧亮度下降occupied置信度集体衰减。解决方案构建滑动窗口状态机以10帧为窗口对每个车位ID维护状态队列。5.2 车位ID绑定技术用OpenCV SIFTRANSAC实现跨帧车位锚定由于摄像头固定所有车位在图像中位置稳定。我们为每个车位分配唯一ID方法如下选取首帧清晰图像用labelImg手动标注所有车位已包含在数据集中firc_car_XXXX.xml即为此用途提取每个bndbox中心点(cx,cy)作为该车位的地理锚点对后续帧用SIFT匹配首帧与当前帧的ORB特征计算单应性矩阵H将所有锚点坐标乘以H投影到当前帧得到实时车位网格。Python实现核心代码import cv2 import numpy as np def get_parking_grid(xml_path): 从XML提取所有车位锚点 tree ET.parse(xml_path) anchors [] for obj in tree.findall(object): bbox obj.find(bndbox) xmin int(bbox.find(xmin).text) ymin int(bbox.find(ymin).text) xmax int(bbox.find(xmax).text) ymax int(bbox.find(ymax).text) cx (xmin xmax) // 2 cy (ymin ymax) // 2 anchors.append([cx, cy, 1]) # 齐次坐标 return np.array(anchors) def match_frames(img1, img2): 计算两帧间单应性矩阵 sift cv2.SIFT_create() kp1, des1 sift.detectAndCompute(img1, None) kp2, des2 sift.detectAndCompute(img2, None) bf cv2.BFMatcher() matches bf.knnMatch(des1, des2, k2) good [] for m, n in matches: if m.distance 0.75 * n.distance: good.append(m) src_pts np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2) dst_pts np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2) H, mask cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0) return H # 使用示例 anchors get_parking_grid(firc_car_2532.xml) # 首帧XML H match_frames(cv2.imread(firc_car_2532.jpg), cv2.imread(firc_car_2533.jpg)) projected H anchors.T # 投影到下一帧 projected projected[:2] / projected[2] # 齐次除法5.3 状态机设计五状态跃迁表与决策阈值定义车位状态FREE空闲、OCCUPIED占用、ENTERING驶入中、LEAVING驶出中、UNKNOWN未识别。状态跃迁规则如下当前状态输入YOLO置信度下一状态触发条件FREEoccupied_conf 0.6ENTERING连续3帧满足ENTERINGoccupied_conf 0.8OCCUPIED连续5帧满足OCCUPIEDempty_conf 0.7LEAVING连续3帧满足LEAVINGempty_conf 0.9FREE连续5帧满足UNKNOWN任意UNKNOWN初始化后首帧注意empty_conf和occupied_conf取自YOLO输出的probs数组非原始置信度而是Softmax后概率。5.4 实时决策输出生成JSON状态流供IoT平台消费最终输出格式每秒1帧{ timestamp: 2024-08-15T14:23:18.123Z, camera_id: parking_lot_A, slots: [ { id: 1, status: OCCUPIED, confidence: 0.92, last_update: 2024-08-15T14:23:17.890Z }, { id: 2, status: FREE, confidence: 0.98, last_update: 2024-08-15T14:23:18.123Z } ] }该JSON可直连MQTT Broker供停车诱导屏或APP实时更新。我一般会用asyncio封装成独立服务每帧处理控制在120ms内RTX3060实测确保不丢帧。从那以后我每次部署新摄像头都强制走一遍SIFT锚点校准状态机阈值标定流程哪怕多花2小时也比上线后被物业投诉“车位状态总不准”强。希望帮到你。本文还有配套的精品资源点击获取
返回列表