简介:这份资源是面向计算机、人工智能、通信工程、自动化等专业学生与教师的YOLOv8目标检测实战项目,聚焦停车场违规占道车辆识别场景,可用于毕业设计、课程设计、大作业或项目立项演示。压缩包共8个文件,约15.91MB,包含3个Python脚本、3个模型权重文件与2个说明文本,分别对应可视化界面、模型训练、视频检测推理及部署说明等模块,结构清晰、便于快速上手。项目已完整测试运行,附带数据集、可视化页面与部署教程,可生成核心指标曲线、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果及标签分布图,帮助读者直观理解模型训练与评估流程。目前已有58人学习下载,适合希望掌握YOLOv8训练、推理与可视化全流程的读者参考,也可在此基础上修改扩展实现其他检测功能。
1. 停车场违规占道检测:为什么 YOLOv8 是当前最省事的落点
地下停车场里最让人头疼的不是车位少,而是消防通道、转弯盲区、出入口被长期占道。物业靠人巡逻,一圈下来半小时,等发现时车早走了。用固定摄像头加一套 YOLOv8 车辆检测系统,就能把这件事变成自动告警:摄像头画面进来,模型框出车辆,再叠加一个多边形区域判断,落在禁停区里的车直接标红并记录时间。这套思路对应的就是《基于YOLOv8的停车场违规占道车辆检测系统》,它把源码、可视化界面、完整数据集和部署教程打包在一起,目标是简单部署即可运行,适合毕设或课程设计。
我选 YOLOv8 而不是 Faster R-CNN 或 SSD,理由很实际:Ultralytics 这套框架把训练、验证、导出、推理全串成一条命令,环境配置的坑少;模型从 n 到 x 有多个尺寸,GTX1660Ti 这种老卡也能跑 n 或 s 版本;检测头是 anchor-free 的,对小目标和遮挡场景比早期 YOLO 稳。停车场场景里车辆尺度变化大、光线差、常有柱子遮挡,YOLOv8 的 CSP 主干加 PAN-FPN 结构能兼顾速度和召回。下面按「数据怎么准备 → 模型怎么训 → 界面怎么搭 → 坑在哪」的顺序讲透,新手能照着跑,熟手能看到参数边界。
2. 数据集准备:从公开车辆数据集到停车场禁停区标注
2.1 为什么不能直接拿 BDD100K 或 CCPD 开训
很多人第一反应是去下 BDD100K 或 CCPD 数据集,觉得车辆样本多。但这两个数据集和停车场违规占道场景差得远。BDD100K 是自动驾驶路测数据,视角是行车记录仪,车辆尺度大、道路结构完全不同;CCPD 是车牌数据集,标注的是车牌框不是车辆框。直接拿来训,模型在停车场俯拍或斜拍画面里会明显掉点。常见做法是:用 COCO 或 BDD100K 里筛出车辆类做预训练权重,再用自己场景的停车场数据微调。如果标题里说的「完整数据集」已经包含停车场实拍图,优先用它,别绕远路。
停车场数据集的标注格式建议直接用 YOLO 的 txt 格式,每行class_id x_center y_center width height,坐标归一化到 0~1。类别不用多,car、truck、bus三类足够,违规占道判断靠的是车辆框和禁停区多边形的空间关系,不是靠类别。数据集目录按 Ultralytics 约定组织:
parking_dataset/ ├── images/ │ ├── train/ # 训练图,建议 1500~3000 张 │ ├── val/ # 验证图,占 10%~15% │ └── test/ # 测试图,占 5%~10% ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── parking.yamlparking.yaml是数据集描述文件,内容如下:
# 停车场车辆检测数据集配置 path: ./parking_dataset # 数据集根目录 train: images/train # 训练集相对路径 val: images/val # 验证集相对路径 test: images/test # 测试集相对路径 names: 0: car 1: truck 2: bus这里path用相对路径,方便整个项目打包迁移;names的索引必须和标注 txt 里的class_id严格对应,错一位模型就学歪。如果只有车辆一个类,把names改成0: vehicle即可,但后续禁停区判断逻辑不变。
2.2 禁停区怎么标:多边形区域与车辆框的判定
违规占道检测的核心不是「有没有车」,而是「车在不在禁停区」。禁停区一般用多边形表示,因为停车场通道、消防通道很少是规则矩形。做法是在配置文件里存一组多边形顶点坐标,推理时用射线法或 Shapely 判断车辆框中心点是否落在多边形内。下面是一个最小可用的判定脚本:
from shapely.geometry import Polygon, Point # 禁停区多边形,坐标为画面像素点,按实际摄像头画面标定 NO_PARKING_ZONES = [ Polygon([(120, 300), (480, 300), (480, 520), (120, 520)]), # 消防通道 Polygon([(600, 200), (900, 200), (900, 400), (600, 400)]), # 转弯盲区 ] def is_violation(box_xyxy): """判断车辆框中心是否落在任一禁停区内""" x1, y1, x2, y2 = box_xyxy center = Point((x1 + x2) / 2, (y1 + y2) / 2) for zone in NO_PARKING_ZONES: if zone.contains(center): return True return False逻辑说明:box_xyxy是 YOLOv8 输出的检测框左上角和右下角坐标,取中心点比取整个框更稳,因为车辆部分压线时中心点判定更符合「占道」直觉。参数上,多边形顶点必须按实际摄像头分辨率标定,换摄像头或改机位就要重标。如果画面有透视畸变,建议先做一次透视校正再标多边形,否则近处禁停区会偏大、远处偏小。
提示:禁停区坐标不要写死在代码里,放到单独的
zones.json,方便物业按现场调整,也方便毕设答辩时演示不同区域。
3. YOLOv8 训练:环境配置、参数设置与损失曲线怎么看
3.1 环境配置与最小训练命令
环境配置是新手第一道坎。我一般用 conda 建独立环境,Python 3.9 或 3.10 都行,PyTorch 按显卡选版本。GTX1660Ti 不支持 bf16,用 fp16 混合精度即可。安装命令:
conda create -n parking python=3.10 -y conda activate parking # 根据 CUDA 版本装 PyTorch,1660Ti 常见 CUDA 11.8 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics opencv-python shapely装完用yolo checks验证环境,能看到 CUDA 可用就对了。训练命令一行搞定:
yolo detect train \ model=yolov8n.pt \ data=parking_dataset/parking.yaml \ epochs=100 \ imgsz=640 \ batch=16 \ device=0 \ project=runs/parking \ name=exp1参数说明:model=yolov8n.pt用官方预训练权重,小数据集微调收敛快;imgsz=640是速度和精度的平衡点,停车场小目标多可以试 800,但 1660Ti 显存 6G 跑 800 要把batch降到 8;epochs=100配合早停patience=20足够,数据少时别硬堆到 300,容易过拟合。训练完权重在runs/parking/exp1/weights/best.pt。
3.2 损失函数曲线与 mAP 的读法
训练日志里box_loss、cls_loss、dfl_loss三条曲线是判断训练状态的窗口。box_loss下降慢说明框回归没学好,常见原因是标注框不贴合或学习率偏大;cls_loss震荡大说明类别样本不均衡,停车场里 car 远多于 truck/bus,可以给稀有类加权或补样本。mAP50 到 0.85 以上、mAP50-95 到 0.6 以上,停车场场景基本可用。如果验证集 mAP 远低于训练集,先查验证集标注有没有漏标,再查是不是训练集和验证集来自同一段视频导致过拟合。
画损失曲线用 Ultralytics 自带的results.csv,一行 matplotlib 就能出图:
import pandas as pd import matplotlib.pyplot as plt df = pd.read_csv("runs/parking/exp1/results.csv") df.columns = df.columns.str.strip() # 列名可能带空格 plt.plot(df["epoch"], df["train/box_loss"], label="train box") plt.plot(df["epoch"], df["val/box_loss"], label="val box") plt.xlabel("epoch"); plt.ylabel("loss"); plt.legend() plt.savefig("loss_curve.png", dpi=150)逻辑说明:results.csv每轮一行,列名带train/和val/前缀。重点看 train 和 val 是否同步下降,如果 val 先降后升就是过拟合,早停或加数据增强。参数上dpi=150够论文用,毕设插图别用默认 72。
注意:训练前务必确认
parking.yaml里path指向正确,路径错了 Ultralytics 会报找不到图片,但报错信息不总是直观,先手动ls一下确认目录结构。
4. 可视化界面:用 Gradio 搭一个能演示的检测面板
4.1 界面选型:Gradio 比 PyQt 更适合毕设演示
可视化界面这块,标题里说「操作简单」,我推荐 Gradio。原因很直接:PyQt 要写信号槽、打包成 exe 还容易缺 DLL,答辩现场翻车概率高;Gradio 几行代码就能出网页界面,支持图片上传、视频上传、实时摄像头,浏览器打开就能演示,老师看着也直观。如果非要桌面程序,PyQt5 也行,但开发时间至少多一倍。下面给 Gradio 的最小实现:
import gradio as gr import cv2 import numpy as np from ultralytics import YOLO from shapely.geometry import Polygon, Point model = YOLO("runs/parking/exp1/weights/best.pt") ZONES = [Polygon([(120, 300), (480, 300), (480, 520), (120, 520)])] def detect(image): results = model.predict(image, imgsz=640, conf=0.4, iou=0.5) annotated = results[0].plot() # 自带画框 for box in results[0].boxes.xyxy.cpu().numpy(): x1, y1, x2, y2 = box[:4] center = Point((x1 + x2) / 2, (y1 + y2) / 2) if any(z.contains(center) for z in ZONES): cv2.rectangle(annotated, (int(x1), int(y1)), (int(x2), int(y2)), (0, 0, 255), 3) cv2.putText(annotated, "VIOLATION", (int(x1), int(y1) - 8), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2) return annotated demo = gr.Interface(fn=detect, inputs=gr.Image(type="numpy"), outputs=gr.Image(type="numpy"), title="停车场违规占道检测") demo.launch(server_name="0.0.0.0", server_port=7860)逻辑说明:model.predict的conf=0.4是置信度阈值,停车场场景建议 0.35~0.45,太低误检多、太高漏检;iou=0.5是 NMS 阈值,车辆重叠不多时保持默认。results[0].plot()返回带框的 numpy 图,再叠加红色违规框。demo.launch的server_name="0.0.0.0"让局域网内其他设备也能访问,答辩时用手机就能演示。
4.2 视频流与告警记录
图片演示够用,但真实场景是视频流。把gr.Image换成gr.Video或gr.Image(sources=["webcam"])即可。告警记录建议落一个 CSV,字段包括时间、车辆框坐标、命中的禁停区编号:
import csv, time def log_violation(box, zone_id): with open("violations.csv", "a", newline="") as f: writer = csv.writer(f) writer.writerow([time.strftime("%Y-%m-%d %H:%M:%S"), *[round(v, 1) for v in box], zone_id])参数上,violations.csv按天分文件更好查,zone_id对应zones.json里的区域名。如果要做实时告警,可以在命中违规后触发一次声音或推送,但毕设阶段 CSV 记录足够。
提示:Gradio 默认队列可能在高帧率视频下丢帧,
demo.launch前加demo.queue(max_size=10)能缓解,但实时性要求高还是建议用 OpenCV 直接读流加多线程。
5. 避坑与排查:部署和训练里最容易翻车的 5 个点
5.1 现象:训练 loss 不降,mAP 一直是 0
原因通常是标注格式错。YOLO 要求归一化坐标,如果标注是像素坐标且没除宽高,模型学不到东西。解决:写个脚本检查所有 txt,坐标超过 1 就说明没归一化,批量除以图片宽高。
5.2 现象:推理时框全在画面左上角
原因是输入图片尺寸和训练时不一致,或者imgsz设错。YOLOv8 推理会自动 letterbox,但如果手动改了预处理就容易错位。解决:推理统一用model.predict(source, imgsz=640),别自己 resize。
5.3 现象:GTX1660Ti 训练报 CUDA out of memory
原因是batch或imgsz太大。1660Ti 6G 显存,imgsz=640时batch=16是上限,跑 800 要降到 8。解决:加batch=-1让 Ultralytics 自动选,或开amp=True混合精度省显存。
5.4 现象:禁停区判定在视频里抖动
原因是车辆框中心点在多边形边界附近来回跳。解决:加一个连续 N 帧命中才告警的计数器,N 取 5~10,能过滤掉瞬时误判。
5.5 现象:Gradio 界面在服务器上打不开
原因是server_name默认127.0.0.1,只监听本机。解决:改成0.0.0.0,并确认防火墙放行 7860 端口。如果还不行,检查是不是被其他进程占了端口,lsof -i:7860查一下。
6. 进阶技巧:把违规占道判定从「框中心」升级到「框重叠面积」
框中心判定有个明显短板:车辆斜停时中心点可能落在禁停区外,但车身已经压线。更稳的做法是算车辆框和禁停区多边形的重叠面积占比,超过阈值就判违规。Shapely 的intersection能直接算:
from shapely.geometry import box as shapely_box def overlap_ratio(box_xyxy, zone, img_w, img_h): """车辆框与禁停区的重叠面积占车辆框面积的比例""" x1, y1, x2, y2 = box_xyxy car_box = shapely_box(x1, y1, x2, y2) inter = car_box.intersection(zone).area car_area = (x2 - x1) * (y2 - y1) return inter / car_area if car_area > 0 else 0 # 阈值 0.3 表示车身 30% 以上压进禁停区就算违规 if overlap_ratio(box, zone, 1920, 1080) > 0.3: trigger_alarm()参数上,阈值 0.3 是我在几个停车场场景里试出来的经验值:太低会把正常通行车辆误判,太高会漏掉斜停占道。不同机位要微调,俯拍角度大的可以降到 0.2,平视角度建议 0.35。这个方法的代价是每帧多一次多边形求交,1080P 下单帧增加约 2~3ms,实时性影响可忽略。
另一个进阶方向是加跟踪。用 ByteTrack 或 BoT-SORT 给车辆分配 ID,只有同一 ID 连续多帧违规才告警,能彻底解决抖动和重复告警。Ultralytics 内置了model.track,一行就能开:
yolo detect track source=parking.mp4 model=best.pt tracker=bytetrack.yaml最后说个我自己的习惯:每次改完禁停区坐标或阈值,一定拿一段包含正常通行和违规占道的测试视频跑一遍,人工数一下误报和漏报,别只看单张图效果。停车场场景的玄学在于光线和角度,白天调好的参数晚上可能就翻车,多留几段不同时段的测试视频当后悔药。希望帮到你。
本文还有配套的精品资源,点击获取