
简介面向计算机视觉、人工智能、自动化等专业在校学生的智慧工地基坑支护结构变形监测系统完整项目包基于YOLOv8目标检测算法实现适用于毕业设计、课程设计、大作业或初期项目演示。项目以实际工地安全监测为背景聚焦基坑支护结构变形识别配有完整数据集帮助使用者快速搭建一套可演示、可评估的深度学习应用系统。压缩包共8个文件以Python脚本、PyTorch权重文件和说明文档为主涵盖可视化页面设计、模型训练、视频检测、模型推理等功能模块目录结构清晰便于查阅与二次开发。资源整体约15.91MB轻量易下载目前已有42人学习下载。代码均经过测试运行成功可生成核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果以及标签分布图覆盖训练评估全流程既能支撑毕业论文实验分析也能在答辩环节直观呈现模型性能附带README说明与部署教程基础较弱的学习者也能按步骤完成环境配置与运行验证。1. 基坑支护变形监测为什么先用YOLOv8从位移计到视觉识别的落地逻辑做基坑工程的毕设或课程设计最难的不是把模型跑通而是让老师一眼看出“这套系统真的能用在工地上”。传统的基坑支护结构变形监测靠全站仪、测斜仪、应变计这些接触式传感器数据准但布点贵、覆盖稀而且只能测“点”不能测“面”。换一套基于YOLOv8的视觉监测思路用普通监控摄像头对准支护桩、腰梁和支撑让目标检测模型每秒跑十几帧直接把裂缝、渗水、支护位移这类风险特征框出来再叠加一个可视化界面输出监测报表——这就是“基于YOLOv8的智慧工地基坑支护结构变形监测系统”这个标题背后真正的技术栈。它适合三类人一是要做智慧工地方向毕设的同学二是想快速搭一套CV落地Demo的课程设计者三是刚入行做工地视觉监测的工程师。它的价值在于把“深度学习训练”和“工程监测业务”串成了一条完整链路而不仅仅是训练一个权重文件。2. 数据闭环先跑通基坑监测数据集怎么组织、标注与划分2.1 检测对象与标注规范裂缝、渗水、支护变形这三类目标怎么标任何监督学习项目都是从“定义问题”开始的。基坑支护结构变形监测视觉上能看到的现象主要有三类一是混凝土表面裂缝表现为细长线状纹理二是渗水/水渍表现为深色不规则区域常出现在施工缝和止水帷幕附近三是支护结构位移表现为支撑梁与围檩之间的相对错位或者支撑端部脱开。这三类目标的形态差异很大所以在YOLOv8里不能笼统地用一个“defect”标签包打天下否则类别内方差太大训练出来的模型会在这个类和那个类之间反复抖动。标注规范建议按“风险类型 区域”来定裂缝用多边形标注因为裂缝是细长目标矩形框会把大量背景像素框进来导致正样本噪声偏高渗水用矩形框就够因为它本身是块状支护位移则要把“支撑端部”和“围檩基准”同时框出来后续做位移判定时靠两个框的相对位置计算。实际画标注时用LabelImg或X-AnyLabeling都行导出为YOLO格式时每张图片对应一个同名txt文件每行是 class_id x_center y_center width height坐标用归一化到[0,1]的浮点数。# 标注输出的YOLO txt示例假设类别0裂缝, 1渗水, 2位移 # 类别ID 中心点x 中心点y 目标宽度 目标高度全部归一化 0 0.4832 0.6521 0.0234 0.0876 1 0.7122 0.3345 0.1560 0.2041 2 0.3568 0.7890 0.0870 0.1220归一化坐标是YOLO系列的标准要求训练时模型会按网格尺寸映射回原图。如果你用的是JSON或XML标注记得写个脚本转成txt。这里有个容易翻车的点坐标归一化必须除以图片宽高而OpenCV读取图片的通道顺序是BGR转换时不要搞混。标注数量上每个类别最少150到200个实例如果只有几十张图模型拟合的是记忆而不是特征。2.2 自建数据集不够时怎么补公开裂缝/渗水数据集与现场扩充策略很多课程设计场景下没有真实基坑现场这时可以用公开的混凝土裂缝和渗水检测数据集做迁移学习底子。公开数据集的标注风格和你的目标要接近比如裂缝数据集大多是桥面、隧道、大坝的混凝土表面和基坑围护结构地下连续墙、灌注桩比较接近迁移效率高。常见的CCPD数据集是车牌检测HRSC2016是遥感船舶这些和基坑没关系别因为下载方便就乱接。现场扩充有两个低成本做法一是用手机摄像头在工地周边或学校实训基地的围挡、护坡墙上采集照片尽量覆盖早中晚光照二是对已有图片做离线增强包括HSV色域扰动、随机亮度、仿射变换和Mosaic增强。YOLOv8自带mosaic增强但mosaic对细长裂缝不友好因为它会把裂缝裁断建议训练时把mosaic只在最后10个epoch关闭或者把增强强度调低。数据目录结构按YOLO惯例组织dataset/ ├── images/ │ ├── train/ # 训练集图片约70% │ ├── val/ # 验证集图片约20% │ └── test/ # 测试集图片约10% └── labels/ ├── train/ ├── val/ └── test/这个结构是ultralytics框架默认支持的。划分数据集时要注意同一条基坑支撑梁的连续多帧图片必须放在同一个集合里否则模型会“偷看”验证集导致验证指标虚高。写个简单的Python脚本按文件名前缀哈希划分比手动拖文件更稳定。import os import random from pathlib import Path random.seed(42) data_dir Path(dataset) image_dir data_dir / images label_dir data_dir / labels # 假设raw_images里有全部未划分的图片和同名txt标签 raw list((data_dir / raw_images).glob(*.jpg)) reserved_prefix {brace] # 同一根支撑梁的图片文件名前缀固定 train_imgs, val_imgs, test_imgs [], [], [] for p in raw: # 同一前缀的所有帧进同一个集合避免数据泄漏 prefix p.stem.split(_)[0] if prefix in reserved_prefix: r random.random() if r 0.7: train_imgs.append(p) elif r 0.9: val_imgs.append(p) else: test_imgs.append(p) for split, imgs in [(train, train_imgs), (val, val_imgs), (test, test_imgs)]: (image_dir / split).mkdir(parentsTrue, exist_okTrue) (label_dir / split).mkdir(parentsTrue, exist_okTrue) for img in imgs: img.rename(image_dir / split / img.name) txt img.with_suffix(.txt) if txt.exists(): txt.rename(label_dir / split / txt.name)这段脚本的核心逻辑是用文件名前缀作为分组键把同一监测点的连续帧固定放入同一集合。random.seed(42)保证可复现。需要改的是reserved_prefix把现场采集时命名的前缀填进去如果你没有前缀规则就按时间戳的小时段划分核心是防止连续帧泄漏。2.3 数据集yaml配置与类别不平衡处理训练前要写一个data.yaml告诉YOLOv8去哪里读数据和类别名path: ./dataset train: images/train val: images/val test: images/test nc: 3 names: [crack, seepage, displacement]这里path建议写成相对路径兼容不同机器。names的顺序必须和标注txt里的class_id对应这个顺序非常关键训练和推理时都要用同一个yaml否则会出现“标签错位”——比如你把crack放在第0类推理时模型输出框显示的名称就会和实际语义对不上。类别不平衡是基坑场景的常态裂缝样本可能远多于渗水。处理办法不是粗暴删样本而是用类别权重或在训练参数里提高少样本类别的损失贡献。YOLOv8的cls_loss默认对每个类别一视同仁如果渗水样本只有裂缝的30%可以在损失函数中给渗水类加权重不过更简单的做法是先用默认配置训练再看混淆矩阵确认哪一对类别容易混淆再针对性补数据。3. 模型训练与参数调优从环境配置到损失函数曲线判读3.1 yolov8环境配置CPU能跑但别指望快GPU要一次配到位yolov8环境配置是在很多新手那里“翻车”的重灾区。先明确一点这个项目用CPU训练也不是不能跑一张640×640的图在普通台式机上推理大约要200到400毫秒训练一个50轮的模型可能要十几个小时只适合用来验证流程。真正做课程设计演示最好找一台显卡至少6GB显存的机器。配置环境的常见做法是用Anaconda建独立环境Python版本选3.8到3.10PyTorch按CUDA版本安装。# 创建独立环境避免污染系统Python conda create -n yolo python3.9 -y conda activate yolo # 安装PyTorch以CUDA 11.8为例实际以nvidia-smi显示的最高CUDA版本为准 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 # 安装ultralytics和依赖 pip install ultralytics安装完成后敲一段验证代码确认能调用到GPUimport torch print(CUDA available:, torch.cuda.is_available()) if torch.cuda.is_available(): print(GPU name:, torch.cuda.get_device_name(0))如果打印出来是False先检查显卡驱动里是否能识别GPU再检查PyTorch版本和CUDA是否匹配。我见过很多次这种情况驱动装好了但pip install torch时装了CPU版原因是指令默认从PyPI拉的包不带cuda。解决方法是严格按PyTorch官方的index-url装。另外ultralytics会自动下载yolov8n.pt权重到用户目录下的.cache国内网络慢的时候会卡很久可以手动建好目录把预训练权重放进去。3.2 训练命令与参数说明epochs、batch、imgsz、patience怎么设数据准备好了训练命令其实很简洁yolo train modelyolov8n.pt datadataset/data.yaml epochs100 batch16 imgsz640 device0 patience15 projectruns namebrace_monitor每个参数的落地含义要心里有数modelyolov8n.pt是nano版本预训练权重显存占用低、速度快适合课程设计如果机器配置高可以换yolov8s或yolov8m精度会高几个点但推理速度会下来。基坑裂缝是小目标nano的特征提取能力偏弱建议至少用s。batch16是每次迭代送入的图片数显存不够时会报OOM6GB显存跑yolov8n建议batch8跑yolov8s用4。imgsz640是训练图片分辨率。原图如果很大比如监控摄像头是1920×1080训练时会被缩放到640。想保留更多裂缝细节可以抬到768但训练时间和显存都会涨。patience15表示连续15轮验证集指标没有提升就提前停止防过拟合也省时间。训练完成后best.pt和last.pt分别对应验证集最优和最后一轮的权重都在runs/brace_monitor/weights/下。实际部署用best.pt。训练过程中要在终端盯几样东西每个epoch的box_loss、cls_loss、dfl_loss是否在下降验证集的精确率precision和召回率recall是否震荡上升。yolov8画损失函数曲线可以用训练日志直接生成也可以自己写一个小脚本读取runs/brace_monitor/results.csv画图。import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/brace_monitor/results.csv) # 看列名常见的有 train/box_loss, train/cls_loss, val/box_loss 等 plt.plot(df[train/cls_loss], labeltrain_cls_loss) plt.plot(df[val/cls_loss], labelval_cls_loss) plt.legend() plt.savefig(loss_curve.png, dpi120)这个脚本的价值在于保存一条可放进论文的损失曲线。判读曲线时最常遇到的情况是训练loss下降但验证loss和PR曲线一直抖动说明模型在过拟合优先把epochs降下来或者给数据增强加一点噪声。如果训练和验证loss一起高比如loss在2附近掉不下去先查数据是否存在标签错位或误标这个最隐蔽。3.3 网络结构图与推理脚本从权重文件到可视化检测结果很多人会问要不要给论文画yolov8网络结构图。yolov8整体上是anchor-free的CSPDarknet结构backbone负责多尺度特征提取neck用PANet融合特征head输出80×80、40×40、20×20三个尺度上的检测结果。画网络结构图时不要自己临摹用ultralytics自带方法导出模型结构图即可from ultralytics import YOLO model YOLO(runs/brace_monitor/weights/best.pt) model.model.save(brace_model.onnx) # 先导出onnx # 也可以直接用netron工具打开onnx看结构训练完模型的落地测试很简单from ultralytics import YOLO model YOLO(runs/brace_monitor/weights/best.pt) # 对单张图片推理 results model.predict(sourcetest_images/brace_001.jpg, conf0.4, iou0.5, saveTrue) for r in results: boxes r.boxes for box in boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) xyxy box.xyxy[0].tolist() print(f类别{model.names[cls_id]} 置信度{conf:.2f} 框{xyxy})conf0.4是置信度阈值低于这个分数的框会被过滤基坑现场光照复杂建议调低到0.3宁可多几个误报之后用业务规则再筛iou用于非极大值抑制保持0.5即可。saveTrue会把画好框的图片存到当前目录的runs/detect下。推理时如果出现“No labels found”或者结果全空先检查模型类别名和你要检测的目标种类是否一致。4. 可视化界面与Flask部署把模型输出变成监测报表4.1 为什么用Flask而不是实时视频流课程设计里“能用”比“炫技”重要智慧工地可视化界面在毕设答辩里是最容易拿分的部分。常见做法是用Flask起一个Web服务前端页面负责上传图片或者视频片段后端调用YOLOv8推理把检测框画在结果图上并附带一张监测记录表。之所以选Flask而不是用OpenCV直接弹窗口是因为评审老师更认可“客户端-服务端”的工程结构而且Flask部署简单局域网里用浏览器就能访问不用在每台机器上配Python环境。有人会问为什么不做RTSP视频流实时监测。技术上是可行的用OpenCV的VideoCapture拉流逐帧送进模型再把处理后的帧推给前端。但课程设计里视频流会暴露两个问题一是帧率上不去gtx1660ti跑yolov8s大约每秒15到20帧画面会卡顿二是没有录像回放不利于答辩时展示。推荐的做法是先对上传的视频抽帧检测再把检测到的帧和结果存下来最后在页面里按时间顺序回放这样既稳妥又能讲故事。4.2 一个最小可用的Flask监测页面图片上传、目标检测、报表生成下面是一个能直接跑起来的Flask应用核心部分省略了前端CSS和模板细节但逻辑完整import os import time from flask import Flask, request, render_template, url_for from ultralytics import YOLO import cv2 app Flask(__name__) UPLOAD_FOLDER uploads RESULT_FOLDER results os.makedirs(UPLOAD_FOLDER, exist_okTrue) os.makedirs(RESULT_FOLDER, exist_okTrue) model YOLO(runs/brace_monitor/weights/best.pt) app.route(/, methods[GET]) def index(): return render_template(index.html) app.route(/detect, methods[POST]) def detect(): f request.files[image] timestamp time.strftime(%Y%m%d_%H%M%S) input_path os.path.join(UPLOAD_FOLDER, timestamp f.filename) f.save(input_path) img cv2.imread(input_path) # 用模型推理注意source传numpy数组也行 results model.predict(sourceimg, conf0.3, iou0.5) report_rows [] for r in results: for box in r.boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) xyxy box.xyxy[0].tolist() # 把检测结果转换成监测记录 report_rows.append({ object: model.names[cls_id], confidence: round(conf, 3), bbox: [round(x, 1) for x in xyxy], time: timestamp }) # 保存画了框的结果图 res_img results[0].plot() # BGR order result_path os.path.join(RESULT_FOLDER, res_ filename_no_ext .jpg) cv2.imwrite(result_path, res_img) return render_template(result.html, result_urlurl_for(static, filenameimages/res_ f.filename), rowsreport_rows) if __name__ __main__: app.run(host0.0.0.0, port5000, debugFalse)这段代码把深度学习推理和Web接口串起来了。逻辑说明model.predict(sourceimg)接收的是OpenCV读入的BGR图像数组ultralytics内部会完成通道转换results[0].plot()返回的是画好检测框的BGR图所以后面用cv2.imwrite保存不需要再转RGB否则颜色会偏。host0.0.0.0表示允许局域网内其它设备访问这样答辩时可以直接在教室大屏浏览器上打开。参数说明conf0.3放在Web端比训练时的0.4更低因为网页展示需要尽量把目标框出来多几个误报可以接受但漏检会让老师觉得模型“不灵”。port5000是Flask默认端口如果被占用改成5001即可但前端页面里所有请求地址要跟着改。前端模板里用最简单的img标签展示结果表格列出每个检测框的类别、置信度和坐标。这里不需要写复杂JavaScript能用就行。如果想把结果导出成CSV监测报表可以用pandas在detect路由里拼一个DataFrame再调用to_csv这样论文的“监测数据表”就有了素材。4.3 把界面做成“智慧工地味”监测点管理、时间轴回放与预警阈值只做一个上传检测页功能上确实有点单薄。加两个低成本模块整个系统的完整度立刻不一样。第一个是监测点管理。在数据库或JSON文件里维护一张点位表包含点位编号、位置描述比如“基坑东侧第三道支撑”、关联摄像头IP或照片目录。每次上传图片时要求选择监测点并把检测结果写入该点位的记录列表。推荐用SQLite不用装服务用Python内置的sqlite3就能建表代码量也不大。第二个是阈值预警。比如对裂缝目标设定“单张图检测到超过N个裂缝目标”或“最长裂缝长度超过M像素”时页面显示红色预警。长度计算需要对裂缝目标做骨架提取相对麻烦更简单的替代方案是统计裂缝框的对角线长度当它超过图像宽度的1/3时算“明显裂缝”。虽然粗略但能体现工程思维。时间轴回放可以做成一个列表页从SQLite里按时间倒序查询所有检测记录每条记录带缩略图。答辩时先跑一遍回放再切到实时上传演示老师对你的系统完成度的判断会明显不一样。5. 部署与运行避坑指南环境冲突、路径乱码、显存不足的5个典型问题5.1 现象训练到一半CUDA out of memory进程被杀原因batch和imgsz设置超出了显卡显存上限。我刚接触yolov8时也踩过笔记本GPU只有4GB显存却用batch16训练yolov8s跑不到20个step就崩了。解决先降batch到4再不行换yolov8n或者开梯度累积。ultralytics有cacheTrue参数会把数据提前缓存到内存虽然能加快训练但也可能增加显存碎片。还有一种更隐蔽的情况系统里开了多个TensorFlow进程占用显存用nvidia-smi查看进程把无关的Python进程杀掉再训练。5.2 现象训练正常但推理时检测结果全空或者类别名称全错原因推理时没有加载训练时使用的data.yaml导致类别名和ID错位或者传入了RGB图像而模型期望BGR。很多人在Flask里用PIL.Image.open读图得到的是RGB但ultralytics内部如果接到numpy数组默认按BGR处理两种颜色空间下裂缝这类低对比度目标的表现差异不大但渗水区域的颜色变化明显误检漏检都很常见。解决统一用cv2.imread读图或者把PIL的RGB数组cv2.cvtColor(img, cv2.COLOR_RGB2BGR)后再传给模型。另外加载模型后用model.names打印类别确认顺序是否与训练时一致。5.3 现象Windows下训练时中文路径或中文文件名报错OpenCV无法解析原因Windows默认编码和YOLO内部对Unicode路径的兼容性不一致。数据集路径或图片名带“基坑”、“支撑”这类中文字符时cv2.imread返回Noneultralytics会抛出空图片错误。解决项目根目录和数据集路径全部改成英文和数字文件名不要有中文。这听起来像废话但很多课程设计者就是从网上下了一个带中文目录名的数据集开始的。把数据集复制到D:/brace_dataset这类路径下再操作删掉中文名再训练能省下一个晚上的排查时间。5.4 现象Flask页面打开很慢每次上传图片要等好几秒原因每次调用推理时都要重新加载模型。如果模型放在predict函数里每请求一次就YOLO(best.pt)一次这个加载动作本身就是瓶颈。解决把模型初始化放在路由函数外在Flask应用启动时加载一次之后所有请求共用同一份权重。还要注意如果开了debugTrueFlask的reloader会加载两次应用显存直接翻倍部署时务必设成debugFalse。5.5 现象部署到RK3588或Jetson Orin这类边缘设备时onnx导出失败或推理乱框原因边缘设备部署通常要先导出ONNX或TensorRT模型而导出时的一些参数和动态轴没设置好。yolov8导出onnx的命令是yolo export modelbest.pt formatonnx dynamicTrue simplifyTrue imgsz640dynamicTrue让输入的宽高可以在运行时变化但有时反而会让TensorRT优化器无从下手推理变慢。解决边缘设备上固定imgsz640导出时不要开dynamic如果推理乱框检查NMS后处理是否被重复执行——ONNX里通常包含了部分后处理如果再用代码跑一次NMS就会出现双重抑制。用onnxruntime的官方示例做一遍确认输出shape是[1, 84, 8400]也就是4个坐标加80个类别概率加8400个候选框。6. 进阶验证与持续改进用时间序列数据评估监测可靠性精度指标只能证明“模型能认出目标”不能证明“系统能用于监测”。基坑变形监测的本质是一场时间维度的观察同一个裂缝是变宽了还是稳定了渗水面积是扩散了还是退水了。所以我把最后这一步叫做“从检测到测量”。具体做法是固定摄像头位姿对同一监测点每天或每小时拍一张照片用模型检测并记录目标的框坐标然后计算两个指标裂缝长度像素变化率和渗水区域面积变化率。这里不需要精确到毫米只需要看趋势。当连续N个时间窗口内变化率超过设定阈值时系统就输出预警。这个方案避开了相机标定的复杂性同时又能讲出一个完整的监测闭环。核心脚本可以用一个定时任务驱动import json import time from pathlib import Path from ultralytics import YOLO model YOLO(best.pt) history [] def snapshot(monitor_point, img_path): result model.predict(sourceimg_path, conf0.3)[0] records [] for box in result.boxes: cls_id int(box.cls[0]) if model.names[cls_id] in (crack, seepage): xyxy box.xyxy[0].tolist() area (xyxy[2]-xyxy[0]) * (xyxy[3]-xyxy[1]) records.append({cls: model.names[cls_id], area: area, time: time.time()}) history.append({monitor_point: monitor_point, records: records}) # 与上一次对比 if len(history) 2: last_area sum(r[area] for r in history[-2][records]) current_area sum(r[area] for r in records) delta (current_area - last_area) / (last_area 1e-6) if delta 0.2: print(f预警{monitor_point} 目标面积变化率 {delta:.2%}) json.dump(history, open(monitor_history.json, w), indent2)这段代码逻辑很直白记录每次快照的目标面积和变化率。1e-6是为了防止除零delta0.2相当于允许20%以内的波动阈值工地光照变化容易引起目标面积波动阈值建议调到0.25以上。真正的产品级方案需要做相机内参标定和畸变校正把像素面积换算成物理面积这一点在论文里点一句“可通过棋盘格标定实现毫米级换算”就够了不必真的做。我最想提醒你的一点是课程设计不是算法竞赛不要过度追求在验证集上把mAP刷到0.95。拿到一套能稳定运行、能画图、能出报表、能讲清整条技术链路的系统比把模型精度从0.87提高到0.88更能打动评委。哪怕是最简单的nano模型配合清晰的界面和完整的数据管理逻辑已经能体现你对“智慧工地”这个场景的理解。希望这篇笔记帮你在部署和训练路上省下几个通宵把更多精力放在业务逻辑和展示上。本文还有配套的精品资源点击获取