YOLOv8停车场违停检测毕设:训练部署全流程解析 简介一份面向计算机视觉毕业设计场景的YOLOv8停车场车辆占道违停检测项目基于YOLOv8实现车辆检测与占道违停识别适合计算机科学、人工智能、电子信息等专业学生用于毕设、课程设计或项目立项演示。压缩包共8个文件15.91MB含3个py脚本、3个pt权重文件和2个txt说明。py脚本覆盖可视化界面、视频检测与模型训练pt权重含yolov8n.pt、best.pt、yolo11n.pt可直接加载txt含README与使用说明便于快速部署运行。代码全部测试通过运行成功后上传可生成核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果与标签分布图便于毕设答辩展示与分析论证。已有62人关注学习下载后参照说明可复现完整流程也便于二次开发。1. 停车场占道违停检测一个能直接跑通的 YOLOv8 毕设方案做毕设最怕的不是模型难而是拿到项目以后跑步起来。这份基于 YOLOv8 的停车场车辆占道违停检测资源把源码、可视化界面、数据集、部署教程打包在一起解压以后按 README 走训练到演示的链路能直接拉通。它解决的场景很明确监控画面里车辆停在消防通道、非停车区这类占道行为用目标检测模型框出来并给出依据。适合计算机视觉方向的学生做毕设或课设也适合刚学 YOLOv8 的人当练习工程。拆这个工程时第一眼看到 train_mode.py 和 Detection_video.py 这种命名就知道它把训练和检测分开了。yolov8n.pt、yolo11n.pt、best.pt 三个权重既有预训练又有训练好的结果。对答辩来说现场能跑出检测框、能调出混淆矩阵和 PR 曲线远比贴结构图更有说服力。如果你机器上有 Python 和一块显卡按 README 配完依赖就能先跑演示再改数据。基础好一点的话把检测脚本替换成自己的推理服务也方便这套资源本质上是一个可以改装的 YOLOv8 落地骨架。2. 源码包拆解与环境配置先花十分钟把工程点亮2.1 资源里到底有什么文件视角的工程骨架解压 zip 后你看到的不是一个深不可测的框架而是几个职责很清晰的文件。我用目录树把它展开. ├── Visual_interface.py # 可视化界面交互式展示检测结果 ├── Detection_video.py # 视频检测脚本读入图片/视频输出检测结果 ├── train_mode.py # 训练入口指定数据集后开始训练 ├── yolov8n.pt # YOLOv8n 预训练权重 ├── yolo11n.pt # YOLO11n 预训练权重视版本而定 ├── best.pt # 训练得到的最优权重默认推理用它 ├── README.txt # 使用说明第一步先读它 ├── datasets/ # 数据集目录 └── runs/ # 训练输出目录训练后生成这个结构最大的优点是职责分离train_mode.py 负责训练Detection_video.py 负责批量检测Visual_interface.py 负责答辩演示。三个文件正好对应开题、中期、答辩三个阶段要做的事你不需要在不同项目之间来回切换。yolov8n.pt 是 YOLOv8 的 nano 权重模型体积小训练快、显存占用低。yolo11n.pt 是 YOLO11 系列的 nano 权重属于更新的主干如果你的 ultralytics 版本偏老加载 yolo11n.pt 可能会报错这时直接用 yolov8n.pt 训练就行。best.pt 是最终要用的模型正常推理都靠它。下载后第一件事不是双击 py 文件而是打开 README.txt里面一般写了数据集放哪、依赖装什么、先跑哪个脚本。2.2 环境依赖与安装顺序Python、CUDA、ultralytics 怎么对齐这个工程依赖 ultralytics、torch、opencv-python界面部分还需要 PyQt5 这类工具库。常见做法是先建一个干净的 conda 环境避免跟机器上已有的 Python 环境打架。我一般用 Python 3.9因为很多带摄像头调用的 opencv-python 在 3.9 下最稳。conda create -n yolo_parking python3.9 -y conda activate yolo_parking pip install ultralytics pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install opencv-python pyqt5注意--index-url是告诉 pip 用 PyTorch 官方 CUDA 11.8 的源。如果你机器是 NVIDIA 卡且驱动较新也可以直接pip install torch默认会装 CUDA 12 对应版本。训练小模型的话 CPU 也能跑只是慢所以演示阶段还是建议优先用 GPU。装完以后验证一下环境python -c import torch, ultralytics; print(torch.cuda.is_available(), ultralytics.__version__)。如果输出 True 说明显卡被识别如果 False说明装的是 CPU 版 torch需要重装。这一步别跳过很多翻车都是到这里才发现的。版本对齐方面yolov8n.pt 对应 ultralytics 8.0 以上yolo11n.pt 需要 8.3.0 以上。如果训练时报ModuleNotFoundError或者和 yolo11 相关的 KeyError别犹豫把训练脚本里的模型路径改回 yolov8n.pt。这个项目不只一个人改过权重混用的情况很常见认准 best.pt 才是你最终要用的模型。2.3 数据集目录与标注格式训练前必须对齐的三张表标准 YOLO 数据集结构是 images 和 labels 成对出现train 和 val 分开。val 的比例我习惯留 20%如果作者只给了一个总文件夹你最好自己按 8:2 分一下不然训练时的验证指标会失真。datasets/ ├── images/ │ ├── train/ # 训练图片 │ └── val/ # 验证图片 ├── labels/ │ ├── train/ # 对应标注 │ └── val/ # 对应标注 └── parking.yaml # 模型引用的数据集配置parking.yaml 是 train_mode.py 运行时会读取的配置内容很简单就是告诉模型图片在哪个目录、有几个类别。对占道违停检测来说类别数一般只有 1 或 2。如果只检测违停车辆nc1如果还想检测正常停放车辆nc2。这个决定要在训练前定好否则标注要重改。train: datasets/images/train val: datasets/images/val nc: 1 names: 0: illegal_parkingnames 里的 key 要和标注文件里的 class id 对应。标注格式也顺手说明一下每行是class x_center y_center width height坐标全部归一化到 0~1。比如一张 1920x1080 的图车中心在 (960, 540)宽 480高 360那么 txt 里就是0 0.5 0.5 0.25 0.3333。很多人拿到数据集以后不看标注内容直接开训练结果类别对不上、训练 loss 变成 NaN。所以我在训练前会先跑一个小脚本核对图片和 label 文件名是否一一对应import os img_dir datasets/images/train lab_dir datasets/labels/train imgs {os.path.splitext(f)[0] for f in os.listdir(img_dir)} labels {os.path.splitext(f)[0] for f in os.listdir(lab_dir)} print(imgs:, len(imgs), labels:, len(labels)) print(missing labels:, len(imgs - labels)) print(missing images:, len(labels - imgs))如果 missing labels 不是 0说明有些图片没有标注这些图在训练时会被忽略数量多了会影响 mAP。我一般把缺失的图片挪到另一个文件夹而不是直接删掉防止以后想补标注时找不到原图。3. 训练自己的违停检测模型从数据准备到指标曲线3.1 训练脚本怎么改train_mode.py 的常用参数与启动命令train_mode.py 是这份资源的训练入口。它本质上是对 ultralytics YOLO 训练接口的封装所以你可以在命令行直接加参数覆盖默认值。我在自己机器上跑过最稳的命令是 batch8、epochs150、imgsz640机器好一点可以上 batch16但效果不会线性变好只是训练时间缩短。python train_mode.py --data datasets/parking.yaml --epochs 150 --batch 8 --imgsz 640 --model yolov8n.pt --device 0--model可以传 yolov8n.pt 或 yolo11n.pt。如果你想接着上次训练的结果继续练把--model改成runs/train/exp/weights/last.pt这样会继承之前的权重和优化器状态。train_mode.py 里如果写了固定参数比如 epochs50那么命令行传的--epochs不一定会覆盖因为脚本内部可能是自己定义变量再赋值的。遇到这种时候直接打开 py 文件搜索epochs或batch改成你需要的数值。毕设脚本写得再干净也免不了有几个硬编码这是常态。这里给一个等价写法让你知道脚本内部大概做了什么方便自己改逻辑from ultralytics import YOLO # 加载预训练权重nano 版本速度最快 model YOLO(yolov8n.pt) # 开始训练 model.train( datadatasets/parking.yaml, epochs150, imgsz640, batch8, device0, # 0 表示第一块显卡CPU 用 cpu projectruns/train, nameexp_parking, exist_okTrue, # 允许覆盖同名文件夹 )device 参数值得单独说如果你的机器没有 GPUdevicecpu也能跑但 nano 模型 640 输入100 epoch 可能要十几个小时。大部分毕设机器哪怕是 GTX 1660 Ti 6G也会比纯 CPU 快 5 倍以上。有卡就优先用卡别拿时间硬扛。3.2 训练流程与产物best.pt、yolov8n.pt、yolo11n.pt 分别干什么训练启动后ultralytics 会先把数据集的标签统计出来生成一张标签分布图然后逐 epoch 迭代。每跑完一个 epoch用验证集算一次 Precision、Recall、mAP50、mAP50-95之后把所有曲线写进 runs/train/exp 目录。这个过程中你不太需要盯着控制台重点是看 results.png 里的曲线变化。训练结束时weights 目录下会生成两个文件best.pt 和 last.pt。best.pt 是验证集 mAP 最高的那个 epoch 的权重last.pt 是最后一个 epoch 的权重。如果你只想做演示用 best.pt 就够了如果你想续训才用 last.pt。yolov8n.pt 是起始预训练权重负责给你 COCO 上的先验best.pt 是你的停车场场景下的最终模型yolo11n.pt 是作者放进去的另一个预训练选择。三个名字看起来像实际职责完全不同。训练完以后推理路径只认 best.pt不要再改回 yolov8n.pt否则检测框会变得特别稀疏因为你用的是没有微调的 COCO 检测器。3.3 核心指标曲线怎么读混淆矩阵、F1、PR 的答辩语言训练结束后runs/train/exp 目录下会有一堆图。评审老师最容易抓住提问的是这几张混淆矩阵、F1 曲线、PR 曲线、验证集预测结果。你有必要提前准备好怎么讲。混淆矩阵 confusion_matrix.png 的横轴是预测类别纵轴是真实类别对角线的值越接近 1说明这个类别分得越准。占道违停检测如果只有一类矩阵就是一个 1x1 的方块加一个 background 列真正要看的其实是 background 被误检成车辆的比例。如果 background 那一列有数字说明模型把路沿、树影当成了车这时候需要增加负样本或者提高置信度阈值。F1_curve.png 和 PR_curve.png 都适合放进答辩 PPT。F1 曲线是置信度阈值从 0 到 1 变化时 F1 值的变化峰值对应的阈值就是理论上最优的 conf。PR 曲线下的面积就是 AP面积越大越好。我一般会圈出 PR 曲线上靠近左上角的位置跟老师说“我在阈值为 0.4 附近取得精度和召回率的平衡”。评委一听就知道你确实自己调过模型。val_batch 开头的图片是验证集的可视化结果上面有预测框和置信度。把这些图和真实标注放在一起看能直观知道哪些车漏检了。停车场的漏检通常发生在两类情况车身颜色和路面相近、两车紧贴停靠形成一个长框。遇到前者增加白天不同光线的训练图片遇到后者可以在后处理里降低 NMS 阈值让两个紧密框不被合并。4. 可视化页面与视频检测从权重文件到可演示界面4.1 可视化页面设计Visual_interface.py 的界面逻辑与调用方式Visual_interface.py 是这份资源里最容易被忽略的部分。很多学生拿到手只跑 train_mode.py训练完就不知道该给老师展示什么。其实这个脚本把界面和模型串起来了你在界面上点几个按钮就能实时看到检测框。典型的界面逻辑是三段式加载模型、打开视频或图片、显示结果。界面左边是操作区右边是视频画面。用 PyQt5 实现时核心是定时器不断从 OpenCV 的 VideoCapture 读帧然后把帧送进模型结果转成 QImage 显示在 QLabel 上。代码结构通常长这样import cv2 from ultralytics import YOLO from PyQt5.QtGui import QImage, QPixmap class ParkingApp: def __init__(self): self.model YOLO(best.pt) self.conf_thres 0.4 def process_frame(self, frame): results self.model(frame, confself.conf_thres, verboseFalse)[0] annotated results.plot() # 画框后的 BGR 图 rgb cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB) h, w, ch rgb.shape img QImage(rgb.data, w, h, ch * w, QImage.Format_RGB888) return QPixmap.fromImage(img)这里model(frame, confself.conf_thres)返回的结果带有一个plot()方法会直接把框、类别名、置信度画在拷贝图上不用自己写绘制框的代码。如果你想在界面上额外显示“当前检测到 N 辆车”可以遍历 results.boxes.cls 统计。注意 QImage 的 bytesPerLine 参数是ch * w很多教程写成w导致图片显示成斜条纹或者颜色错位。这句是我在 PyQt5 里最容易踩的坑先写在这给你避雷。4.2 视频检测脚本Detection_video.py 的输入输出与参数Detection_video.py 面向的是批量处理场景比如你有一段停车场监控视频想快速得到一段带框的输出视频。它和可视化界面的区别是不需要交互纯命令行跑完就走。常见调用方式是这样python Detection_video.py --source test_video.mp4 --weights best.pt --conf 0.4 --save --device 0--source可以传视频文件、图片文件夹、摄像头编号。摄像头传 0 表示本机第一个摄像头在答辩现场演示时很有用。--save的意思是保存结果到 runs/detect/predict 目录默认文件名是 exp 加序号。如果不加--save只会在终端打印检测结果和 FPS旁边的人看不到画面所以演示时记得加--save或者配合显式窗口显示。如果 Detection_video.py 本身不支持命令行参数而你需要换模型就打开脚本搜索YOLO(这一行把它替换成YOLO(best.pt)。这类脚本往往把模型路径写死在文件里不要犹豫直接改。4.3 把检测结果接到界面上置信度阈值与类别过滤的四个参数检测场景的效果由几个参数决定我列成一张表方便你对着调参数建议值说明conf0.35-0.45停车场遮挡多阈值太高会漏检iou0.45-0.6IOU 越高越不容易合并相邻车辆框imgsz640训练用的输入尺寸不要随便改大device0显卡编号CPU 推理改成cpu如果画面上出现大量重复框就把 iou 调低一点比如 0.3如果车辆被切成了半个框就把 iou 调高比如 0.7。这个参数没有绝对最优我通常先用 conf0.4、iou0.45 跑一遍再根据错检漏检调整。要是界面需要区分“违停”和“正常停车”就要在训练时定义两个类别。但这份资源的数据集从命名看是单类场景所以先以一类目标为主。多类别扩展也不麻烦在 data.yaml 里改 nc2并保证 label 文件里的 class id 有 0 和 1重新训练后 best.pt 就会输出两个类别。5. 避坑排查数据、显存、路径与部署中的五个翻车点这份资源我拆完以后也帮两个师弟跑过。下面是从实操中记下来的五类高频问题每一条都是先看到现象再定位原因最后给解决路径。做毕设时不用全看卡在哪就查哪。5.1 中文路径导致数据集加载失败现象训练刚启动还没进第一个 epoch终端报 FileNotFoundError 或Assertion t failed提示找不到 parking.yaml。原因Windows 下路径里带中文用户名比如C:\用户\张三\Desktopultralytics 的文件处理模块会把中文路径编码搞乱。解决把整个工程复制到纯英文路径下比如D:\yolo_parking再打开 train_mode.py 把所有相对路径重新确认一遍。如果你机器用户名本身是中文不要改系统用户名而是新建一个纯英文目录比如D:\project把代码和数据都放进去。5.2 显存不足与 batch_size 的取舍现象训练到第二三个 epoch 时出现 CUDA out of memory。原因batch16、imgsz640 时显存占用超过显卡容量尤其 4G 显存的机器很容易爆。解决先降到 batch4如果还报错用 imgsz480 训练。YOLOv8n 是小模型batch8 和 batch4 的最终 mAP 差距不大别为了追求 batch 大硬撑。我的习惯是训练前用nvidia-smi看剩余显存剩余 6G 以上才用 batch83-6G 用 batch4。5.3 best.pt 与 last.pt 选错导致演示效果差现象用训练好的模型跑视频检测框非常少车辆只框出一半。原因你说用“训练好的” last.pt但最后一个 epoch 的权重不一定最优过拟合或训练不充分都会让它效果变差。解决推理时一定要指定 best.pt最好在 Detection_video.py 里直接写死 best.pt 路径。训练完以后在 runs/train/exp/weights 目录确认两个文件都存在如果只有 last.pt说明训练被中断用 last.pt 续训几个 epoch 再重新评估。更稳妥的做法是把 best.pt 单独复制到项目根目录让脚本引用根目录的模型。5.4 可视化界面启动失败依赖缺失与 OpenCV 版本冲突现象运行 Visual_interface.py 直接闪退或者在 import cv2 时报错安装 opencv-python 后又出现 Qt 相关报错。原因界面脚本同时依赖 OpenCV 和 PyQt5如果两个库单独安装版本不匹配会导致 QImage 转换失败。另一个常见情况是 opencv-python 和 opencv-contrib-python 同时存在这两个包会抢同一套 DLL导致奇怪崩溃。解决重新安装 PyQt5 和 opencv-python并使用 ultralytics 的plot()方法代替手写画框。如果还闪退就在终端运行python Visual_interface.py看具体报错模块。如果装了 contrib 包先pip uninstall opencv-python opencv-contrib-python只保留其中一个。5.5 部署到 RK3588 时的算子兼容问题现象把 best.pt 转成 rknn 后在 RK3588 上推理结果全是乱框或者完全没有输出。原因YOLOv8 的 DFL 结构计算距离回归直接导出的 ONNX 里包含一些 RKNN 工具链不友好的算子。如果导出时没有做简化和特定 opset 设置转出来的模型后处理就不对。解决先在 ultralytics 里导出 onnx命令是python -c from ultralytics import YOLO; YOLO(best.pt).export(formatonnx, opset12, simplifyTrue, imgsz640)再把生成的 best.onnx 交给 rknn-toolkit2 转换配置里选择 post_process 为 yolo11 或 yolov8 对应版本。这条对大多数人来说属于进阶操作但如果你的毕设题目里写了“嵌入式部署”这就是必踩的坑。建议把导出的 onnx 先用 onnxruntime 在电脑上跑一遍确定框的位置和 PyTorch 推理一致再转 rknn。否则你在板子上调一整天也分不清是量化问题还是导出问题。6. 进阶技巧导出 ONNX 并用 TensorRT 提速顺手验证整个流程如果训练完、界面也跑通了你还可以做一件让答辩加分的事把 best.pt 导出成 ONNX再用 TensorRT 加速。这样能顺便验证训练的模型能不能脱离 PyTorch 独立运行——很多评委喜欢问“你这个模型部署到服务器上用什么推理框架”你有实测结果比背台词有说服力。导出 ONNX 的命令一行就够python -c from ultralytics import YOLO; YOLO(best.pt).export(formatonnx, opset12, simplifyTrue, imgsz640)opset12 是为了兼容 RKNN、TensorRT 这些工具链simplifyTrue 会去掉一些冗余算子。导出完成后生成 best.onnx体积通常比 best.pt 小一些而且不依赖 PyTorch。验证导出模型是否正确的脚本也很简单用 onnxruntime 跑一张图看输出的形状是不是[1, 84, 8400]或类似结构。如果输出维度不对多半是 opset 没设对或 simplify 过度清理。我一般会写一个小脚本对比 PyTorch 和 ONNX 对同一张图的框坐标误差误差超过 1% 就换导出参数。import cv2 import onnxruntime as ort import numpy as np from ultralytics import YOLO img cv2.imread(demo.jpg) img_resized cv2.resize(img, (640, 640)) input_tensor img_resized[:, :, ::-1].transpose(2, 0, 1)[None].astype(float32) / 255.0 ort_sess ort.InferenceSession(best.onnx) onnx_out ort_sess.run(None, {ort_sess.get_inputs()[0].name: input_tensor})[0] print(onnx output shape:, onnx_out.shape) # 用 PyTorch 推理得到框坐标与 onnx 输出对比 model YOLO(best.pt) torch_out model(img_resized, imgsz640, verboseFalse)[0] print(torch boxes:, torch_out.boxes.xyxy.cpu().numpy()[:2])这里 input_tensor 的格式是 NCHW、RGB、归一化到 0~1这是 ultralytics 导出模型时约定的输入格式。onnx_out 是原始预测张量后续 NMS 可以直接用 ultralytics 库里的ops.nms处理也可以在自己写的部署代码里补充。如果要再转 TensorRT engine用 trtexec 或 onnx-tensorrt 都行同样的输入格式不用改代码。从那以后我每次训练完都会强制走一遍导出验证的流程因为模型部署不了界面再漂亮也是空中楼阁。希望这个习惯也能帮到你。本文还有配套的精品资源点击获取