简介:这份资源面向计算机、人工智能、自动化等专业的在校学生与教师,提供一套基于YOLOv8的工地基坑变形预警完整项目方案,可用于毕业设计、课程设计或大作业。压缩包共8个文件,约15.91MB,包含3个Python脚本、3个模型权重文件与2个说明文本,分别承担可视化界面、模型训练、视频检测推理以及部署说明等用途,结构清晰,便于快速上手。项目已通过运行测试,配套完整数据集与可视化页面,可生成核心指标曲线、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果及标签分布图,方便答辩展示与结果分析。目前已有28人学习下载。对于需要快速搭建目标检测项目、理解YOLOv8训练与推理流程的读者,这份资源能提供从数据到界面再到部署的一站式参考,也可在此基础上修改扩展,实现其他检测功能。
1. 基坑变形预警为什么选 YOLOv8:一份能直接跑通的毕设级资源
工地上基坑边坡的位移监测,传统做法靠全站仪打点或者埋测斜管,数据准但采样频率低,等发现异常往往已经晚了。视觉方案的好处是摄像头架上去就能持续盯,成本低、覆盖广。这份资源把 YOLOv8 目标检测用在基坑变形预警上,配套源码、可视化界面、完整数据集和部署教程,解压后简单配置就能跑起来。它适合正在做毕设或课程设计的同学,也适合想快速验证视觉预警思路的工程师。核心逻辑不复杂:用标注好的基坑裂缝、位移标志物、支护结构异常等目标训练检测模型,推理端接一个可视化界面实时显示告警。下面从环境搭建、数据组织、训练调参、界面联调到避坑,一步步拆开讲。
2. 环境搭建与依赖安装:从零把 YOLOv8 跑起来
2.1 选 Python 版本和 PyTorch 安装方式
YOLOv8 官方推荐 Python 3.8 以上,实际用 3.9 或 3.10 最稳。PyTorch 版本要和 CUDA 对齐,如果手头只有 CPU 机器也能跑,只是训练慢。常见做法是先用 conda 建独立环境,避免和系统 Python 打架。
conda create -n yolo_kb python=3.10 -y conda activate yolo_kb # CPU 版本安装,适合没有独显的机器 pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu # 如果有 NVIDIA 显卡,换成对应 CUDA 版本的命令 # pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics opencv-python PyQt5 numpy pandas matplotlib这里ultralytics是 YOLOv8 的官方库,装完就能用yolo命令行。PyQt5是给可视化界面用的,如果资源里的界面是 Gradio 或 Streamlit,对应换成gradio或streamlit。opencv-python负责视频流读取和画框。参数上唯一要注意的是 PyTorch 和 CUDA 的对应关系,装错了会在torch.cuda.is_available()返回 False,训练时自动落到 CPU,速度差十倍以上。
2.2 验证环境和模型加载
装完先跑一条命令确认环境没问题:
from ultralytics import YOLO import torch print("CUDA available:", torch.cuda.is_available()) model = YOLO("yolov8n.pt") # 会自动下载预训练权重 results = model("https://ultralytics.com/images/bus.jpg") print(results[0].boxes)这段代码做了三件事:检查 GPU 是否可用、加载 nano 版预训练权重、对一张示例图做推理。如果boxes有输出,说明环境通了。yolov8n.pt是模型规格,n 最小最快,s/m/l/x 依次增大。基坑场景目标种类不多,通常 n 或 s 就够,除非要检测细小裂缝才上 m。预训练权重首次运行会自动下载到当前目录,离线环境需要提前把.pt文件放好。
2.3 资源目录结构梳理
解压后一般能看到这样的结构,不同打包方式可能略有差异:
| 目录/文件 | 作用 |
|---|---|
datasets/ | 基坑图像和标注文件 |
weights/ | 预训练权重和训练产出 |
train.py | 训练入口脚本 |
detect.py | 推理脚本 |
ui/ | 可视化界面代码 |
requirements.txt | 依赖清单 |
README.md | 部署说明 |
先读README.md确认作者用的 Python 和库版本,再对照自己的环境。如果requirements.txt里版本锁得很死,建议按它来,避免 API 变动导致脚本报错。
3. 数据集组织与标注格式转换:让 YOLOv8 认得你的基坑图
3.1 YOLO 格式的目录约定
YOLOv8 要求数据按固定结构放:
datasets/ images/ train/ val/ labels/ train/ val/图像和标签文件名一一对应,标签是.txt,每行格式为class_id x_center y_center width height,坐标全部归一化到 0~1。基坑场景常见类别有crack(裂缝)、settlement(沉降标志)、deformation(支护变形)、water(渗水)等,具体看资源里data.yaml怎么定义。
3.2 从 Labelme 标注转到 YOLO 格式
如果拿到的是 Labelme 的 JSON 标注,需要转一道:
import json import os from PIL import Image def labelme_to_yolo(json_path, output_dir, class_map): with open(json_path, "r", encoding="utf-8") as f: data = json.load(f) img_w = data["imageWidth"] img_h = data["imageHeight"] lines = [] for shape in data["shapes"]: label = shape["label"] if label not in class_map: continue cls_id = class_map[label] points = shape["points"] xs = [p[0] for p in points] ys = [p[1] for p in points] x_center = (min(xs) + max(xs)) / 2 / img_w y_center = (min(ys) + max(ys)) / 2 / img_h w = (max(xs) - min(xs)) / img_w h = (max(ys) - min(ys)) / img_h lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}") name = os.path.splitext(os.path.basename(json_path))[0] + ".txt" with open(os.path.join(output_dir, name), "w") as f: f.write("\n".join(lines)) class_map = {"crack": 0, "settlement": 1, "deformation": 2, "water": 3} labelme_to_yolo("sample.json", "labels/train", class_map)class_map必须和data.yaml里的names顺序一致,否则训练出来的类别会错位。归一化用图像实际宽高,不是标注框的宽高。Labelme 的矩形标注取两个对角点,多边形标注取所有点的外接矩形,上面代码统一按外接矩形处理,对基坑这种偏矩形的目标够用。
3.3 data.yaml 配置
path: ./datasets train: images/train val: images/val nc: 4 names: ["crack", "settlement", "deformation", "water"]nc是类别数,names顺序和转换时的class_map对应。path用相对路径时,训练脚本的工作目录要对,否则会报找不到数据。常见做法是写绝对路径,省得来回切目录。
4. 训练调参与模型导出:基坑场景怎么设才不翻车
4.1 训练命令和关键参数
yolo detect train \ data=datasets/data.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ lr0=0.01 \ patience=20 \ project=runs/kb \ name=exp1epochs是训练轮数,基坑数据集通常几百到几千张,100 轮起步。imgsz是输入尺寸,640 是默认值,裂缝这种细长目标可以提到 960 或 1280,但显存占用翻倍。batch根据显存调,8G 显存跑 640 尺寸大概能到 16。lr0初始学习率,0.01 是 YOLOv8 默认,数据集小可以降到 0.001。patience是早停耐心值,20 轮验证指标不升就停,省时间。
4.2 训练过程看什么指标
训练日志里重点盯三个:box_loss定位损失、cls_loss分类损失、mAP50平均精度。box_loss和cls_loss应该整体下降,震荡正常但别一直往上走。mAP50是 IoU 阈值 0.5 下的平均精度,基坑场景能到 0.7 以上算可用。如果mAP50卡在 0.3 以下,先查标注质量,再看类别是否混淆。
from ultralytics import YOLO model = YOLO("runs/kb/exp1/weights/best.pt") metrics = model.val(data="datasets/data.yaml") print(metrics.box.map) # mAP50-95 print(metrics.box.map50) # mAP50 print(metrics.box.map75) # mAP75best.pt是验证集上表现最好的权重,last.pt是最后一轮的。部署用best.pt,继续训练用last.pt接着跑。
4.3 导出 ONNX 和推理加速
yolo export model=runs/kb/exp1/weights/best.pt format=onnx imgsz=640导出 ONNX 后可以用 ONNX Runtime 推理,不依赖 PyTorch,部署到边缘设备更方便。imgsz要和训练时一致,否则精度会掉。如果资源里提到 RK3588 或类似嵌入式平台,通常就是走 ONNX 转 RKNN 的路线,转换脚本在部署教程里会有。
5. 可视化界面联调与预警逻辑:从检测框到告警输出
5.1 界面调用推理接口
可视化界面一般用 PyQt5 或 Gradio 写,核心是调detect.py里的推理函数。以 PyQt5 为例:
import sys import cv2 from PyQt5.QtWidgets import QApplication, QLabel, QPushButton, QVBoxLayout, QWidget from PyQt5.QtGui import QImage, QPixmap from ultralytics import YOLO class KBWindow(QWidget): def __init__(self): super().__init__() self.model = YOLO("runs/kb/exp1/weights/best.pt") self.label = QLabel("等待检测") self.btn = QPushButton("开始检测") self.btn.clicked.connect(self.run_detect) layout = QVBoxLayout() layout.addWidget(self.label) layout.addWidget(self.btn) self.setLayout(layout) def run_detect(self): cap = cv2.VideoCapture(0) # 换成基坑摄像头 RTSP 地址 ret, frame = cap.read() cap.release() if not ret: return results = self.model(frame, conf=0.5) annotated = results[0].plot() h, w, _ = annotated.shape img = QImage(annotated.data, w, h, 3 * w, QImage.Format_RGB888).rgbSwapped() self.label.setPixmap(QPixmap.fromImage(img)) app = QApplication(sys.argv) win = KBWindow() win.show() sys.exit(app.exec_())conf=0.5是置信度阈值,低于这个值的框不显示。基坑预警建议调低到 0.3~0.4,宁可误报别漏报。results[0].plot()直接返回画好框的图,省得自己写绘制逻辑。摄像头地址换成 RTSP 流就能接现场球机。
5.2 预警逻辑怎么写
检测到目标只是第一步,预警要加规则。常见做法是统计连续帧里某类目标的数量或面积占比,超过阈值再触发告警:
def check_alarm(results, frame_area, threshold=0.05): alarm = False for box in results[0].boxes: cls_id = int(box.cls[0]) if cls_id in [0, 2]: # crack 或 deformation x1, y1, x2, y2 = box.xyxy[0].tolist() area_ratio = (x2 - x1) * (y2 - y1) / frame_area if area_ratio > threshold: alarm = True return alarmthreshold是面积占比阈值,0.05 表示目标框占画面 5% 以上才告警。这个值要根据摄像头焦距和距离标定,没有通用值。连续帧计数可以用队列存最近 N 帧的结果,避免单帧误检触发告警。
5.3 部署到现场要注意什么
现场部署第一件事是固定摄像头角度,每次挪动都要重新标定。光照变化大的工地建议加补光灯,或者训练时把不同时段的数据都标进去。网络不稳的地方,推理端放本地,只把告警结果传回服务器,别传视频流。
6. 避坑与常见问题排查
6.1 训练 loss 不降反升
现象:box_loss从第一轮就开始涨,mAP50一直是 0。原因通常是标注格式错了,比如坐标没归一化、类别 ID 从 1 开始、或者图像和标签文件名对不上。解决:用yolo detect train前先跑一遍数据检查,确认每个.txt里的坐标都在 0~1 之间,类别 ID 从 0 开始,图像和标签数量一致。
6.2 推理时类别全错
现象:框的位置对,但类别标签全是同一个。原因一般是data.yaml里names顺序和训练时不一致,或者导出 ONNX 后类别映射丢了。解决:训练和推理用同一份data.yaml,导出 ONNX 时确认names写进了模型元数据。
6.3 可视化界面卡死
现象:点开始检测后界面无响应。原因是在主线程里跑了推理,阻塞了 UI 事件循环。解决:把推理放到QThread里,通过信号槽把结果传回主线程更新界面。Gradio 和 Streamlit 同理,用异步或后台任务。
6.4 摄像头读不到流
现象:cv2.VideoCapture返回 False。原因可能是 RTSP 地址格式不对、网络不通、或者 OpenCV 编译时没带 FFmpeg。解决:先用ffplay或 VLC 验证流地址能播,再检查 OpenCV 版本,pip install opencv-python默认带 FFmpeg,如果用的是opencv-python-headless可能缺。
6.5 显存不够报 OOM
现象:训练到一半报 CUDA out of memory。原因是batch或imgsz太大。解决:先把batch降到 8 或 4,还不行就降imgsz到 416。也可以用yolov8n代替yolov8m,参数量少一半。
7. 把预警阈值调准的一个笨办法
预警阈值这东西没有理论最优解,我试过最有效的办法是拿一段已知结果的视频回放,手动标出真正该告警的时间点,然后跑不同阈值看误报和漏报的平衡点。具体操作:准备一段 5~10 分钟的现场视频,人工记录哪些时刻确实出现了裂缝扩展或支护变形,然后用脚本批量跑不同conf和面积阈值组合,统计每个组合的准确率和召回率。
import cv2 from ultralytics import YOLO model = YOLO("runs/kb/exp1/weights/best.pt") cap = cv2.VideoCapture("site_test.mp4") frame_area = None results_log = [] while True: ret, frame = cap.read() if not ret: break if frame_area is None: frame_area = frame.shape[0] * frame.shape[1] results = model(frame, conf=0.3, verbose=False) for box in results[0].boxes: cls_id = int(box.cls[0]) x1, y1, x2, y2 = box.xyxy[0].tolist() ratio = (x2 - x1) * (y2 - y1) / frame_area results_log.append((cap.get(cv2.CAP_PROP_POS_FRAMES), cls_id, ratio)) cap.release() # 按帧号排序后和人工标注对比,找最佳阈值这段代码把每帧的检测结果和面积占比都记下来,导出成 CSV 后和人工标注对齐。conf=0.3是故意调低的,先把所有可能的框都留下,后面再按面积阈值筛。跑完几组不同参数,选误报可接受且漏报最少的那组。
| 阈值组合 | 误报次数 | 漏报次数 | 建议场景 |
|---|---|---|---|
| conf=0.5, ratio=0.05 | 3 | 7 | 告警频率敏感 |
| conf=0.3, ratio=0.03 | 12 | 1 | 安全优先 |
| conf=0.4, ratio=0.04 | 6 | 3 | 平衡 |
从那以后我每次调预警阈值都强制走一遍视频回放,不再拍脑袋定参数。这套流程多花半小时,但能省掉现场反复调参的麻烦。希望帮到你。
本文还有配套的精品资源,点击获取