ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

宿舍安全监测毕设落地:YOLOv8从环境搭建到界面部署全攻略

宿舍安全监测毕设落地:YOLOv8从环境搭建到界面部署全攻略 简介这是一份基于YOLOv8的校园宿舍安全监测系统完整项目包适合计算机视觉、人工智能方向的学生用于毕业设计或课程设计也便于初学者对照学习完整落地流程。压缩包共8个文件主要包含Python源码文件训练、检测及可视化界面、PyTorch模型权重文件yolov8n.pt、best.pt等、以及README等说明文件整体约15.91MB。目前已有62人学习下载。从内容预览看项目包含可视化界面、模型训练与视频检测脚本能够输出核心指标曲线、混淆矩阵、F1曲线、精确率-召回率曲线、验证集预测结果和标签分布图适合答辩展示或本地快速部署验证。作者在描述中明确代码已测试可用并附有部署与使用说明下载后按README操作即可跑通流程适合作为项目起步参考或二次开发基础。1. 宿舍安全监测系统拿到项目包之后先别急着点运行宿舍安全监测的毕设题年年都有但绝大多数翻车不在模型而在环境、数据和界面这三样不太像技术的技术上。标题里这个项目给出的是一条完整链路YOLOv8检测模型、可视化界面、完整数据集、部署教程做法上确实比单独训一个模型更能撑起答辩——因为评审老师看的不只是精度数字而是你有没有把数据、训练、部署、展示真正串起来。它适合两类人一类是拿它做毕业设计或课程设计想尽快跑通并理解每条命令在干什么另一类是入门目标检测想用一套现成方案快速摸清 YOLOv8 的工作方式。我的建议是把“简单部署”四个字理解成“最小可运行路径”后面所有坑都是从这个最小路径长出来的。2. 先搭 YOLOv8 环境再跑代码CPU 版和 GPU 版的实际选择标题里的部署教程第一步永远是环境。环境问题在毕设里占比极高而且多数报错信息跟环境无关——是环境之间互相干扰。常见做法是先建一个干净的 conda 环境把 Python 版本锁定再装对应平台的 PyTorch 和 ultralytics 包。后面命令默认在 Ubuntu 20.04 下执行Windows 用户只需要把 conda activate 的写法换成自己系统的对应命令路径分隔符注意一下即可。2.1 Ubuntu 20.04 CPU 版环境为什么先把它作为兜底很多毕设小组的机器配置参差不齐实验室电脑可能没有独立显卡。YOLOv8 对 CPU 推理是支持的PyTorch 的 CPU 版也是所有安装路径里最不容易出问题的一条。我一般会先用 CPU 版把整条链路跑通再考虑要不要换 GPU——因为 CPU 版能帮你排除掉显卡驱动、CUDA 版本、显存不足这三类问题剩下的错误基本都是自己代码的问题。conda create -n dorm_safety python3.9 -y conda activate dorm_safety pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu pip install ultralytics这段命令做了三件事用 conda 创建并激活一个名为 dorm_safety 的独立环境从 PyTorch 官方 CPU 源安装 torch 和 torchvision避免误装到带 CUDA 的版本安装 ultralytics 包它会一并拉取 opencv-python、pandas、matplotlib 等依赖。python3.9 是 YOLOv8 支持范围内兼容性最均衡的版本3.8 也可以但不建议用 3.11 以上的新版本某些依赖包还没跟上。CPU 版能干什么、不能干什么要心里有数。推理一张 640×640 的图大约需要几秒到十几秒取决于 CPU 型号训练一个小数据集也能跑但时间按小时算。所以 CPU 版适合先跑通流程、验证数据和代码真正大规模训练还是得找 GPU。2.2 有 NVIDIA 显卡时的 GPU 环境1660Ti 这类卡怎么配对如果机器有 GTX 1660Ti 或者同级别显卡训练速度会快很多但 6GB 显存会在 batch size 和图像尺寸上卡住你。先确认驱动状态再装 PyTorch顺序别反。nvidia-smi python -c import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))nvidia-smi 用来查看驱动版本、显卡型号和剩余显存。显卡没被识别时后面所有 torch.cuda.is_available() 都会返回 False这是新手最常踩的坑。确认驱动正常后在刚才的 conda 环境里装 CUDA 版 PyTorchpip install torch torchvision --index-url https://download.pytorch.org/whl/cu121cu121 对应 CUDA 12.1。如果你的驱动比较老装 cu118 版本更稳妥。装完后重新运行上面那行 python 检测命令看到 True 和显卡型号说明 GPU 可用。这里有个经验1660Ti 跑 yolov8n 或 yolov8s 是舒服的batch 控制在 8 以内、imgsz 用 640显存刚好够yolov8x 在这个卡上基本没法跑强行跑只能把 batch 压到 1训练速度还不如用 yolov8s别在这上面浪费时间。2.3 环境验证用一张测试图跑通推理 demo环境装完先别碰自己的数据集。用官方权重跑一张普通图片确认推理链路通不通。这一步的意义在于把“环境问题”和“项目问题”切分开。yolo predict modelyolov8n.pt sourcetest.jpgyolo 是 ultralytics 自带的命令行入口。model 指定权重文件source 指定图片路径第一次运行会自动下载 yolov8n.pt大概 6MB。如果命令执行完在输出目录里出现了带预测框的 test.jpg说明 ultralytics、torch、opencv 这条链路已经通了后面所有报错都可以排除环境因素放心去做数据和训练。source 参数也可以传视频路径或摄像头设备号比如 source0 表示调用第一个摄像头这个到界面联调时会用到。3. 把宿舍监控截图变成可训练的数据集标注、转换与目录数据是标题里“完整数据集”之后你大概率要自己做的一件事。宿舍安全监测的项目包通常会附带一批截图和标注但你毕设答辩时几乎一定会面临一个问题老师要求检测的类别和你拿到的数据集类别不一致或者你想在自己的宿舍场景里补充数据。这时候就得自己动手处理数据集。3.1 用 labelme 标注宿舍场景类别命名与多边形注意点标注工具用 labelme 就够了界面简单导出的是 JSON 格式适合 YOLO 系列。安装和启动命令pip install labelme labelme打开 labelme 后加载宿舍走廊或寝室截图为图片用多边形或多边形矩形工具框住目标。类别命名务必统一用英文小写比如 person、smoke、fire、phone不要用中文也不要一会儿 Person 一会儿 person——YOLO 对类别名大小写敏感转换脚本里按精确匹配过滤大小写不一致会导致目标被静默丢掉。标注时有几个细节会直接影响后面训练尽量贴目标边缘不要把整张床都框进去只为了框住床上的人遮挡严重的相邻目标宁可分开标两个框也不要合并成一个宿舍场景里常见的远处小目标即使模糊也建议标上这会让模型在走廊长焦画面里更稳健。3.2 labelme JSON 转 YOLO 格式转换脚本与四个边界坑labelme 保存的 JSON 记录的是多边形顶点坐标YOLO 训练需要的是一行一个目标的归一化框坐标。转换脚本是绕不开的常见做法是写一个 Python 脚本把多边形外接矩形算出来再归一化。下面这个脚本能直接用import json import os def labelme_to_yolo(json_path, save_dir, class_names): # 读取 labelme 导出的 JSON 文件 with open(json_path, encodingutf-8) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] file_name os.path.splitext(os.path.basename(json_path))[0] out_path os.path.join(save_dir, file_name .txt) with open(out_path, w, encodingutf-8) as out: for shape in data[shapes]: label shape[label] if label not in class_names: continue # 过滤掉未定义类别的标注 points shape[points] xs [p[0] for p in points] ys [p[1] for p in points] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys) # 转成 YOLO 格式的归一化坐标 cx (x_min x_max) / 2 / img_w cy (y_min y_max) / 2 / img_h w (x_max - x_min) / img_w h (y_max - y_min) / img_h class_id class_names.index(label) out.write(f{class_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}\n) if __name__ __main__: class_names [person, smoke, fire] os.makedirs(labels, exist_okTrue) for name in os.listdir(jsons): if name.endswith(.json): labelme_to_yolo(os.path.join(jsons, name), labels, class_names)这段脚本的核心逻辑是逐条遍历 shapes 数组取多边形所有顶点的横纵坐标算出外接矩形再除以图片宽高做归一化。除以 img_w 和 img_h 这一步是 YOLO 格式的关键漏掉的话训练出的框会全部偏移。转换完检查一下每张图生成的 txt 行数应该等于标注目标数如果行数少了多半是类别名大小写没对齐。转换过程中的边界坑逐个说清楚。第一labelme 手滑点多了一个点导致外接矩形比实际目标大一圈这种问题只能在标注阶段用 labelme 重新打开检查代码层看不出来。第二同一张图片对应多个 JSON 文件时txt 会被互相覆盖脚本按图片名输出就是为了规避这个问题但多轮标注时要注意清理旧文件。第三归一化后的宽高值可能很小比如远处目标只有 0.01 级别保留 6 位小数防止精度丢失这也是脚本里写{w:.6f}的原因。第四图片尺寸很大时比如 1920×1080归一化本身没问题但训练阶段 imgsz 会缩到 640小目标的框会变得更小所以标注时不要把极小目标全标进去太小反而干扰模型学习。3.3 数据集目录结构images 和 labels 分开放YOLOv8 的标准目录结构是 images 和 labels 并列各自内部再分 train 和 val。每张 jpg 对应一个同名 txttxt 里每行是一个目标。目录建好了需要一个 data.yaml 指向这些路径。path: /home/user/dorm_dataset train: images/train val: images/val names: 0: person 1: smoke 2: firepath 建议写绝对路径不写相对路径。因为训练脚本可能从不同目录启动相对路径会跟着当前工作目录变化训练时大概率报找不到图片。train 和 val 的值是相对于 path 的路径names 的索引顺序必须和转换脚本里的 class_names 顺序一致这个索引顺序就是后面模型预测输出的类别 id错一位就全错。3.4 训练集和验证集划分按时间段而不是随机打散宿舍监控场景有个特殊性同一摄像头拍的连续帧高度相似光照和角度几乎一样。如果随机划分训练集和验证集验证集里很可能混入训练集的“孪生帧”训练出来的模型看起来 mAP 很高实际部署到真实摄像头就掉链子这是典型的数据泄漏。常见做法是按时间切分比如前 7 天的截图全部进训练集后 3 天的进验证集这样验证集里出现的画面在时间上和训练集没有重叠评估结果更接近真实部署。如果你的数据集不是按时间采集的至少也要按摄像头编号切分保证同一个摄像头视角的画面不完全落在同一个集合里。4. 训练一个真正能用的宿舍检测模型选型、参数与损失曲线数据和环境就绪后训练阶段的核心就两件事选对模型体积、调对训练参数。很多项目包自带的训练脚本参数是通用的你要做的是理解每个参数在宿舍场景下的合理取值而不是照抄。4.1 yolov8n 到 yolov8x 怎么选显存和速度决定边界YOLOv8 有 n、s、m、l、x 五个体积等级网络结构由 backbone、neck、head 三部分组成ultralytics 会在加载模型时自动搭好不需要手动构建。选择标准很简单显存小的机器用 n显存充足的机器优先考虑 s。1660Ti 的 6GB 显存跑 yolov8s 没问题yolov8m 就比较勉强了。CPU 训练只建议用 yolov8n因为 m 及以上体积在 CPU 上迭代一轮的时间会让人怀疑人生。宿舍安全监测的目标类别少、场景固定yolov8n 的精度完全够用。很多人的误区是觉得越大越好实际上在几百张宿舍截图的规模下yolov8x 和 yolov8n 的差距主要来自参数量数据量不够时大模型反而更容易过拟合。我的做法是先训一个 yolov8n 做基线跑通后再训一个 yolov8s 对比精度如果提升不明显就直接用 n训练时间短界面部署时帧率也更高。4.2 训练脚本epoch、batch、imgsz、patience 逐个拆训练命令用 ultralytics 的官方 CLI 就能完成不需要自己写训练循环。yolo detect train \ datadataset/data.yaml \ modelyolov8n.pt \ epochs100 \ batch8 \ imgsz640 \ patience20 \ projectruns \ namedorm_experimentepochs100 对宿舍场景足够了。你的数据集如果只有几百张图100 轮训练会在 30 到 50 轮左右收敛后面轮次主要看验证集有没有继续提升。batch8 是 1660Ti 显存下的安全值CPU 训练改成 batch2 或 1因为 CPU 内存虽然够但 batch 太大一次迭代的时间会成倍拉长。imgsz640 是 YOLOv8 默认的输入分辨率宿舍监控画面不需要更大2048×1536 的原图会被自动缩放分辨率再高只会拖慢速度精度提升有限。patience20 是最值得关注的参数意思是连续 20 轮验证集指标没有提升就自动停止训练这个机制能帮你省掉大量无效等待。训练完成后输出在 runs/dorm_experiment/ 目录下里面有 best.pt 和 last.pt 两个权重文件best.pt 是验证集上表现最好的部署时用这个。另外会有 results.png 和 results.csv分别保存训练曲线和逐轮指标下一步画损失曲线就用这个 CSV 文件。4.3 画损失函数曲线图从 results.csv 提取并看懂过拟合信号results.png 自带的曲线图够用但很多场景下你需要自己画——比如远程训练完把权重和日志拷回来或者想同时对比两次实验的曲线。从 CSV 里提取数据画图是最灵活的方式import pandas as pd import matplotlib.pyplot as plt log pd.read_csv(runs/dorm_experiment/results.csv) print(log.columns) # 先看列名不同版本列名略有差异 plt.figure(figsize(10, 5)) plt.plot(log[epoch], log[train/box_loss], labeltrain_box_loss) plt.plot(log[epoch], log[val/box_loss], labelval_box_loss) plt.xlabel(epoch) plt.ylabel(loss) plt.legend() plt.savefig(loss_curve.png, dpi150)results.csv 是训练过程中自动写入的每一行是一个 epoch 的汇总列名包含 train/box_loss、val/box_loss、metrics/mAP50(B) 等。列名在不同 ultralytics 版本里略有差异所以第一句先打印列名确认。把训练损失和验证损失画在一起核心目的是观察两条曲线的走势训练损失持续下降而验证损失在第某个 epoch 后开始回升说明过拟合了解决办法是减少 epochs、增大数据增强或缩小模型体积。如果曲线整体是锯齿状乱跳先检查 batch 是不是太小——CPU 上 batch1 训练出来的损失曲线就是一条剧烈抖动线不代表模型有问题这是单个样本的梯度噪声属于正常现象别被吓到。5. 宿舍安全监测系统落地避坑四个反复出现的部署问题下面是这类型项目里出现频率最高的几个坑每一条都是现象、原因、解决三步说清。这些坑不是模型原理层面的全是环境、数据、界面联调时会遇到的实际问题也是我见过最多人卡住的地方。5.1 import ultralytics 报错或版本漂移现象conda 环境里 import ultralytics 提示 ModuleNotFoundError或者昨天还能跑的训练命令今天突然报参数错误。原因本机装了不止一个 Python 环境pip 命令实际装到了 base 环境而不是当前激活的 conda 环境另一个常见原因是 ultralytics 被后续某个操作自动升级了新版本改了默认行为或接口。解决先用 python -m pip 替代裸 pip保证装进当前环境再查看当前版本并锁定依赖。pip freeze | grep ultralytics python -m pip install ultralytics你查到的版本号python -m pip 的关键在于它会绑定当前激活的 Python 解释器而不是系统默认的那个。锁版本号的意义在于 ultralytics 迭代很快大版本之间的训练参数和验证指标列名都可能变化锁定版本后你的训练脚本、界面代码的行为可复现不会因为重装环境而翻车。5.2 训练时报 CUDA out of memory现象训练刚开始一两步就报 CUDA out of memory进程直接退出命令行里能看到类似“CUDA error: out of memory”的信息。原因batch size 开太大或者数据加载器的多线程把多张图同时读入显存。很多人以为显存占用只跟模型体积有关实际上 batch8 时一次迭代要同时放 8 张 640×640 的图加上中间激活值和梯度占用会暴涨。解决把 batch 调到 2 或 1 重试。如果还想提高训练效率不要只调大 batch而是先把 workers 参数设小。yolo detect train datadataset/data.yaml modelyolov8n.pt epochs100 batch2 imgsz640 workers0workers0 表示数据加载不开子线程虽然读取速度会慢一点但显存占用最小。这一步能用来看清楚你的显存边界在哪batch1 能跑batch2 爆掉说明边界是 2后面就按这个值训练别跟显存较劲。5.3 mAP 很高但现场检测不出来现象训练时验证集的 mAP50 在 0.8 以上结果界面一打开摄像头画面里明明有人却一个框都画不出来或者框的位置错得离谱。原因训练数据和部署场景不一致常见的有三种。训练图是白天光线充足的走廊截图摄像头画面是夜间昏暗的寝室部署时界面把画面缩放过小再喂给模型比如训练时 imgsz640界面却把帧 resize 到 320 再推理还有一种是摄像头画面是竖屏的训练图是横屏的长宽比差异导致目标形变。解决先把推理端的 resize 尺寸设置成和训练一致确认这一步后再考虑场景差异。具体在界面代码里找到调用 model.predict 的地方把 imgsz 参数改成 640。如果尺寸一致后还是检测不到基本就是训练数据和现场画面的光照、角度差异太大解决办法是往训练集里加入现场采集的帧哪怕标注几十张效果也会有明显改善。宿舍这个场景尤其要注意夜间弱光画面这是最常见的翻车点别只拿白天截图训。5.4 可视化界面调用摄像头闪退现象界面程序一开摄像头就弹窗报错然后整个进程直接结束连界面都关不掉。原因PyQt5 这类界面框架中常见的做法是把摄像头读取放在主线程里而 OpenCV 的 VideoCapture.read() 是阻塞调用会导致界面消息循环卡死严重时直接崩溃。另一个高频原因是摄像头被其他程序占用比如浏览器、手机投屏软件占着摄像头不释放。解决把摄像头读取从界面主线程里拆出去单独开一个子线程循环读帧主线程只负责把最新一帧绘制到界面上。同时打开摄像头前先确认没有被其他程序占用。import threading import cv2 class CameraThread(threading.Thread): def __init__(self, src0): super().__init__() self.cap cv2.VideoCapture(src) self.frame None self.running True def run(self): while self.running: ret, frame self.cap.read() if ret: self.frame frame这段代码只做了两件事子线程里循环读取摄像头帧存到公有变量 self.frame主线程的界面刷新逻辑只管从这个变量取最新帧并显示。这样即使单帧读取偶尔慢一点界面也不会卡死最多是画面有点掉帧。如果加了线程仍然闪退就先单独运行cv2.VideoCapture(0)的测试脚本确认摄像头本身没被占用再回来查界面代码。5.5 训练用的类别与界面里的类别编号对不上现象模型推理正常检测框也画出来了但标签名全是乱的——人身上标着 smoke或者显示的名字和训练时的类别完全对不上。原因YOLO 的类别识别靠 class id 而不是名称。训练时 data.yaml 里定义的第 0 类是 person界面代码里的类名列表却是按另一种顺序写的比如界面默认 0smoke、1fire两边一错位所有框的标签全串了。解决把界面代码里的类名列表和训练用的 data.yaml 同步一遍。常见做法是在界面代码里直接读取 data.yaml 生成类名列表而不是手写死。import yaml with open(dataset/data.yaml, r, encodingutf-8) as f: data_cfg yaml.safe_load(f) class_names data_cfg[names]这个做法比在界面代码里手写[smoke, fire, person]稳妥得多因为训练配置是唯一的权威来源界面直接读它两边永远不会对不上。如果项目包里的界面代码已经写死了类名改这里就行权重里的类别顺序不会变。6. 把检测结果接进可视化界面一个避免重复推理的绘制技巧训练好模型后毕设界面最常见的实现方式是用 PyQt5 搭窗口OpenCV 负责摄像头取帧和画框。这里有一个很多人绕远路的点为了显示检测结果在每一帧里调用两次模型推理一次为了拿框一次为了画图或者把 results 对象里的坐标又手动换算一遍白费工作量。一个可靠的技巧是直接用预测结果的 boxes 对象在原始帧上画框不再做任何坐标换算from ultralytics import YOLO import cv2 model YOLO(runs/dorm_experiment/weights/best.pt) while True: ret, frame cap.read() if not ret: break results model(frame, imgsz640, conf0.4) for box in results[0].boxes: x1, y1, x2, y2 box.xyxy[0].tolist() cls int(box.cls[0]) conf float(box.conf[0]) label f{model.names[cls]} {conf:.2f} cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2) cv2.putText(frame, label, (int(x1), int(y1) - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imshow(dorm safety monitor, frame) if cv2.waitKey(1) 0xFF ord(q): break这段代码里最值得注意的两点是box.xyxy 已经是原图坐标直接拿去画矩形即可不要自己再除以缩放系数model.names 来源于训练时的 data.yaml和 box.cls 天然对应所以标签不会串。conf0.4 是置信度阈值宿舍场景下 0.4 比较稳漏检多就降到 0.25误报多就提高到 0.5这个数值可以直接留到界面里做成滑块方便答辩时演示。还有一个习惯必须养成model 初始化放在循环外面在界面创建之前只加载一次。如果写在循环里每帧都会重新读取权重文件界面直接卡成幻灯片。这一点在 PyQt5 的定时器刷新回调里尤其容易犯模型加载是毫秒级到秒级的操作绝对不能放在槽函数里。我习惯在项目目录里单独放一个 predict_single.py只跑一张测试图用来在改界面代码之前确认推理和画框逻辑没坏。这个习惯救过我很多次——界面 bug 和模型 bug 混在一起时先定位是哪一层的毛病再动手改能省下大半调试时间。希望帮到你。本文还有配套的精品资源点击获取
返回列表