
简介面向计算机相关专业学生及毕业设计开发者基于YOLOv8的智能家居老人服药提醒系统提供了一站式可运行方案解决智能药盒场景下的目标检测与提醒需求。资源内包含完整Python源码、预训练模型权重、配置文件、可视化页面及部署说明共97个文件压缩包仅24.21MB其中py源码70个pyc编译文件12个pt模型4个另有xml配置、txt说明和mp4演示视频模块划分明确便于按需查阅与二次开发。项目已通过功能测试可生成混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果及标签分布图等核心指标图表配合可视化界面能直观展示检测效果。已有39人学习下载适合用于毕业设计、课程设计或目标检测方向的项目立项演示功能完整、操作简单可放心直接使用。1. 这个毕设题目本质上是「检测模型 业务逻辑」两件事很多同学拿到《基于YOLOv8的智能家居老人服药提醒系统》这个题目第一反应是「又要训练一个YOLO模型」。但真正动手之后会发现模型只占整个项目三分之一的工作量。剩下三分之二花在「怎么定义一次服药行为」和「怎么让提醒不烦人」上。这个系统的核心价值不是「检测到药盒」而是「检测到药盒被拿起、隔了多久被放下、这次交互算不算一次有效服药」。YOLOv8在这个项目里承担的是视觉感知层——识别画面里的人手、药盒、水杯而提醒逻辑是在检测结果之上叠加的时序判断。如果你只想跑通一个demo用预训练权重加一个界面就能交差但想拿高分、能答辩、敢演示就必须把「检测」和「行为判定」之间的缝隙填上。适合用它做毕设的人有两类一类是目标检测入门想用YOLOv8做一次完整的「数据-训练-部署」闭环另一类是系统集成方向想展示自己能把模型包进可视化界面、对接硬件。下面所有内容都按「能复现」的标准写从数据标注讲到界面打包。新手照做能跑通熟手可以直接跳到第5章看避坑清单。2. 先把场景拆清楚服药提醒要检测的不是「药」是「动作」2.1 类别的设计直接决定标注工作量如果按照「检测药盒」的思路去做你会遇到一个很尴尬的问题药盒的外观千奇百怪有瓶装的、板装的、分格药盒、透明自封袋而且老人家里同一款药盒会出现在餐桌、茶几、床头柜多个位置。让模型去学「所有药盒的样子」等于把简单问题复杂化。我建议把检测目标定为四类person人体、hand手部、pill_box药盒、cup水杯。为什么不检测「药瓶」而是「药盒」——因为提醒系统的触发点是「盒子被打开/拿起」而不是「瓶子存在」。这个类别设计直接决定了后续行为判定的复杂度类别越少模型越好训但业务逻辑就要多写类别越多标注越累推理也越慢。我一般用5类封顶其中person只在画面里有老人出镜时才需要如果你的部署场景是「摄像头对着桌面」而不是「对着人」这一类的权重可以砍掉少一类就少一批误检。2.2 数据集的三种来源和真实占比标题里写的「完整数据集」通常指某位作者自己采的桌面场景视频帧。但你在网上能找到的开源数据集绝大多数是公共场景厨房、客厅、办公室和「老人坐姿服药」这个垂直场景有分布偏移。我的经验是别指望一份现成数据集直接训出高精度。常见做法是三层凑数据。第一层公开的COCO子集里抽Hand类COCO本身没有hand可以用EGOHANDS或TV-Hand占20%左右用来让模型先见一见「手」的多样性。第二层自己用手机拍固定机位模拟摄像头高度把药盒、水杯在桌面不同位置各放几十张占60%。第三层用Labelme对第二层数据做标注把拍到的每一帧里出现的手、药盒、水杯框出来占20%的迭代余量。整体规模控制在1500到3000张每张平均1.5到2个目标YOLOv8s完全够用。标注的时候有个习惯必须养成hand的框要贴着皮肤边缘不要把整个手臂包进去pill_box要把盒子完整框住哪怕被手遮挡了一半也要框「完整的盒体估计范围」。YOLOv8对遮挡目标的回归能力取决于训练标签里有没有这种「被遮住也要框全」的数据。标注格式转成YOLO txt时class_id顺序固定为0: person, 1: hand, 2: pill_box, 3: cup后面转数据集配置直接复用。3. 用 YOLOv8 训练自己的数据集从环境配置到看曲线3.1 环境搭建CPU 和 GPU 两条路的真实差别标题对应的部署教程里常见的环境是ubuntu20.04 YOLOv8 CPU版本这说明作者默认目标机器是普通的笔记本或无独显台式机。CPU训练YOLOv8s不是不可以但是有个前提数据集别超过3000张epoch别拉满100想省时间就用YOLOv8n预热结构再续训。先给出一套我在Ubuntu 20.04上踩稳的安装顺序GPU版# 1) 创建虚拟环境避免把系统Python搞乱 conda create -n yolo python3.9 -y conda activate yolo # 2) 安装PyTorch。先查自己的CUDA版本nvcc --version pip install torch2.1.0 torchvision0.16.0 --index-url https://download.pytorch.org/whl/cu118 # 3) 安装ultralytics。YOLOv8的官方实现已经并进这个包 pip install ultralytics8.2.0 # 4) 验证环境 python -c from ultralytics import YOLO; print(ok)第2步的CUDA版本一定要先确认nvidia-smi显示的CUDA版本是驱动支持的版本而PyTorch需要的是运行时CUDA两者可以不同——只要PyTorch的运行时CUDA版本不高于驱动版本就能跑。如果你只看nvidia-smi就去装最新的cu121很常见的结果是torch.cuda.is_available()返回False白费半小时。如果只有CPU把第2步换成pip install torch2.1.0不指定index-url默认装CPU版训练时间会变成GPU的15到20倍。所以CPU跑的话我的建议是直接换yolov8n.yaml 640输入 epoch50先跑通全流程后续再考虑要不要租GPU。3.2 数据集配置文件和训练命令的四个关键参数训练前要先准备好dataset.yaml放在项目datasets/MedicineReminder/目录下# dataset.yaml path: /home/your_name/MedicineReminder/datasets # 数据集根目录 train: images/train # 训练图片目录 val: images/val # 验证图片目录 names: 0: person 1: hand 2: pill_box 3: cup这里有个坑path必须是绝对路径不能用相对路径。Ultralytics在训练时会用path拼接train和val一旦拼出来的目录不存在它不会报「路径错误」而是直接跑一个空数据集最后loss曲线是平的mAP0.5直接是0。我第一次跑的时候就是被这个「空数据集训练不报错」的设计坑掉了一个下午。训练命令和参数说明yolo detect train \ --model yolov8s.pt \ --data /home/your_name/MedicineReminder/datasets/MedicineReminder.yaml \ --epochs 100 \ --imgsz 640 \ --batch 16 \ --device 0 \ --patience 20 \ --cache ram \ --project /home/your_name/MedicineReminder/runs \ --name train_small参数里最值得解释的是patience和cache。patience20表示验证集指标连续20轮不提升就提前停止用来防过拟合但如果你数据集很小不到1000张建议改成30不然模型还没学够就被停了。cache ram是先把图片缓存进内存能省大量磁盘IOCPU训练时效果尤其明显——代价是吃内存16G内存的机器建议改成cache disk。imgsz640是精度与速度的平衡点老电脑显存不够就降到480精度会掉3到5个点但显存占用少一半。3.3 训练跑起来后你应该盯着哪三张图训练过程中和结束后去runs/train_small/目录下看三个东西results.png、confusion_matrix.png、val_batch*.jpg。results.png里有train/loss和val/loss两条曲线。正常情况是训练损失一路下降验证损失先降后平。如果验证损失在第30轮突然向上翘说明过拟合了——解决方式是加数据增强YOLOv8默认已经开了hsv_h、hsv_s、translate等或者把dropout打开或者回到第2章把数据量补到2000张以上。confusion_matrix.png看的是类别混淆。最常见的错误是hand和pill_box互相误检——原因是标注框太紧、手和盒子挨得太近。如果混淆矩阵里这两类交叉严重不要急着调模型先回头检查标注框hand标注是不是只框了两根手指如果是把框放宽到整个手背一般能压下去一截误检。val_batch*.jpg是验证集上的预测可视化。这里要看的不是「框得准不准」而是「漏检的目标长什么样」。如果漏检的图集中在「手捏药盒、药盒半透明、光线暗」这三种情况说明数据集里缺这些困难样本从训练集里捞出来单独强化比调任何超参数都管用。4. 把模型接进可视化界面服药提醒逻辑的三种写法4.1 界面技术选型桌面端用 PySide6网页端用 Flask标题里写「可视化界面」对毕设来说桌面端用PySide6就是Qt的Python绑定网页端用Flask是两种最稳的方案。PySide6的优势是打包后能做成一个.exe演示的时候双击就开不用起服务Flask的优势是手机上能开浏览器看画面适合远程演示但需要解释「为什么网页能看到摄像头」。我个人推荐PySide6原因很实际答辩现场最容易翻车的环节就是「打开网页、输入地址、等模型加载」任何一个环节犹豫五秒评委的注意力就散了。PySide6把窗口、视频流、日志三个区域固定好打开即是可用状态。PySide6界面核心结构至少要有三块左侧是摄像头画面QLabel显示帧右侧是状态面板当前检测到的类别、最近一次服药时间、提醒记录列表底部是按钮区开始监测、停止监测、立即提醒。不要做复杂的参数设置页毕设演示场景里没人去调置信度阈值把这些参数写成配置文件里的常量就行。4.2 服药动作判定的三段式逻辑这是整个系统里最容易被低估的部分。单纯的「检测到药盒」没有意义——药盒放在桌上模型每帧都能检测到难道每帧都提醒一次真正要判断的是「一次拿起-放下-离开的完整过程」。# monitor.py 核心判定逻辑 class DoseActionMonitor: def __init__(self, threshold0.5, hold_frames10, interval3): self.threshold threshold # 置信度阈值 self.hold_frames hold_frames # 目标连续出现多少帧算「稳定存在」 self.interval interval # 两次服药之间的最短间隔分钟 self.state IDLE # IDLE / HOLDING / TAKEN self.hold_counter 0 self.last_dose_time 0 def update(self, detections, frame_time): # 第一步找当前帧里置信度最高的 pill_box 和 hand pill_box self._find_best(detections, pill_box, self.threshold) hand self._find_best(detections, hand, self.threshold) # 第二步状态机转移 if self.state IDLE: # 手和药盒同时存在且手的位置与药盒重叠 - 进入 HOLDING if hand and pill_box and self._overlap(hand, pill_box): self.hold_counter 1 if self.hold_counter self.hold_frames: self.state HOLDING self.hold_counter 0 elif self.state HOLDING: # 手消失但药盒还在或者两个都不在 - 认为一次拿起动作结束 if not hand: self.state TAKEN self.hold_counter 0 elif self.state TAKEN: # 进入 TAKEN 后检查与上一次服药的时间间隔 if frame_time - self.last_dose_time self.interval * 60: self.last_dose_time frame_time self.state IDLE return dose_taken else: self.state IDLE return None这段逻辑看着简单但跑起来会发现三个问题。第一hold_frames10的意思是「手和药盒连续重叠10帧才确认拿起」如果视频流是15帧每秒10帧就是0.67秒老人动作慢一点、手抖一点就可能永远进不了HOLDING状态——所以这个参数按目标人群调整演示视频里动作利落就设8实拍老人动作就设15。第二interval3表示「3分钟内重复拿起不算新一次服药」这是防误报的关键否则老人把药盒拿起来看一眼又放下系统会连报三次。第三_overlap函数算的是IoU但要放宽一点手和药盒的IoU大于0.1就算重叠因为手捏着药盒时检测框往往只有边缘相交。4.3 提醒的「打扰分级」从声音到推送的递进策略老人服药提醒系统最怕的不是漏报而是误报太多导致老人把提醒当成噪音。我常见的设计是三级递进第一级是界面内弹窗和语音播报只针对「检测到拿起但超过N分钟没有检测到放下」的异常第二级是微信推送当连续两次漏服时发给监护人第三级是短信或电话只在超过半天没有交互记录时触发。每一级都要有「关闭提醒」的入口而且要记录关闭时间和原因这个日志在答辩时很有说服力——说明你考虑到了真实场景下「老人不在家、摄像头空转」的干扰。界面里的状态面板建议展示当前状态机的值IDLE/HOLDING/TAKEN这样演示的时候评委能看到「拿起-放下-记录」的完整过程而不是只看到一个框在跳动。状态值可视化比检测框更能体现系统设计完整性。5. 部署避坑YOLOv8服药提醒系统最常见的五个翻车现场5.1 现象训练时 loss 为 nan从第1轮开始就是 nan出现这个现象先别怀疑数据集。最常见的原因是学习率太大YOLOv8默认lr00.01如果你用了很小的batch比如2或4梯度噪声会被放大早期训练就炸。解决方法是把lr0降到0.001再把batch提到8以上。如果数据集里有一张全黑的图或者全白的图也会触发nan——训练前写一段脚本扫一遍所有图片的std把标准差小于1的图片直接删掉。5.2 现象摄像头预览很流畅但模型推理一卡一卡这是典型的「可视化界面拖累了推理」问题。PySide6里如果在主线程跑模型推理界面绘制和推理互相抢GIL帧率直接砍半。解决方式是把推理放到QThread里主线程只负责把QPixmap贴到QLabel上。另一个隐蔽的坑是摄像头采集分辨率默认1080p推理输入是640如果每一帧都先缩放再推理缩放本身也要耗几十毫秒。建议采集端直接设置cv2.CAP_PROP_FRAME_WIDTH为1280高度720减少一次不必要的缩放。5.3 现象提示「No labels found in /datasets/images/train」这句话看着像数据集为空但实际原因通常是dataset.yaml的train路径写错了。YOLOv8的目录规范是images/train配labels/train如果你只把图片放进了images忘了放对应的labels文件夹或者labelme导出的txt文件和图片文件名没对齐就会报这个错。检查顺序数据集根目录下是否同时有images和labels两个一级目录每个目录下是否都有train和val子目录两个子目录里的文件名是否一一对应。5.4 现象模型检测到手了但一直不进 HOLDING 状态这种情况几乎都出在坐标映射上。界面显示的是摄像头原图检测框的坐标是640×640输入尺寸下的坐标如果你在update()里用原图坐标和检测坐标计算IoU永远是0。解决方式是在update()函数入口统一换算x1_orig x1 * orig_w / 640。另一个常见来源是检测框的xyxy格式被误当成xywh用了results[0].boxes.xyxy输出的是左上角和右下角坐标如果你按中心点加宽高去算IoU数值也会诡异。5.5 现象打包成 exe 后双击没反应或者闪一下就退出PySide6 ultralytics打包最常见的坑是资源文件路径。yolov8s.pt权重文件在开发时被放在项目根目录打包后路径变了模型加载直接失败。解决方式是用sys._MEIPASSPyInstaller运行时解包路径拼接权重路径。第二个坑是ultralytics依赖的libgcc等动态库没被PyInstaller收进去会报DLL load failed。规避办法是不要用--onefile改用--onedir模式然后手动把site-packages/ultralytics整个拷进dist目录成功率最高。6. 用一组「十秒动作视频」验证系统有效性再决定要不要加功能模型训练完、界面能跑、提醒能弹这时候先别急着拍照截图写论文。我建议你先录一段十秒左右的视频脚本固定为手伸向药盒、拿起、停顿、放下、手离开。把这段视频在界面的「视频回放」模式里跑一遍看三个指标拿起动作有没有在2秒内被确认、放下后有没有在1秒内回到IDLE、整个过程有没有触发多余提醒。这三个指标能过再开始写论文的实验章节。如果这段视频跑下来暴露了问题常见的补充手段有三个按性价比排序一是给hand类别加一个「距离药盒中心越近权重越高」的后处理这是见效最快的二是在dataset.yaml里把hand类的mosaic增强概率调低因为手部目标太小马赛克增强容易把半个手切碎三是加一帧差分——如果画面里连续10帧没有任何目标变化直接把状态机冻结避免光照缓慢变化的干扰。我自己的习惯是在DoseActionMonitor里加一个debug_log列表每次状态转移都记录frame_time, state, conf, iou四个值。这个日志平时不显示但只要出了奇怪的误报回放日志三分钟就能定位是检测问题还是状态机问题。这个习惯救过我很多次也建议你保留。这套系统的真正难点不是YOLOv8而是「检测结果如何转换成一件具体的事」。把状态机写清楚、把数据集做扎实、把界面整理干净这个方向就是能拿得出手的完整项目。希望这些步骤和踩坑记录能帮你少走几段弯路。提示如果你用的是Windows系统把第3章的环境搭建命令里的source activate换成conda activate即可其余无差别。CPU训练的机器建议在train命令里加一句--workers 0否则Windows下多进程数据加载偶尔会卡死。本文还有配套的精品资源点击获取