☰
YOLOv8停车场违停检测毕设:训练部署全流程解析
2026/10/10 11:29:20 网站建设 项目流程

简介:一份面向计算机视觉毕业设计场景的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 python=3.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。如果只检测违停车辆,nc=1;如果还想检测正常停放车辆,nc=2。这个决定要在训练前定好,否则标注要重改。

train: datasets/images/train val: datasets/images/val nc: 1 names: 0: illegal_parking

names 里的 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 训练接口的封装,所以你可以在命令行直接加参数覆盖默认值。我在自己机器上跑过,最稳的命令是 batch=8、epochs=150、imgsz=640;机器好一点可以上 batch=16,但效果不会线性变好,只是训练时间缩短。

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 里如果写了固定参数,比如 epochs=50,那么命令行传的--epochs不一定会覆盖,因为脚本内部可能是自己定义变量再赋值的。遇到这种时候,直接打开 py 文件,搜索epochs=或batch=,改成你需要的数值。毕设脚本写得再干净,也免不了有几个硬编码,这是常态。

这里给一个等价写法,让你知道脚本内部大概做了什么,方便自己改逻辑:

from ultralytics import YOLO # 加载预训练权重,nano 版本速度最快 model = YOLO('yolov8n.pt') # 开始训练 model.train( data='datasets/parking.yaml', epochs=150, imgsz=640, batch=8, device=0, # 0 表示第一块显卡,CPU 用 'cpu' project='runs/train', name='exp_parking', exist_ok=True, # 允许覆盖同名文件夹 )

device 参数值得单独说:如果你的机器没有 GPU,device='cpu'也能跑,但 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, conf=self.conf_thres, verbose=False)[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, conf=self.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。这个参数没有绝对最优,我通常先用 conf=0.4、iou=0.45 跑一遍,再根据错检漏检调整。

要是界面需要区分“违停”和“正常停车”,就要在训练时定义两个类别。但这份资源的数据集从命名看是单类场景,所以先以一类目标为主。多类别扩展也不麻烦:在 data.yaml 里改 nc=2,并保证 label 文件里的 class id 有 0 和 1,重新训练后 best.pt 就会输出两个类别。

5. 避坑排查:数据、显存、路径与部署中的五个翻车点

这份资源我拆完以后,也帮两个师弟跑过。下面是从实操中记下来的五类高频问题,每一条都是先看到现象,再定位原因,最后给解决路径。做毕设时不用全看,卡在哪就查哪。

5.1 中文路径导致数据集加载失败

现象:训练刚启动,还没进第一个 epoch,终端报 FileNotFoundError 或Assertion 't' failed,提示找不到 parking.yaml。

原因:Windows 下路径里带中文用户名,比如C:\用户\张三\Desktop,ultralytics 的文件处理模块会把中文路径编码搞乱。

解决:把整个工程复制到纯英文路径下,比如D:\yolo_parking,再打开 train_mode.py 把所有相对路径重新确认一遍。如果你机器用户名本身是中文,不要改系统用户名,而是新建一个纯英文目录,比如D:\project,把代码和数据都放进去。

5.2 显存不足与 batch_size 的取舍

现象:训练到第二三个 epoch 时,出现 CUDA out of memory。

原因:batch=16、imgsz=640 时显存占用超过显卡容量,尤其 4G 显存的机器很容易爆。

解决:先降到 batch=4,如果还报错,用 imgsz=480 训练。YOLOv8n 是小模型,batch=8 和 batch=4 的最终 mAP 差距不大,别为了追求 batch 大硬撑。我的习惯是训练前用nvidia-smi看剩余显存,剩余 6G 以上才用 batch=8,3-6G 用 batch=4。

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(format='onnx', opset=12, simplify=True, imgsz=640)",再把生成的 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(format='onnx', opset=12, simplify=True, imgsz=640)"

opset=12 是为了兼容 RKNN、TensorRT 这些工具链,simplify=True 会去掉一些冗余算子。导出完成后生成 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, imgsz=640, verbose=False)[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 都行,同样的输入格式,不用改代码。

从那以后,我每次训练完都会强制走一遍导出验证的流程,因为模型部署不了,界面再漂亮也是空中楼阁。希望这个习惯也能帮到你。

本文还有配套的精品资源,点击获取

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

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

立即咨询