ARTICLE DETAIL

资讯详情

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

YOLOv5+OpenPose摔倒检测:从环境搭建到时序建模的完整实战

YOLOv5+OpenPose摔倒检测:从环境搭建到时序建模的完整实战 简介这份资源面向计算机视觉方向的本科毕业生与深度学习入门者提供一套可直接运行的摔倒检测完整方案解决人体姿态识别与跌倒行为判定的工程落地问题。项目以YOLOv5完成人体目标检测结合OpenPose提取骨骼关键点再通过动作分类模型判断摔倒状态覆盖从数据采集、关键点生成到模型训练的完整链路并支持按需扩展其他姿态类别。压缩包共193个文件约40.29MB包含39个Python脚本、17个YAML配置、2个pt权重与2个jit模型文件以及75张jpg、11张jpeg样本图片和若干txt、md说明文档另附Dockerfile与依赖配置便于环境复现。目前已有1243人学习下载。读者可获得经导师认可、严格调试通过的毕业设计源码与全部数据直接用于课题复现、二次开发或姿态分类迁移实验省去从零搭建检测与分类流程的时间成本。1. 摔倒检测这套方案到底在做什么从 YOLOv5 到 OpenPose 的完整链路摔倒检测这件事很多人第一反应是「拿个分类网络跑一下不就行了」。真上手就知道纯分类模型在真实场景里几乎没法用——人蹲下、弯腰捡东西、快速坐下这些动作在单帧图像上和摔倒高度相似误报能把人逼疯。所以工业界和毕设里比较稳的做法是把「人体框检测」和「骨架关键点」两条线拼起来YOLOv5 负责在画面里快速框出人OpenPose 负责把框内的人体骨架关键点提出来最后靠关键点的几何关系比如躯干倾角、髋膝踝的相对位置、关键点速度来判断这个人是不是摔了。这套「YOLOv5 OpenPose 摔倒检测」的组合正好是计算机毕业设计、人工智能专业毕业设计里非常典型的一个选题也是 yolov5 训练自己的数据集、yolov5 部署这类热搜词背后最常见的落地场景之一。它适合谁适合手上有 Python 基础、想做一个能跑通、能演示、能写进论文的完整视觉项目的人。整套链路的核心价值在于YOLOv5 保证实时性OpenPose 保证姿态精度摔倒判定逻辑保证可解释性——三者缺一不可。下面我按「环境怎么搭 → 数据怎么准备 → 两个模型怎么串 → 判定逻辑怎么写 → 坑在哪」的顺序把这条链路拆开讲清楚。2. 环境配置与两个模型的选型理由为什么不是 YOLOv8 也不是 MediaPipe2.1 YOLOv5 和 OpenPose 各自解决什么问题先把职责分清楚不然后面串的时候容易乱。YOLOv5 在这里只做一件事输入一帧图像输出若干个人体边界框bounding box格式是[x1, y1, x2, y2, conf, cls]。它不关心这个人是什么姿态只关心「这里有没有人」。选 YOLOv5 而不是 YOLOv8主要原因是毕设场景下 YOLOv5 的生态最成熟——yolov5 源码结构清晰、yolov5 环境配置的教程最多、conda yolov5 的踩坑帖遍地都是出问题好查。YOLOv8 精度略高但如果你只是做摔倒检测YOLOv5s 或 YOLOv5m 完全够用而且推理速度更快对树莓派5上部署自己训练的yolov5模型这类需求更友好。OpenPose 负责第二步拿到 YOLOv5 裁剪出来的人体区域输出 18 个或 25 个 COCO 格式的关键点坐标鼻子、脖子、肩膀、手肘、手腕、髋、膝、踝等。为什么不用 MediaPipeMediaPipe 确实轻量、部署简单但它的关键点在遮挡场景下抖动明显而且它是单人姿态估计画面里多人时处理起来反而麻烦。OpenPose 的 PAFPart Affinity Fields机制对多人场景更稳关键点置信度输出也更完整适合做摔倒这种对时序稳定性要求高的任务。代价是 OpenPose 模型大、推理慢所以必须用 YOLOv5 先做人体检测来缩小 OpenPose 的输入范围这就是两个模型串联的根本原因。2.2 用 conda 搭一套能跑通的 YOLOv5 环境环境这块我踩过最多的坑就是版本冲突。PyTorch、CUDA、torchvision 三者版本必须对齐否则要么 import 报错要么推理时 CUDA 报 illegal memory access。下面这套是我验证过能跑通的组合Python 3.8 PyTorch 1.10 CUDA 11.3适配 YOLOv5 6.x 版本。# 创建独立环境避免污染系统 Python conda create -n fall_detect python3.8 -y conda activate fall_detect # 安装 PyTorch注意 cuda 版本要和本机驱动匹配 # 如果本机没有 NVIDIA 显卡把 cu113 换成 cpu pip install torch1.10.0 torchvision0.11.0 torchaudio0.10.0 --extra-index-url https://download.pytorch.org/whl/cu113 # 安装 YOLOv5 依赖requirements.txt 在 yolov5 根目录 cd yolov5 pip install -r requirements.txt # 验证环境是否正常 python -c import torch; print(torch.cuda.is_available())这段命令的逻辑是先隔离环境再装 GPU 版 PyTorch最后装 YOLOv5 的依赖。关键参数说明——cu113对应 CUDA 11.3如果你本机是 CUDA 12.x可以换成cu121但 PyTorch 1.10 官方只提供到 cu113所以要么降驱动要么升 PyTorch 版本。torch.cuda.is_available()返回True才算 GPU 可用返回False说明驱动或版本不匹配这时候别急着往下走先把这一步解决掉。OpenPose 的安装更麻烦官方 CMake 编译对新手不友好。我一般推荐用现成的 Python 封装比如openpifpaf或者直接调用 OpenPose 的 C 编译产物。如果只是毕设演示用openpifpaf能省掉大量编译时间# openpifpaf 是 OpenPose 的轻量替代API 更友好 pip install openpifpaf # 测试单张图片的关键点提取 python -m openpifpaf.predict test.jpg --json-output -o output.json--json-output会把关键点坐标输出成 JSON方便后续和 YOLOv5 的检测框做匹配。-o指定输出目录。这一步跑通说明姿态估计这条线没问题了。提示如果你坚持用原版 OpenPose编译时一定要开BUILD_PYTHON选项否则后面 Python 调用会找不到模块。编译时间大概 20 到 40 分钟取决于机器性能。3. 数据集准备与 YOLOv5 训练自己的数据集从标注到跑通第一个 epoch3.1 摔倒数据集的构成和标注要点摔倒检测的数据集一般分两部分一部分是通用人体检测数据用来训练 YOLOv5 的人体框另一部分是摔倒/非摔倒的姿态序列数据用来调判定逻辑。YOLOv5 这边你至少需要标注 2000 到 5000 张包含人体的图片类别就一个person。标注工具用 labelImg 或 Roboflow 都行输出 YOLO 格式的 txt 文件每行是class_id x_center y_center width height坐标都归一化到 0 到 1 之间。摔倒数据这块公开数据集里 UR Fall Detection Dataset 和 Le2i Fall Detection Dataset 比较常用前者有 RGB 和深度图后者是视频片段。如果你要做时序判定建议把视频按帧拆开每 5 帧取一帧标注这一帧的状态站立、行走、坐下、摔倒。注意摔倒的标注不要只标摔倒瞬间那一帧要把摔倒前 0.5 秒到摔倒后 1 秒的帧都标上这样判定逻辑才有足够的时间窗口去计算关键点速度。3.2 YOLOv5 训练命令和关键参数怎么调数据准备好之后目录结构要按 YOLOv5 的要求来images/train、images/val、labels/train、labels/val然后写一个data.yaml指向这些路径。# data.yaml path: ./fall_dataset train: images/train val: images/val nc: 1 names: [person]nc是类别数这里只有 person 一类所以是 1。names要和标注时的类别顺序一致。这个文件放错位置是新手最常见的翻车点YOLOv5 会报Dataset not found其实就是路径没对上。训练命令如下# 从预训练权重开始训练yolov5s.pt 是最小的模型 python train.py \ --img 640 \ --batch 16 \ --epochs 100 \ --data data.yaml \ --weights yolov5s.pt \ --cfg models/yolov5s.yaml \ --name fall_yolov5s参数说明--img 640是输入分辨率摔倒检测里人通常占画面比例不大640 够用想更准可以上 1280 但显存翻倍。--batch 16是批大小显存不够就降到 8 或 4。--epochs 100对 5000 张图来说差不多看 loss 曲线不再下降就可以停。--weights yolov5s.pt是加载预训练权重这一步千万别省从零训练收敛慢而且精度低。--name是这次训练的输出目录名结果会存在runs/train/fall_yolov5s/下面。训练过程中重点看三个指标box_loss、obj_loss、mAP0.5。box_loss 下降说明框的位置越来越准obj_loss 下降说明模型对「有没有人」的判断越来越稳mAP0.5 到 0.85 以上基本就能用了。如果 mAP 卡在 0.5 上不去先检查标注有没有漏标或错标再考虑加数据或换更大的模型。注意yolov5 超参数里--lr0默认是 0.01如果你用自己的数据集且数据量小于 2000 张建议降到 0.001否则容易过拟合。这个参数在hyp.scratch.yaml里也能改。4. 把 YOLOv5 和 OpenPose 串起来推理流程与摔倒判定逻辑4.1 两阶段推理的代码实现串接的核心思路是YOLOv5 先跑一遍拿到人体框把每个框裁剪出来送给 OpenPose 做关键点提取最后把关键点坐标映射回原图坐标系。下面这段代码是整个流程的主干。import cv2 import torch import numpy as np # 加载 YOLOv5 模型 model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/fall_yolov5s/weights/best.pt) model.conf 0.5 # 置信度阈值低于这个值的框不要 def detect_person(frame): 用 YOLOv5 检测人体框返回裁剪后的人体区域和原图坐标 results model(frame) boxes results.xyxy[0].cpu().numpy() # [x1, y1, x2, y2, conf, cls] persons [] for box in boxes: x1, y1, x2, y2 map(int, box[:4]) # 留一点边距避免关键点被裁掉 pad 20 x1 max(0, x1 - pad) y1 max(0, y1 - pad) x2 min(frame.shape[1], x2 pad) y2 min(frame.shape[0], y2 pad) crop frame[y1:y2, x1:x2] persons.append({crop: crop, bbox: (x1, y1, x2, y2)}) return persons def get_keypoints(crop): 对裁剪区域做姿态估计返回关键点坐标相对裁剪区域 # 这里用 openpifpaf 做示例实际可替换为 OpenPose import openpifpaf keypoints openpifpaf.predict(crop) return keypointsmodel.conf 0.5这个阈值很关键。设太低会框到背景里的杂物设太高会漏掉远处的人。摔倒检测场景里我一般用 0.4 到 0.5 之间宁可多框几个再靠后续逻辑过滤。pad 20是给裁剪区域留边距因为 OpenPose 对边缘关键点估计不准如果紧贴着框裁手腕和脚踝的关键点容易丢。4.2 摔倒判定的三个几何特征关键点拿到之后怎么判断摔没摔我用的是三个特征组合躯干倾角、髋部高度变化、关键点速度。躯干倾角是脖子到髋部中点的连线与垂直方向的夹角。站立时这个角度小于 30 度摔倒时通常大于 60 度。但光看角度不够因为弯腰捡东西也能到 60 度所以要看第二个特征髋部高度。摔倒时髋部会快速下降到接近地面用髋部关键点的 y 坐标除以画面高度如果这个比值在短时间内从 0.5 以上掉到 0.3 以下就是强摔倒信号。第三个特征是速度。摔倒是一个快速过程从站立到倒地通常不超过 1 秒。计算髋部关键点在连续 10 帧内的 y 方向位移速度如果速度超过阈值比如每秒下降 0.3 个画面高度结合前两个特征就能确认摔倒。def compute_fall_score(keypoints_history): 根据关键点历史序列计算摔倒得分 if len(keypoints_history) 10: return 0.0 # 取最近 10 帧的髋部中点 hip_y [kp[hip_center][1] for kp in keypoints_history[-10:]] # 髋部下降速度 velocity (hip_y[-1] - hip_y[0]) / len(hip_y) # 躯干倾角 angle keypoints_history[-1][torso_angle] # 综合评分 score 0.0 if velocity 0.02: # 下降速度阈值 score 0.4 if angle 60: # 倾角阈值 score 0.3 if hip_y[-1] 0.6: # 髋部接近地面 score 0.3 return scorevelocity 0.02这个阈值是归一化后的意思是每帧髋部下降超过画面高度的 2%。angle 60是躯干倾角阈值单位是度。hip_y[-1] 0.6表示髋部已经到画面下方 60% 的位置。三个条件各占 0.4、0.3、0.3 的权重总分超过 0.7 就判定为摔倒。这套权重是我在 UR Fall 数据集上试出来的你可以根据自己的场景微调。提示判定逻辑一定要加时间窗口平滑单帧判定必然抖动。我一般用 10 帧的滑动窗口窗口内超过 7 帧判定为摔倒才触发报警这样能过滤掉大部分误报。5. 避坑与排查这套链路最容易翻车的五个地方5.1 现象YOLOv5 检测框抖动严重同一个人框忽大忽小原因视频帧间没有做跟踪YOLOv5 是逐帧独立检测帧间抖动是正常的。解决加一个简单的 IOU 跟踪器比如 SORT 或 ByteTrack把帧间同一个人的框关联起来再做关键点提取。这样不仅框稳定了关键点序列也连续了速度计算才准。5.2 现象OpenPose 关键点置信度低手腕脚踝经常丢原因裁剪区域太小或者分辨率太低OpenPose 对小于 100x100 的人体区域估计效果很差。解决YOLOv5 的输入分辨率从 640 提到 1280或者把裁剪区域放大到 256x256 再送 OpenPose。另外如果画面里人很小考虑用 YOLOv5m 或 YOLOv5l 替代 YOLOv5s。5.3 现象摔倒判定误报率高坐下和蹲下都被判成摔倒原因只看单帧的躯干倾角和髋部高度坐下和蹲下的特征和摔倒高度重叠。解决引入时序特征计算髋部下降的加速度。摔倒的加速度是突然的尖峰坐下是平缓的。用加速度峰值检测能有效区分。另外加一个「摔倒后是否保持倒地」的判断坐下之后人会很快站起来摔倒后通常会有几秒的静止。5.4 现象GPU 显存不够两个模型同时加载就 OOM原因YOLOv5 和 OpenPose 都占显存如果 batch 设大了或者输入分辨率高了显存直接爆。解决YOLOv5 用 FP16 推理model.half()OpenPose 用轻量版模型或者把两个模型分时加载——先跑 YOLOv5 拿到所有框释放 YOLOv5 的显存再加载 OpenPose 处理裁剪区域。树莓派5上部署自己训练的yolov5模型时这个策略尤其重要。5.5 现象训练时 loss 不下降mAP 一直是 0原因最常见的是 data.yaml 路径写错或者标注文件的类别 ID 不是从 0 开始。解决先跑python train.py --data data.yaml --img 640 --batch 4 --epochs 1做一次单 epoch 测试看能不能正常读取数据。如果报No labels found检查 labels 目录下是不是空的或者文件名和 images 目录下的图片名对不上。YOLOv5 要求图片和标注文件同名只是扩展名不同。6. 进阶技巧用关键点序列做时序建模把误报再降一半前面讲的几何特征判定本质上还是手工规则在复杂场景下天花板有限。如果你想让毕设的含金量再上一个台阶可以把关键点序列送进一个轻量时序模型比如 LSTM 或 1D-CNN让模型自己学摔倒的时序模式。具体做法是把每个人连续 30 帧的 18 个关键点坐标x, y, confidence拉成一个 30x54 的矩阵作为 LSTM 的输入输出是摔倒/非摔倒的二分类。import torch.nn as nn class FallLSTM(nn.Module): def __init__(self, input_size54, hidden_size64, num_layers2): super().__init__() self.lstm nn.LSTM(input_size, hidden_size, num_layers, batch_firstTrue) self.fc nn.Linear(hidden_size, 2) # 二分类 def forward(self, x): # x shape: (batch, seq_len, input_size) out, _ self.lstm(x) # 取最后一个时间步的输出 out self.fc(out[:, -1, :]) return outinput_size54是 18 个关键点乘以 3 个值x, y, confidence。hidden_size64是 LSTM 隐藏层维度太大容易过拟合太小欠拟合。num_layers2是两层 LSTM一般两层够用。训练数据就用你标注好的摔倒序列正负样本比例控制在 1:3 左右负样本包括站立、行走、坐下、蹲下、弯腰。训练完之后把 LSTM 的输出和前面的几何规则做加权融合规则得分占 0.4LSTM 得分占 0.6这样既有可解释性又有学习能力。验证方法上我习惯用留出法把 UR Fall 数据集按视频片段划分70% 训练30% 测试确保同一个视频的帧不会同时出现在训练集和测试集里否则准确率会虚高。测试时重点看两个指标召回率摔倒有没有漏报和误报率正常动作有没有被误判。摔倒检测里召回率比准确率重要宁可误报也不能漏报所以阈值要往召回率方向偏。最后说个我自己的习惯每次改完判定逻辑我都会拿一段包含「坐下、蹲下、捡东西、摔倒」四种动作的视频跑一遍把每种动作的得分曲线画出来看。如果坐下和摔倒的得分曲线有重叠区域说明特征还不够区分得继续加特征或者调权重。这个笨办法帮我省了很多次「论文写完才发现误报率爆炸」的后悔药。希望帮到你。本文还有配套的精品资源点击获取
返回列表