资讯动态

基于YOLOv8的跌倒检测系统实战:从数据集构建到可视化告警全流程

发布时间:2026/10/19 8:37:56 来源:尧图企业网站定制
最近在做边缘设备上的异常行为检测其中一个落地场景就是养老院和家庭监护里的行人跌倒报警。跌倒检测这个项目我前后做过两版第一版用姿态估计加规则判断误报率高得离谱第二版直接用YOLOv8做目标检测配上一个简单的几何规则做二次过滤效果和实时性都让我比较满意。这篇文章就把整个项目拆开讲清楚从数据集怎么搞、标注有什么讲究、YOLOv8怎么训练和调参到推理脚本怎么写、可视化界面怎么搭最后是踩过的坑合集。适合刚接触深度学习检测任务、想完整跑通一个可落地项目的同学参考。项目源码包含了训练和推理两部分自带数据集和一个桌面可视化界面拿到之后可以照着流程复现换成自己的场景数据重新训练也不难。1. 项目整体设计与思路拆解1.1 跌倒检测到底在检测什么很多第一次接触这个项目的人容易犯一个错误以为跌倒检测就是“检测到人”然后把人标个框就完事了。实际上跌倒检测的核心是识别一个事件而不只是一个物体。人在画面里站立、行走、坐下、蹲下这些都是正常状态跌倒检测系统要在这些人体状态中把“突然倒地”这个特殊事件准确挑出来并且尽可能不打扰正常行为。这就带来一个天然难点跌倒动作在视觉上其实没有绝对清晰的边界。一个人躺在地上不动和一个人睡觉、或者蹲下系鞋带从单帧图像上看可能非常相似。这也是我之前第一版用姿态估计做的时候误报特别多的原因——姿态点画出来确实是横着的但它判断不了这个人的意图和上下文。后来我换了一个思路先用YOLOv8做人体检测把人和人的包围框稳定地找出来然后再用连续帧的空间几何关系和时序变化去判断这个人是不是真的摔了。这样虽然多了一层逻辑但误报率一下子就降下来了。从需求方角度来看跌倒检测的场景主要集中在三块养老机构/医院病房的离床监控、家庭独居老人的安全监护、公共区域如地铁站、健身房的异常事件预警。不同场景对实时性和准确度的要求不一样。养老院大概需要能在5秒内发现跌倒并联动告警家庭摄像头场景则更看重低误报不然半夜响一次警报家里人得疯掉。所以这个项目的定位就是一个通用底座模型负责把人检测出来规则层负责判断事件界面负责呈现和告警三个模块互相配合。1.2 为什么选YOLOv8作为核心模型YOLO系列在目标检测里已经算“标配”了但YOLOv8并不是单纯比v5多了几层网络它在设计上有几个变化对这个项目非常关键。首先是anchor-free机制。之前的YOLO版本需要预先聚类算出锚框尺寸如果训练数据里跌倒的人体框宽高比和常规人体差异很大比如横躺的人框很扁锚框匹配可能会有偏差。YOLOv8改成anchor-free之后候选框直接由特征图中心点回归训练更简单对极端宽高比的框也更友好。其次是模型结构上的C2f模块和Decoupled Head。C2f模块相当于把梯度回传的路径拉长了网络可以更充分地学习特征。而解耦检测头把分类和回归分开处理收敛速度和精度都优于之前耦合的方式。实际跑下来YOLOv8s在中等显卡上做单帧推理延迟基本在20毫秒以内完全满足视频流逐帧检测的要求。还有一个很实在的理由是生态。YOLOv8官方仓库把训练、验证、导出、推理全链路都封装好了命令行直接跑省去很多造轮子的时间。而且它支持导出ONNX方便后面在边缘设备上部署。如果你以后要换摄像头角度、换室内环境只需要重新训练或者微调不用改框架代码。1.3 系统架构训练、推理、界面三条线整个系统我拆成了三条线来开发这样分工清晰后期也好维护训练线数据集准备、标注格式转换、YOLOv8训练、指标评估。训练线输出一个最佳的模型权重文件。推理线加载模型权重对图片/视频/摄像头拉流的帧做检测输出目标框、类别和置信度再叠加时序判断逻辑输出“跌倒/正常”事件。界面线基于PyQt5做一个桌面应用把推理结果实时画到画面里同时显示FPS、告警记录、事件截图提供打开文件/摄像头等操作入口。三条线之间用标准的模型文件和结构化的事件数据交互比如推理线输出的是frame, boxes, scores, class_ids界面线只负责展示和告警这样即使某一天你想把界面换成Web端推理线和训练线都不用动。这个设计虽然简单但在实际项目里非常省心强烈建议一开始就把模块边界划清楚。2. 数据集准备与处理2.1 数据从哪来、各要多少数据集是整个项目的命根子YOLOv8再强数据不行照样白搭。我这个项目的数据来源分两部分一部分是网上能找的公开跌倒检测数据集另一部分是自己在办公室和模拟场地里用普通监控摄像头录的一段视频抽帧后作为补充。数量上我的经验是跌倒样本至少要有800到1200张正常人体样本至少要有2000张以上然后再拿一部分只包含空场景的背景帧做负样本。因为跌倒本质上是一个小概率事件如果正样本太少模型很容易把“人横躺在画面里”全部当成正常或者干脆把一些相似的姿态误判成跌倒。数据采集时有一个关键点场景多样性比单纯的数量更重要。同一个房间同一个角度拍1000张不如不同房间、不同光线、不同角度各拍100张。如果只是在一个固定场景训练换到真实环境后泛化能力会很差。我自己的做法是尽量覆盖逆光、夜间红外、侧光、摄像头俯视45度和顶视90度这几类典型角度因为家用摄像头大多装在墙角高处俯视角度和公开数据集里的平视画面差别很大。原始数据采集完之后一定要做清洗。我踩过一次坑拿到的视频里有些帧是有人影但非常模糊的模型训练时把这些模糊帧当成了“跌倒”特征导致推理时画面稍微一糊就误报。后来我写了个小脚本用拉普拉斯方差评估图像清晰度把模糊帧自动剔除准确率立刻改善了不少。2.2 标注规范和YOLO格式细节标注工具我用的是开源的LabelImg和CVAT两者都能输出YOLO格式的txt文件。YOLO格式的标签文件与图片同名每一行对应一个目标框格式是class_id x_center y_center width height注意这里的x_center、y_center、width、height都是归一化到0~1之间的比例值不是像素坐标。比如一张1280x720的图上一个人头部目标框中心在(640, 360)宽300高500那么txt里记录的就是0 0.5 0.5 0.234375 0.694444类别编号上我建议这样定义0表示person正常站立/行走的人1表示fall已经跌倒的人。如果你打算完全依靠模型识别跌倒状态那直接把跌倒的人标成fall就能用如果你像我一样还叠加了规则层做时序判断那么fall类别可以作为“可疑跌倒”事件触发条件后面的规则层再做最后确认。两种方案并不冲突我推荐都保留。标注的时候有两个容易忽略的细节。第一个是遮挡情况下的框怎么打。门框挡住一半的人框要按人体可见部分来打不要脑补完整的身体轮廓模型学的是“当前画面里能看见的部分长什么样”给它完整框反而会把背景也学进去。第二个是框的边界要贴紧物体。很多标注工具默认的框会松一些这在分类模型里无所谓但检测模型的回归头很敏感松紧不一致会引入噪声。2.3 数据增强与样本平衡YOLOv8内置了丰富的数据增强策略包括mosaic、随机仿射变换、hsv颜色扰动、翻转、mixup等。默认配置就能用不需要自己太折腾。但有几个参数我会根据项目需求微调。比如水平翻转这个增强在跌倒检测场景里要注意方向语义。一个人从左往右走被识别成从右往左走问题不大但“左腿先跪地”和“右腿先跪地”的动作细节如果翻转了画面视觉上其实还是可以接受的所以水平翻转我保留。不过垂直翻转我建议关掉因为监控摄像头不会倒着拍垂直翻转会导致模型学到不真实的空间关系。另一个重要的参数是mosaic。YOLOv8默认前70%左右的训练epoch会启用mosaic增强把四张图拼在一起训练这能显著提升模型对遮挡和小目标的鲁棒性。但最后的10个epoch代码会自动关闭mosaic并转为精细拟合这个设计是合理的不用改。要注意的是如果你的数据集很小拼图后每个目标都变得很小模型可能学不好这种情况下可以把mosaic概率从1.0降到0.5。跌倒样本数量少的时候最直接的平衡手段是重复抽帧和硬负样本挖掘。所谓硬负样本就是那些“看起来像跌倒但实际不是”的样本比如人蹲下系鞋带、躺在床上睡觉、瑜伽动作中的卧姿。把这些样本单独抽出来数量不需要太多但一定要有否则模型会傻傻地把所有横躺的人体都判成跌倒。3. YOLOv8训练全过程与调参3.1 环境搭建与依赖清单先说一下环境我的训练机器是8G显存的图形卡内存16G系统是Ubuntu。Python版本用3.8到3.10都行PyTorch装2.x版本。安装YOLOv8官方仓库之后依赖基本会自动装好主要就是torch、torchvision、opencv-python、numpy这几个。显存不够的同学也别慌YOLOv8的模型体积从小到大是n、s、m、l、x五档。我用yolov8s做主要实验的时候batch size设为16640x640输入分辨率显存占用大概7G左右刚好卡在8G卡的边缘。如果显存是6G建议换yolov8n或者把batch降到8。下面是我常设的建议表格可以照着试显卡显存推荐模型推荐batch备注4GYOLOv8n8~16训练时间较长6GYOLOv8s8~16性价比高8GYOLOv8s16我最终用的方案12GYOLOv8m16~32精度更高训练命令非常简洁官方仓库封装得比较好yolo detect train datafall.yaml modelyolov8s.pt epochs100 batch16 imgsz640 device0其中fall.yaml是数据配置文件里面写明训练集验证集路径和类别名train: ./dataset/train val: ./dataset/val nc: 2 names: [person, fall]这个配置文件要放在固定路径下训练的时候直接指定就行。3.2 超参数怎么定、学习率怎么调很多人拿到代码直接epochs300就开跑结果要么过拟合要么收敛极慢。先不要盲目追求epoch数量我的做法是先用epochs50跑一个快速实验看loss曲线和验证集指标的趋势再决定是否加长训练。优化器选择上YOLOv8默认是SGD初始学习率0.01动量0.937。SGD在检测任务里非常稳虽然收敛慢一点但不至于跑飞。如果你追求快速收敛也可以换成AdamW学习率设0.001。我对比过几次在跌倒检测这个任务上两者最终精度差别不大SGD稳定性更好最后我保留默认SGD方案。学习率策略里有一个容易踩坑的地方warmup阶段。YOLOv8默认有3个epoch的warmup也就是在训练刚开始时学习率从0线性增大到目标值。这个机制能避免前面几个batch因为权重还没初始化好而出现大梯度震荡。不要轻易把warmup关掉尤其在batch很小、单批次样本噪声大的时候。另一个要注意的是early stopping的patience参数。默认情况下训练过程会监控验证集的mAP如果连续多轮没有提升就会自动早停。这个参数建议设成20左右太小容易在指标还没完全稳定时草率结束太大又浪费时间。训练过程中我还会刻意开启AMP混合精度训练。如果显存有限AMP可以在几乎不损失精度的情况下节省大约一半显存。命令上加ampTrue即可有问题的场景主要是老显卡支持的算子不全新一点的卡基本没坑。3.3 训练结果怎么看、指标到什么水平算合格训练结束后不要只盯着最后的mAP数字我一般会打开runs/detect/train下的结果曲线重点看三个东西loss曲线、PR曲线、混淆矩阵。loss曲线方面训练集loss应该持续下降并最终趋于平缓验证集loss如果先下降后明显反弹那就是过拟合了——此时距离理想停止点已经过远应该回退到val loss最低点对应的权重文件。YOLOv8源码里保存的best.pt就是val指标最好的那一轮权重不用自己操心。PR曲线的形状很直观曲线越靠近右上角越好。在跌倒检测这个任务里我更关心召回率而不是精确率因为漏报一个跌倒事件可能造成严重后果而误报只是打扰系统可以在告警层做二次过滤。所以我最终选择权重时会优先看recall然后再看mAP0.5。一个合格线供参考当置信度阈值0.5、IoU阈值0.5时mAP0.5如果能到0.86以上模型基本是能用的mAP0.5:0.95能到0.6以上就算不错了。还有一个容易被忽略的检查项是类别分布。打开混淆矩阵如果fall类被预测成person的比例很高说明正样本特征学习不足如果被预测成背景的比例高说明标注框或样本数量有问题。我第一版训练时混淆矩阵里fall被大量预测成person后来重新补充了跌倒样本并且去掉了那些框打得太松的标注再训练就明显改善。4. 推理脚本与可视化界面实现4.1 推理流程拆解从模型输出到事件判断训练完成后拿到权重文件接下来要做的是把它变成实际能用的推理模块。加载模型的代码不复杂官方仓库提供了接口核心是后面的处理逻辑要理清楚。from ultralytics import YOLO model YOLO(best.pt) results model(frame, conf0.45, iou0.45)conf是置信度阈值iou是NMS的IoU阈值。这两个参数非常影响使用体验。置信度阈值设得太低比如0.25会有大量低质量检测框冒出来误报增加设得太高比如0.7又容易漏检跌倒这种可能身体扭曲、遮挡的样本。我实测下来conf0.45是一个比较平衡的位置NMS的iou0.45保持默认即可。模型输出的框和类别只是一个“画面检测结果”要变成“跌倒事件”还需要做一层逻辑判断。我这里采用了两阶段方案模型层面把跌倒的人标记为fall类如果单帧中出现fall类的置信度大于0.5标记为“可疑跌倒”。规则层面连续N帧我取5帧大约0.2秒中如果存在任何一个fall类目标或者检测到的person框宽高比突然变大宽大于高的1.2倍并且该框在画面中的位置变化不大就触发真正的跌倒告警事件。为什么要有第二层因为单帧检测模型只认“当前这帧里是否有人躺在地上”这个静态特征。一个人摔倒后如果还能动画面里可能会有一两帧检测成正常姿态然后又被检测成跌倒态单帧判断就容易误报。通过连续多帧统计把高频抖动过滤掉告警的稳定性会好很多。反过来如果模型直接认定一个人躺着就是跌倒睡觉场景就会误报警回。所以我还会在规则层判断一下这个“跌倒框”在连续多帧里是否保持静止——真正跌倒后人通常短时间内不太会大幅移动。推理性能方面如果把YOLOv8s跑在CPU上640x640的输入大概每帧要150到300毫秒勉强能看但不适合实时。建议至少在带CUDA的显卡上跑。如果部署目标是树莓派或者Jetson这类设备建议用yolov8n导出成ONNX再配合TensorRT或者OpenVINO加速还能再快不少。4.2 可视化界面怎么搭界面我用了PyQt5理由很简单跨平台、控件丰富、画图方便。整个界面分三个区域左边是主预览区显示原始视频流和模型画框后的结果右边是信息面板显示当前FPS、检测到的目标数量、告警次数、最近的告警时间底部是事件日志区用文本记录每一次告警发生的时刻和当时的置信度。PyQt5开发时最容易翻车的点其实是在线程里做推理导致界面卡死。很多人把推理循环直接写在主线程里视频流一跑起来整个窗口就转圈圈不能操作。正确做法是用QThread把视频读取和推理放到后台线程主线程只负责接收信号并刷新画面。我一般定义两个信号一个update_frame信号把带画框的图像传给主界面显示一个alarm_triggered信号专门负责触发告警弹窗和日志更新。这样即便推理偶发延迟界面也不会卡死。代码结构上大概是这个思路class DetectThread(QThread): update_frame pyqtSignal(QImage) alarm_triggered pyqtSignal(dict) def run(self): while self.running: ret, frame cap.read() if not ret: break # 推理、画框、跌倒判断 self.update_frame.emit(qimage) if is_fall_event: self.alarm_triggered.emit({...})主界面里再写两个槽函数一个负责刷新图像显示一个负责弹窗告警这样职责就清楚了。界面上额外做了两个比较实用的功能一个是告警截图保存触发告警时自动把当前帧按时间戳命名保存到本地文件夹方便事后回顾另一个是告警静默时段比如夜间23点到早上7点关闭声音提醒只保留画面提示避免误报打扰休息。这两个功能并不是必须的但实际用户在验收时非常看重。4.3 工程化与落地细节从能跑通的demo到真正能用的系统中间还差一段路。下面几个点是我在实际调试中遇到最多、也最推荐的工程化处理方式。摄像头拉流的分辨率控制。家用摄像头很多是1080p或者2K直接把原始分辨率送进模型会非常占算力。建议先用OpenCV把帧缩放成960x540或者1280x720再喂给模型精度损失很小但FPS能提升一大截。画面缩放要保比例。模型训练用的输入是640x640方形但摄像头画面通常是16:9或4:3如果强行拉伸成方形目标框会失真。用letterbox处理把原始画面等比缩放后填充灰色边缘模型检测效果才稳定。告警联动接口。可视化界面只是展示端真正交付时通常还要对接消息通知。我留了一个alarm_callback回调函数触发告警时调用这个函数里面可以放微信通知、邮件通知或者蜂鸣器控制。这样界面和告警渠道解耦后面接入新渠道不用改主逻辑。模型导出。开发调试阶段直接加载.pt文件最方便但交付的时候依赖PyTorch环境太笨重。我通常会导出ONNX格式再用ONNXRuntime加载部署时只需要装一个onnxruntime包体积小很多CPU推理速度也比原生PyTorch快一些。5. 常见问题与排查经验速查5.1 六个高频问题和解决建议下面是这个项目里我总结的高频问题速查表基本覆盖了从训练到部署可能遇到的典型状况。问题现象可能原因解决办法训练时CUDA out of memorybatch太大或模型太大降batch、换yolov8n、开AMP混合精度loss不降或者震荡剧烈学习率太大、warmup被关学习率降到0.005恢复默认warmupval loss先降后涨过拟合减小epoch、提前早停、加大数据增强mAP低但训练loss正常数据不足、标注质量差、类别不平衡补样本、清洗标注框、用硬负样本跌倒事件频繁误报单帧模型把卧姿正常行为判成跌倒调高conf阈值、加时序规则、补睡觉/蹲下负样本界面拖动或按钮卡顿推理跑在主线程把推理和拉流放到QThread信号槽刷新界面5.2 我踩过的几个坑详细聊一下第一个坑是负样本缺失导致的“躺下即跌倒”误报。第一版训练时我偷懒只标注了正常人和跌倒两类没有把“人躺在床上盖被子”“人躺在沙发上睡觉”这些场景纳入训练集。结果在真实测试里一旦画面中出现躺卧姿态模型毫不犹豫就报跌倒。后来我从公开的卧室、客厅场景中截了几百张“人躺着但未跌倒”的样本标成person类补进去误报立刻降了一个量级。记住跌倒检测的核心难点不是把跌倒认出来而是把“类似跌倒但不是跌倒”的情况排除掉。第二个坑是训练集和推理画面的纵横比不一致。我的训练数据大多来自公开数据集很多是4:3比例但实际部署的摄像头是16:9宽屏。最初我没做letterbox直接把画面缩放成方形导致检测框出现系统性偏移——人的腿在画面边缘时框总是往上跑。后来我统一了训练和推理的预处理方式训练阶段就按640x640 letterbox处理推理阶段也做同样处理问题就消失了。这个坑非常隐蔽如果你发现检测框在画面边缘偏移明显优先查预处理是否一致。第三个坑是验证集指标好看但现场拉胯。有一次模型在验证集上mAP高达0.9但接到真实摄像头后误报频繁。一查才发现真实场景是顶视摄像头而训练数据大多是平视视角。模型从平视学到的“人体”语义在俯视画面里完全变了样。这个问题的解决没有捷径只能老老实实采集目标视角的数据哪怕数量少一点也比单纯堆平视数据有用。所以我后来特意在模拟现场架了一台俯视摄像头录了一段时间数据加入训练集效果才真正稳定下来。5.3 后续在这个项目上还能怎么扩展这个项目目前是基于目标检测的后续如果要进一步提升准确率有两个方向我认为很值得探索。第一个方向是引入姿态估计用YOLOv8-pose把人体关键点检测出来然后通过关键点坐标计算身体主轴与地面的夹角这个角度比包围框的宽高比更能反映“跌倒”姿态。第二个方向是加入时序模型把连续几帧的检测结果输入一个轻量级LSTM或GRU让模型学习“从站立到倒地”的动态过程而不是只看静态帧。这两种方案都会增加计算量但能把误报率再压低一个档次。还有一个更轻量的思路是多机位融合。如果场景里同时有多个摄像头可以分别在每个机位上做检测然后把同一时间内的告警事件做投票或者加权判断。当一个机位因为遮挡不确定时另一个机位的视角可以弥补这对养老院这类多房间部署场景很实用。工程上没有太大难度主要是把各机位的时间戳对齐设计一个简单的事件聚合器。最后再分享一个实测下来的小技巧不要一上来就盯着大模型刷精度先用yolov8n或者yolov8s把整个流程跑通从数据到训练到界面到告警全部调好再回头换大模型提精度。很多同学卡在训练环节反复试参数连界面都没碰过结果后面才发现数据集本身有问题白白浪费了大量时间。另外数据集质量永远比模型大小重要花时间去标注一批高质量、高多样性的跌倒样本回报比换任何模型都大。这个项目的源码、训练权重和可视化界面都打包好了拿到手先不改任何参数直接跑一遍官方给的示例数据确认环境没问题再换自己的数据从训练开始走一遍整个流程会很顺畅。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑