YOLOv8停车场违规占道检测实战:从环境搭建到部署避坑
简介一套基于YOLOv8的停车场违规占道车辆检测系统项目聚焦深度学习目标检测方向面向计算机相关专业学生的毕业设计、课程设计或初期项目演示可实时识别停车场内违规占道车辆配合可视化页面和完整数据集简单部署即可运行。压缩包为zip格式共含8个文件主要包含3个Python源码覆盖可视化界面、模型训练与视频检测、3个PyTorch权重文件和2个说明文档整体大小仅15.91MB目录结构清晰便于按模块查阅与调用。目前已有58人学习下载适合需要快速搭建完整检测流程的初学者或答辩项目。项目附带可视化页面、部署教程和完整数据集运行后可产出核心指标曲线、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果及标签分布图为毕设评审或课程展示提供直观数据支撑同时省去从零搭建环境和反复调参的麻烦拿来即用的完整方案可信赖。1. 停车场违规占道检测是什么一个 YOLOv8 就能撑起的课设项目值班室里的大屏上消防通道被一辆 SUV 堵了半个多小时等安保人员从几十路监控画面里发现时车已经开走了。这种场景在停车场管理里太常见也是计算机视觉课程设计里最容易做出成果的题目之一。标题这个项目本质就是拿 YOLOv8 做目标检测把画面里的车辆分成两类正常泊位里的车和违规占道的车再用一个可视化界面把推理结果框出来。拿到这类压缩包先别急着点训练按钮按“环境搭建 → 数据核查 → 权重推理 → 界面部署”四步走一周内把功能跑通完全来得及。适合毕设也适合课程设计里需要演示系统的同学。2. 本地复现环境搭建、项目结构和一个最小推理命令2.1 运行环境CPU 版也能跑独立环境是省事后悔药这个项目能不能快速跑起来环境配置占一半。项目包里的部署教程通常会要求 Python 3.9 左右的版本搭配 PyTorch 和 ultralytics 包。我的做法是先建一个独立 conda 环境绝不在 base 环境里直接装否则后面装 opencv、pandas 时版本冲突能把人逼疯。conda create -n parking python3.9 -y conda activate parking pip install ultralytics pip install torch torchvision第一条命令创建一个干净的 Python 3.9 环境第二条激活它第三条安装 ultralytics 这个核心依赖它会顺带把推理所需的组件装好。第四行把 torch 和 torchvision 补齐注意这里默认装的是 CPU 版本能跑只是训练会慢。如果你的机器有 NVIDIA 显卡需要先确认驱动支持的 CUDA 版本再重新装对应版本的 PyTorch。不少人在 Ubuntu 20.04 上搭建 YOLOv8 环境时图省事直接一键装结果 import 阶段就报错都是因为 torch 和 CUDA 版本对不上。环境装完先跑一个小脚本确认 torch 真的看到了显卡。这一步是一次验证跳过的话训练跑了一半才发现用的是 CPU白白浪费时间。import torch print(torch:, torch.__version__) print(cuda available:, torch.cuda.is_available()) print(device name:, torch.cuda.get_device_name(0) if torch.cuda.is_available() else CPU)这段脚本就是检查两件事当前环境的 torch 是什么版本以及 CUDA 是否可用。如果打印出 cuda available: False说明你装的是 CPU 版 torch不是显卡有问题。后续训练时 device 参数写 0 是没有意义的必须先把 torch 的版本换掉。2.2 项目结构从训练脚本到界面程序先分清四个模块YOLOv8 停车场检测这类项目压缩包里文件结构大同小异通常围绕训练、推理、界面、数据四个部分展开。parking-detection/ ├── train.py # 训练入口 ├── detect.py # 命令行推理 ├── ui_main.py # 可视化界面 ├── requirements.txt # 依赖清单 ├── weights/ │ └── best.pt # 训练好的模型权重 ├── dataset/ │ ├── images/ │ │ ├── train/ │ │ └── val/ │ └── labels/ │ ├── train/ │ └── val/ └── parking.yaml # 数据集配置文件先把这六个部分认清楚再运行任何代码。train.py 负责重训模型detect.py 负责对单张图片或视频做推理ui_main.py 是界面程序weights/best.pt 是已经训练好的权重dataset 是标注数据parking.yaml 告诉 YOLOv8 数据路径和类别名。很多同学一上来就双击 train.py完全忽略 weights 里已经有个能用的模型这没必要。项目包既然带了 best.pt就说明作者已经跑通过一遍你的第一目标是复现推理效果不是重新发明轮子。2.3 最小推理先用 best.pt 跑通别把代码当黑匣子拿到项目先跑一次推理确认模型路径、图片路径和输出结果都没问题再往后研究界面和训练。python detect.py \ --source dataset/images/val/000012.jpg \ --weights weights/best.pt \ --conf-thres 0.30 \ --iou-thres 0.45 \ --device 0这条命令的意思是对验证集里的某一张图片做检测置信度阈值 0.30两个框重叠度超过 0.45 就做 NMS 合并。如果电脑没有 GPU把 --device 0 改成 --device cpu。跑通之后你会看到输出目录里生成了一张带框图片违规占道车辆被标出来。这个阶段的重点是确认流程不是调指标。conf-thres 设 0.30 只是先看看结果真实的停车场场景我更建议把它降到 0.15 到 0.25因为监控视角下车身小、遮挡多置信度普遍偏低。如果压到 0.10 还是一辆车都不框那问题不在阈值而在权重和图片本身后面避坑章节会专门说。把这一步跑通了项目代码对你来说就不是黑匣子了。3. 数据是地基YOLO 标注格式、类别失衡与坏样本排查3.1 标签文件长什么样中心点坐标和类别编号别搞反处理数据集用于 YOLOv8 训练第一步是看懂标签格式。YOLO 系列用的是 txt 标注每一行描述一个目标五个字段分别是类别编号、目标中心点 x 坐标、中心点 y 坐标、目标宽度、目标高度。x、y、w、h 都是归一化到 0 到 1 的相对值不是像素坐标。# dataset/labels/train/000012.txt 0 0.513 0.426 0.211 0.264 1 0.782 0.315 0.158 0.221第一行的 0 代表类别编号对应的是正常停放车辆后面的四个数字表示框的中心点在这个图像的 51.3% 和 42.6% 位置宽度占全图 21.1%高度占 26.4%。第二行类别是 1也就是违规占道车辆。项目里的 parking.yaml 会定义类别的具体名字。path: dataset train: images/train val: images/val names: 0: normal_parked 1: illegal_occupied这段配置让训练脚本知道训练集和验证集在哪以及每个编号对应的类别名。names 的顺序非常关键训练和推理时必须保持一致。项目包里的界面如果显示类别名对不上优先检查这里是不是被改过。另外如果数据集最初是用 labelme 这类工具标注的 JSON需要先转成 YOLO 格式的 txt 再训练。转换时最容易出的问题是把 JSON 里的类别名顺序和编号映射搞错转完居然和原图对不上。3.2 类别失衡先统计再补数据违规样本往往只有零头停车场场景里正常停放车辆的数量会远远大于违规占道车辆。一个停车场摄像头画面里可能二十辆车只有一辆压在消防通道上这种天然的类别不平衡会让模型倾向于把所有车都预测成正常停放。训练之前一定要先数一数各类别到底有多少框。import os from collections import Counter label_dir dataset/labels/train counter Counter() total_boxes 0 for name in os.listdir(label_dir): if not name.endswith(.txt): continue with open(os.path.join(label_dir, name), r, encodingutf-8) as f: for line in f: line line.strip() if line: cls int(line.split()[0]) counter[cls] 1 total_boxes 1 print(各类别框数:, dict(counter)) print(总标注框数:, total_boxes)这个脚本遍历训练集所有标签文件统计类别 0 和类别 1 的框数。如果违规占道样本不到正常样本的 20%模型大概率会翻车。补数据不是只能靠手动标注常见做法是把包含违规车辆的关键片段每隔十秒抽一帧加入训练集或者对现有违规样本做亮度、平移、旋转增强。需要注意的是停车场画面里车位线和车道方向有强先验水平翻转增强不一定适用镜像后车辆出现在原本不可能出现的车道位置反而误导模型学习位置规则所以增强策略要按场景选。类别占比情况典型后果建议做法违规框少于正常框的 10%模型几乎不预测违规类补充样本或做针对性增强占比在 10%25% 之间能检出但召回率偏低添加类别权重或启用数据增强占比超过 30%训练曲线相对健康正常训练关注夜间样本覆盖3.3 坏样本排查把中心点坐标还原成可视化框标注文件里的数字对不对光看 txt 很难发现问题。写一个可视化脚本把所有标签画回原图再看一遍是处理数据集最关键的一步。import cv2 import os img_dir dataset/images/val label_dir dataset/labels/val out_dir check_vis os.makedirs(out_dir, exist_okTrue) class_names [normal_parked, illegal_occupied] for name in os.listdir(img_dir): if not name.lower().endswith((.jpg, .jpeg, .png)): continue img cv2.imread(os.path.join(img_dir, name)) h, w img.shape[:2] txt_path os.path.join(label_dir, os.path.splitext(name)[0] .txt) if not os.path.exists(txt_path): print([warn] 缺失标签:, name) continue with open(txt_path, r, encodingutf-8) as f: for line in f: parts line.strip().split() if len(parts) ! 5: print([warn] 格式异常:, name, line.strip()) continue cls int(parts[0]) xc, yc, bw, bh map(float, parts[1:]) x1 int((xc - bw / 2) * w) y1 int((yc - bh / 2) * h) x2 int((xc bw / 2) * w) y2 int((yc bh / 2) * h) color (0, 0, 255) if cls 1 else (0, 255, 0) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) cv2.putText(img, class_names[cls], (x1, y1 - 6), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1) cv2.imwrite(os.path.join(out_dir, name), img)这段脚本把验证集所有标注框用红色和绿色画回原图。红色是违规车辆绿色是正常停放。归一化坐标还原回像素坐标时一定要先乘以宽高再减半宽半高得到左上角坐标。跑完检查几个容易出错的位置框是不是刚好包住车身有没有把旁边车辆框进去有没有画到墙上或树上。这个步骤花半小时能省下后面训练返工的好几天。看到标注框歪七扭八就回头改标签工具或标注规范不要急着开训练。4. 重训一套自己的权重训练命令、参数表与损失曲线判读4.1 训练命令从 data.yaml 到 batch、imgsz 参数的确定方法项目自带的权重通常是在作者的数据集上训练的换一个停车场环境效果会打折扣。想训练自己的数据集核心命令就是下面这一条。yolo detect train \ dataparking.yaml \ modelyolov8n.pt \ epochs100 \ batch16 \ imgsz640 \ device0 \ patience20 \ optimizerAdamWdataparking.yaml 指向刚才确认好的数据集配置文件modelyolov8n.pt 表示用 YOLOv8n 作为基础模型在本项目数据集上继续微调。n 是 nano 版本占用资源最少适合 6GB 显存左右的显卡。如果你的显卡是 16GB 显存可以考虑换 yolov8s.pt 提升精度。batch 参数决定每轮喂给模型的图片数量显存越小 batch 越小在 GTX 1660 Ti 这类 6GB 显卡上batch 16 跑 640 分辨率有点吃力建议降到 8或者把 imgsz 改成 480。imgsz 是输入图像分辨率。停车场摄像头通常是高空俯视角车辆在画面里偏小imgsz 从 640 升到 800 能明显提升小目标召回代价是训练时间增加一半左右。patience 是早停参数意思是验证集指标连续 20 轮没有进步就停止训练防止后期浪费时间。AdamW 是优化器多数场景下比默认的 SGD 收敛更稳对新手更友好。训练过程中注意看终端打印的进度条。如果报 CUDA out of memory第一步把 batch 减半再不行把 imgsz 降到 480。如果训练一切正常但损失曲线抖动得很厉害降低学习率常见做法是从默认的 0.01 改成 0.005。训练结束后结果会保存在 runs/detect/train/ 目录下里面的 weights/best.pt 就是你要用的权重。4.2 损失曲线results.csv 画出的四种曲线怎么读YOLOv8 训练过程中会自动记录每个 epoch 的损失值和评估指标存在 runs/detect/train/results.csv 里。不要只看训练结束时的打印信息把曲线画出来才能看清楚模型有没有真的学会。import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/detect/train/results.csv) fig, axes plt.subplots(1, 2, figsize(12, 4)) axes[0].plot(df[train/box_loss], labeltrain box_loss) axes[0].plot(df[val/box_loss], labelval box_loss) axes[0].set_title(box loss) axes[0].legend() axes[1].plot(df[metrics/mAP50(B)], labelmAP50) axes[1].set_title(mAP50) axes[1].legend() plt.tight_layout() plt.savefig(loss_curve.png, dpi150)这段脚本读取 results.csv画出边界框损失曲线和 mAP50 曲线。不同的 ultralytics 版本列名略有区别如果报 KeyError先打印 df.columns 看实际列名再改脚本都行。判断训练是否正常看两点box_loss 是否整体下行mAP50 是否逐步上升。如果训练损失降了但验证损失不降是过拟合需要增加数据或减小模型复杂度。如果最后几个 epoch 突然掉点往往是 mosaic 增强在最后一轮才关闭训练时加一行 close_mosaic10给模型最后 10 轮一个稳定的学习窗口这个细节能救回不少精度。4.3 小目标与俯视角提升违规类别的两项增强策略停车场监控视角有个典型问题车小、视角固定、密集排列。按默认参数训练完正常停放车辆往往检得很好违规占道车辆会漏因为违规样本数量少且常常出现在画面边缘或远处。第一个有效手段是提高推理分辨率。640 分辨率下远处的车可能只有 30 乘 40 像素模型很难学。把 imgsz 改成 800 甚至 960小目标特征保留得更多mAP 提升往往是肉眼可见的。显存不够就别硬扛换 YOLOv8n 模型或者在界面推理时保持训练尺度一致不要在推理时擅自压缩图片尺寸。第二个手段是关闭水平翻转。YOLOv8 默认开启 fliplr 增强但停车场地面有车道线和方向标识违规占道多半和特定位置强相关。镜像翻转后车出现在实际不可能出现的车道上等于给模型喂错误的空间先验。训练参数里加一句 flipud0.0 fliplr0.0通常会有惊喜。还有一个容易忽略的点项目数据集如果只有几百张图别急着大改参数。先拿预训练权重在真实监控截图上跑一遍把漏检错检的图挑出来补充到训练集比加增强更有效。5. 部署期高频坑环境冲突、空框、漏检与 mAP 虚高的排查5.1 环境与依赖import 报错和 torch 版本冲突现象代码一运行就报 ModuleNotFoundError: No module named ultralytics或者 torch 和 torchvision 版本不匹配导致 import 崩溃。原因大多数情况是在 base 环境里随意 pip install装到一半版本冲突或者 Python 版本本身太高比如 3.12 下有些旧版 opencv 编译不过去。极少是代码本身的问题。解决彻底删掉原来的环境重新走一遍第 2 章的环境步骤。强烈建议固定 Python 3.9先装 torch 再装 ultralytics最后按 requirements.txt 补剩余依赖。不要用 conda 装一半、pip 装一半两条包管理器的混用是这个坑的主要来源。5.2 推理端空框置信度阈值、压缩尺寸与类别名错位现象界面里选了一张包含车辆的图片结果一个框都不画或者只有正常车辆框、没有违规车辆框。原因有三个方向按出现频率排序置信度阈值设太高模型对违规车辆的置信度只有 0.2阈值设置 0.3 就全被滤掉了界面把输入图片压缩到很小比如降到 320 分辨率再推理小目标直接丢了类别名映射错乱界面程序里的标签列表顺序和 parking.yaml 里 names 顺序不一致模型预测类别 1界面却显示成类别 0 的颜色和名称。解决先把置信度降到 0.10 做一次推理能框出来就是阈值问题再按场景逐步调回 0.20 左右。图片尺寸问题在界面代码里找推理函数入口确认传给 model 的图片没有经过大比例 resize。类别映射问题用一张已知违规车辆的图片跑 detect.py再把界面结果和命令行结果对比看类别是否一样。注意推理环境、训练环境和界面程序的环境最好保持同一套依赖版本否则容易出现训练时正常、部署时结果不对的怪问题。5.3 数据侧翻车重复帧、标注框不一致带来的假性高指标现象训练时 mAP50 显示 0.9 以上觉得模型很完美一到真实停车场视频里就大量漏检密集误报完全不是测试集那个效果。原因这是项目数据集最常见的坑。数据采集通常来自同一段监控视频如果按连续帧截图训练集和验证集里会出现大量极度相似的画面模型实际上在记忆场景而不是学习车辆特征。另一个问题是标注规范不一致有些人画框包含整个车身包括后视镜有些人只画车头模型的回归目标乱了验证集又恰好和训练集风格一致指标自然虚高。解决重新划分数据集按时间抽帧而不是按连续帧截图。常见做法是每 10 秒取一帧再用感知哈希算法去掉相似度高的图像。标注方面统一规范画车辆外接矩形包含两侧后视镜不包含旁边车辆和阴影。做完这两件事再重训一轮你会发现 mAP 可能降到 0.7 以下但真实场景的可用性反而明显上升。指标好看不等于模型好用这是毕设答辩时最值得拿出来讲的认知。5.4 硬件资源踩坑显存不够和 CPU 硬跑的识别率差异现象训练时直接报 CUDA out of memory或者被迫一直用 CPU 训练跑了一整天还没完。原因显存规划不合理。6GB 显存硬跑 YOLOv8s 加 640 分辨率加 batch 16已经超出物理限制。CPU 模式不是不能跑是训练效率极低而且部分同学等到答辩前两周才发现连调整的机会都没有。解决先看模型大小再定参数。6GB 显存用 YOLOv8nbatch 8imgsz 640稳妥起步。如果显存还是爆就把 imgsz 降到 480。训练之前用 nvidia-smi 看一次显存占用确认没有其他程序占着显存再启动。另外输出目录 runs/detect 下的中间权重文件会占用不少磁盘空间训练前检查磁盘剩余容量。5.5 界面程序跑不起来路径问题和缺失依赖现象命令行推理正常但打开界面就闪退或报错。界面里的图片选择框打开目录后没有预览部分按钮点了没反应。原因项目界面程序通常用 PyQt5 或 Tkinter 实现路径处理比较脆弱。权重路径、数据集路径可能硬编码成了作者的绝对路径换台电脑就失效。图片选择框默认路径指向作者电脑上的文件夹找不到目录就直接崩溃。解决先打开界面脚本搜索 .pt、/home、C:\ 这类绝对路径写法全部改成相对路径或用一个配置文件统一管理。界面打不开图片预览时检查所选目录是否包含 jpg、png 文件以及系统是否有中文字体支持。把命令行推理跑通作为前置条件界面只是一个壳子模型部分才是核心不要花太多时间在美化上。6. 进阶验证把模型接进监控视频流测真实误检率与帧率6.1 用脚本接管视频流抽帧、推理与违规统计停车场检测最终要面对的不是一张张图片而是连续的视频流。界面程序通常已经内置了视频检测但拿它做效果评估不够直观。我习惯写一个独立的脚本直接读取摄像头 RTSP 流或本地视频把违规目标出现的次数统计出来。import cv2 import time from ultralytics import YOLO rtsp_url rtsp://192.168.1.64/stream1 # 换成实际摄像头地址或本地视频路径 model YOLO(weights/best.pt) cap cv2.VideoCapture(rtsp_url) fps cap.get(cv2.CAP_PROP_FPS) or 25 interval int(fps * 0.5) # 每 0.5 秒抽一帧 frame_id 0 illegal_count 0 total_count 0 while True: ret, frame cap.read() if not ret: print(stream interrupted) break if frame_id % interval ! 0: frame_id 1 continue result model(frame, conf0.15, verboseFalse)[0] boxes result.boxes illegal sum(1 for c in boxes.cls if int(c) 1) illegal_count illegal total_count 1 frame_id 1 print(抽帧次数:, total_count) print(检到违规目标次数:, illegal_count)这段脚本的逻辑是按帧读取视频流每 0.5 秒选一帧送入模型推理统计检出的违规目标数量。用时间间隔抽帧而不是逐帧推理是因为 YOLOv8 在 CPU 上无法保证实时处理 1080p 视频抽帧评估更务实。interval 按视频帧率计算保证不管摄像头是 25 帧还是 30 帧都是每 0.5 秒检测一次。推理时 conf 设 0.15比训练时更宽松宁可多一点误报也要保证违规不落网。6.2 三个评估口径真实 FPS、无效帧参与夜间场景测试报告里除了 mAP还应该记录三项实测数据。第一个是真实 FPS用当前帧时间戳减去上一帧时间戳一秒钟能处理几帧就是几帧不要信模型接口文档里的理论值。第二个是无效帧率cap.read 偶尔会返回 false这在无线摄像头流里很常见无效帧率超过 5% 就需要检查网络。第三个是显存占用训练和推理阶段分别看一次 nvidia-smi避免部署时显存泄漏导致运行几小时后卡死。停车场检测真正的检验场是夜间场景。很多项目训练数据集中在白天夜间低光照下车辆特征丢失严重误检率会明显上升。我现在拿到任何模型习惯先找三段与训练集无关的视频做盲测一段白天、一段夜间、一段雨天跑完再看统计数据不只看训练曲线。评估口径对了训练参数才有调整依据。这套思路对毕设答辩或者项目验收都很有说服力希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →