简介:这份资源是面向深度学习入门与计算机视觉实践者的YOLOv5摔倒检测、跌倒识别完整项目包,适合需要完成课程设计、毕业设计或安防场景算法验证的学生与开发者。包内共193个文件,约40.29MB,以jpg、jpeg图像样本和py源码为主,辅以yaml、yml配置、pt权重、pyc缓存及Dockerfile、md说明等,覆盖数据、训练配置与推理脚本,下载后按文档配置环境即可运行。项目难度适中,源码经过本地编译验证,内容经助教审定,能直接满足学习与使用需求。目前已有487人学习下载。读者可获得一套可复现的跌倒识别方案,包括标注数据、模型配置、训练与检测代码,以及OpenPose相关的jit模型文件,便于快速跑通流程、理解YOLOv5在行为识别任务中的落地方式,并在此基础上做二次开发与效果调优。
1. 摔倒检测这件事,为什么 YOLOv5 依然是性价比最高的起点
如果你正在找yolov5 摔倒检测 跌倒识别项目源码+全部数据,大概率是三种人之一:要交毕设的学生、要给养老院或工地做 Demo 的工程师、或者想拿一个完整数据集练手目标检测的转行者。这三种人的共同诉求其实很一致——要一套能跑起来、能复现、能改的完整方案,而不是一篇讲注意力机制的论文。
摔倒检测本质上是一个「人体姿态 + 时序判断」的问题,但绝大多数落地项目最后都退化成了「目标检测 + 规则判断」。原因很现实:姿态估计模型(如 HRNet、MediaPipe)在遮挡、侧躺、快速倒地这些场景下关键点抖动严重,而 YOLOv5 直接检测person和fall两类框,配合宽高比和框中心高度变化做二次判断,鲁棒性反而更好,部署也简单——树莓派 5 上跑量化后的 YOLOv5s 完全可行。
这套方案适合谁?适合想用最小成本跑通「数据集标注 → 训练 → 推理 → 报警逻辑」全链路的人。它不追求 SOTA 精度,但能让你在两天内看到一个真实可用的跌倒识别 Demo。下面我按自己实际做过的顺序,把选型、数据、训练、部署和踩坑一次讲清楚。
2. 从标注到训练集:摔倒数据集的构建与 YOLO 格式转换
2.1 为什么摔倒检测的数据集比模型更决定成败
先说一个血泪经验:摔倒检测项目翻车,90% 不是模型问题,是数据问题。公开数据集里,UR Fall Detection 只有几十段视频,Le2i 场景单一,真正能用的标注数据非常稀缺。所以「全部数据」这四个字在标题里出现,说明这个项目的核心价值其实在数据集,而不是那几百行训练代码。
摔倒检测的数据有几个硬性要求,缺一个模型就会学偏:
- 正负样本比例:跌倒帧和正常行走帧的比例建议控制在 1:3 到 1:5。全是跌倒帧,模型会把「弯腰捡东西」也判成跌倒。
- 场景多样性:至少覆盖室内地板、床边、卫生间、室外水泥地四类背景,否则换个摄像头就废。
- 姿态多样性:前扑、后仰、侧倒、坐地滑倒都要有,只标「躺在地上」的框,模型学不会「正在倒」的中间状态。
- 标注粒度:建议只标
person和fall两类。不要标standing、sitting,那会让类别数膨胀且边界模糊。
我一般会把数据组织成下面这个结构,和 YOLOv5 官方要求完全对齐:
fall_dataset/ ├── images/ │ ├── train/ # 约 70% │ ├── val/ # 约 20% │ └── test/ # 约 10% ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yaml2.2 用脚本把 VOC/COCO 标注转成 YOLO txt
很多现成数据集是 VOC 的 XML 格式,YOLOv5 只认归一化的 txt。转换脚本我写过不下十遍,下面这版是最稳的,处理了边界框越界和空标注两个高频坑:
import os import xml.etree.ElementTree as ET from PIL import Image # 类别映射:0=person, 1=fall CLASS_MAP = {"person": 0, "fall": 1} def voc_to_yolo(xml_dir, img_dir, out_label_dir): os.makedirs(out_label_dir, exist_ok=True) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(".xml"): continue tree = ET.parse(os.path.join(xml_dir, xml_file)) root = tree.getroot() # 图片尺寸从实际图片读取,不要信 XML 里的 size,经常是错的 img_name = root.find("filename").text img_path = os.path.join(img_dir, img_name) w, h = Image.open(img_path).size lines = [] for obj in root.iter("object"): cls_name = obj.find("name").text.strip().lower() if cls_name not in CLASS_MAP: continue # 忽略未定义类别,避免训练时报错 bbox = obj.find("bndbox") x1 = float(bbox.find("xmin").text) y1 = float(bbox.find("ymin").text) x2 = float(bbox.find("xmax").text) y2 = float(bbox.find("ymax").text) # 裁剪到图像边界,防止归一化后出现负数或 >1 x1, y1 = max(0, x1), max(0, y1) x2, y2 = min(w, x2), min(h, y2) if x2 <= x1 or y2 <= y1: continue # 无效框直接丢弃 cx = (x1 + x2) / 2.0 / w cy = (y1 + y2) / 2.0 / h bw = (x2 - x1) / w bh = (y2 - y1) / h lines.append(f"{CLASS_MAP[cls_name]} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}") out_file = os.path.join(out_label_dir, xml_file.replace(".xml", ".txt")) with open(out_file, "w") as f: f.write("\n".join(lines)) voc_to_yolo("annotations_xml", "images_all", "labels_all")逻辑说明:CLASS_MAP决定类别顺序,必须和data.yaml里的names完全一致,否则训练不报错但推理全乱。图片尺寸从 PIL 实时读取而不是用 XML 里的<size>,是因为很多标注工具导出的尺寸和实际图片对不上,这是最常见的「训练 loss 不降」元凶之一。边界裁剪和无效框丢弃这两步,能避免 YOLOv5 在 dataloader 阶段抛出negative width之类的报错。
参数说明:cx/cy/bw/bh全部归一化到 0~1,保留 6 位小数足够。如果你的数据集里fall类特别少,可以在转换后统计一下每类框数量,再决定是否用--weights做类别加权。
2.3 data.yaml 与训练集划分的三个必调项
转换完标注,data.yaml是训练入口,写错一个字段就是几小时白跑:
path: /home/user/fall_dataset train: images/train val: images/val test: images/test nc: 2 names: ['person', 'fall']必调项一:path用绝对路径,别用相对路径,YOLOv5 在不同工作目录下启动时相对路径解析经常出玄学问题。必调项二:nc必须等于names长度,多一个少一个都会在加载时崩。必调项三:训练集和验证集的图片文件名不能重名,否则 YOLOv5 缓存机制会把标签张冠李戴,这个坑我踩过一次,排查了两小时。
划分比例上,如果总图片少于 2000 张,建议 train:val:test = 8:1:1,验证集太小会导致mAP波动大,看不出真实效果。划分时按「视频段」而不是「帧」来分,同一段视频的帧不能同时出现在训练和验证集,否则验证精度虚高,这是时序数据划分的铁律。
3. YOLOv5 训练摔倒检测模型:环境、超参与收敛判断
3.1 conda 环境配置与版本锁定
yolov5环境配置是搜索量最高的长尾词之一,因为版本不匹配的报错能劝退一半人。我一般用 conda 建独立环境,锁死这几个版本:
conda create -n fall_yolo python=3.8 -y conda activate fall_yolo # 先装 torch,注意 CUDA 版本要和驱动匹配 pip install torch==1.13.1 torchvision==0.14.1 --index-url https://download.pytorch.org/whl/cu117 # 再装 yolov5 依赖,不要直接 pip install -r 全量,容易冲突 pip install numpy opencv-python pyyaml tqdm matplotlib pandas seaborn pip install ultralytics==8.0.0 # 如果用官方仓库则 clone 后 pip install -e .逻辑说明:Python 3.8 是 YOLOv5 兼容性最好的版本,3.10 以上在部分torchvision算子上有兼容问题。torch 和 CUDA 必须匹配,cu117对应驱动 515+,装错会报CUDA driver version is insufficient。不要一次性pip install -r requirements.txt,里面有些包版本会互相顶,按需装更稳。
参数说明:如果你只有 CPU,把--device设为cpu,但训练会慢 20 倍以上,建议至少用一张 8G 显存的卡。树莓派 5 上只做推理,不做训练。
3.2 训练命令与超参数怎么改
YOLOv5 的训练命令看着简单,但每个参数都影响收敛:
python train.py \ --data data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --hyp data/hyps/hyp.scratch-low.yaml \ --device 0 \ --project runs/fall \ --name exp1逻辑说明:--weights yolov5s.pt用预训练权重,摔倒检测数据量小,从头训几乎不可能收敛。--img 640是精度和速度的平衡点,摔倒目标通常占画面 1/3 以上,640 够用;如果摄像头很远,改 1280 但显存翻倍。--batch 16在 8G 显存下比较稳,显存不够就降到 8 并加--accumulate 2模拟大 batch。
超参数文件hyp.scratch-low.yaml适合小数据集,如果数据超过 5000 张,换成hyp.scratch-high.yaml。重点看三个值:lr0初始学习率默认 0.01,小数据集建议降到 0.001;mosaic马赛克增强默认 1.0,摔倒场景建议降到 0.5,因为过度拼接会让「倒地」这种整体姿态被切碎;fl_gamma是 focal loss,类别不平衡时设 1.5 能明显提升fall类召回。
3.3 怎么判断模型真的收敛了
yolov5训练自己的数据集最让人焦虑的就是「loss 不降」和「mAP 不涨」。我的判断标准是三条:
第一,看runs/fall/exp1/results.csv,train/box_loss在前 10 个 epoch 应该明显下降,如果平着走,八成是标签路径错了或类别数不对。第二,metrics/mAP_0.5在 50 epoch 后应该稳定在 0.85 以上(摔倒检测这种二分类任务),低于 0.7 说明数据质量有问题。第三,看val/box_loss和train/box_loss的差距,如果验证 loss 持续上升而训练 loss 下降,就是过拟合,加数据或加--dropout。
一个反直觉的点:摔倒检测不要盲目追求高 mAP。fall类的召回率比精度重要得多,漏检一次跌倒的代价远大于误报一次。所以看指标时优先看metrics/recall,必要时把置信度阈值从 0.25 降到 0.15,宁可多报不可漏报。
4. 推理、报警逻辑与树莓派 5 部署
4.1 单帧检测到跌倒判定的规则层
YOLOv5 只给你框,判定「是否跌倒」需要自己写规则。我一般用「宽高比 + 框中心高度 + 连续帧」三条件:
import cv2 import numpy as np def is_fall(box, img_h, prev_centers, fall_counter): x1, y1, x2, y2 = box w, h = x2 - x1, y2 - y1 aspect = w / max(h, 1) # 宽高比,倒地时通常 > 1.2 center_y = (y1 + y2) / 2 / img_h # 归一化中心高度,倒地时偏下 # 条件一:宽高比异常 或 中心明显偏低 shape_flag = aspect > 1.2 or center_y > 0.65 # 条件二:连续 N 帧都满足,避免单帧误判 if shape_flag: fall_counter += 1 else: fall_counter = max(0, fall_counter - 1) return fall_counter >= 5, fall_counter逻辑说明:aspect > 1.2捕捉横向倒地的框,center_y > 0.65捕捉画面下方的异常姿态。fall_counter是防抖计数器,连续 5 帧满足才报警,单帧抖动直接忽略。这个规则层比直接训一个时序模型简单得多,实测误报率能压到可接受范围。
参数说明:1.2和0.65这两个阈值要按你的摄像头高度和视角调。摄像头装得高,center_y阈值要调大;装得低,宽高比更可靠。建议先用测试集跑一遍,画出aspect和center_y的分布直方图再定阈值。
4.2 树莓派 5 上部署自己训练的 YOLOv5 模型
树莓派5上部署自己训练的yolov5模型是最近的热词,我实际跑过,结论是:能跑,但必须量化。原始yolov5s.pt在树莓派 5 上单帧要 1.5 秒,量化成 ONNX 再转 NCNN 后能到 200ms 左右。
# 第一步:导出 ONNX python export.py --weights runs/fall/exp1/weights/best.pt --include onnx --img 640 # 第二步:ONNX 转 NCNN(在 PC 上做,树莓派算力不够) pip install onnxsim ncnn python -m onnxsim best.onnx best_sim.onnx # 用 ncnn 官方工具转换 onnx2ncnn best_sim.onnx best.param best.bin逻辑说明:onnxsim先做图简化,去掉冗余算子,否则onnx2ncnn容易报不支持的操作。转换后在树莓派上用ncnn的 Python 绑定推理,输入尺寸保持 640,预处理用cv2.dnn.blobFromImage保持一致。
参数说明:树莓派 5 建议开--img 320做推理,速度能再快一倍,精度掉 3~5 个点,摔倒检测够用。如果要用摄像头实时,用picamera2库抓帧,别用cv2.VideoCapture,后者在树莓派上延迟高。
4.3 报警联动与误报抑制
检测到跌倒后,报警方式决定项目能不能落地。我一般做三级:本地蜂鸣器、MQTT 推送到网关、截图存证。误报抑制除了前面的连续帧计数,再加一个「静止判定」——如果框在 3 秒内位置几乎不变且宽高比异常,才最终确认,这能过滤掉「蹲下系鞋带」这类动作。
MQTT 推送用paho-mqtt,消息体带上时间戳和置信度,方便后端做二次确认。截图存证按日期/小时分目录,避免单目录文件过多导致树莓派 IO 卡顿。
5. 摔倒检测项目避坑清单:5 个我真实踩过的坑
5.1 坑一:训练 loss 正常但推理全是 person
现象:训练时mAP看着有 0.8,推理时所有框都标成person,fall类一个都不出。原因:data.yaml里names顺序和标注转换时的CLASS_MAP不一致,模型学到的类别索引错位。解决:转换脚本和data.yaml用同一个常量文件定义类别,别手写两遍。
5.2 坑二:验证集精度虚高,换场景就崩
现象:验证集mAP0.95,拿到新摄像头上一测,正常走路也报警。原因:训练集和验证集按帧随机划分,同一段视频的相邻帧同时进了两边,模型等于「背答案」。解决:按视频段划分,同一段视频的所有帧只进一个集合。
5.3 坑三:树莓派上 ONNX 推理结果和 PC 不一致
现象:PC 上检测正常,树莓派上框位置偏移或置信度全乱。原因:预处理不一致,PC 用了 letterbox 填充,树莓派直接 resize 变形。解决:两端统一用 YOLOv5 的letterbox函数,保持长宽比填充灰边,推理后再把框映射回原图坐标。
5.4 坑四:fall 类召回率低,漏检严重
现象:跌倒动作快,模型经常漏掉中间帧。原因:fall类样本少且集中在倒地后的静止帧,缺少「正在倒」的过渡帧。解决:在标注时把倒地过程中的 3~5 帧也标成fall,并降低推理置信度阈值到 0.15,配合连续帧计数。
5.5 坑五:长时间运行内存泄漏
现象:树莓派跑几小时后卡死。原因:每帧都新建cv2.Mat和推理 session,Python GC 跟不上。解决:推理 session 全局初始化一次,帧缓冲复用,每 1000 帧手动gc.collect(),并限制截图存证的分辨率。
6. 把摔倒检测做到能交付:一个提升召回率的采样技巧
最后一章讲一个我实际交付时用的技巧:难例回采 + 类别重加权。摔倒检测的瓶颈从来不是模型结构,而是fall类样本太少、太相似。我的做法是,第一轮训练完不急着调参,而是拿模型在验证集和一段真实场景视频上跑推理,把所有「漏检的跌倒帧」和「误报的正常帧」单独抽出来,人工复核后加进训练集,再跑第二轮。
具体操作上,用下面的脚本把漏检帧自动导出:
# 用第一轮模型跑推理,保存漏检帧 import torch model = torch.hub.load('ultralytics/yolov5', 'custom', path='runs/fall/exp1/weights/best.pt') for frame in video_frames: results = model(frame) preds = results.pandas().xyxy[0] # 如果该帧有 fall 标注但模型没检出,存为难例 if has_fall_gt(frame) and not any(preds['name'] == 'fall'): cv2.imwrite(f"hard_examples/{frame_id}.jpg", frame)逻辑说明:has_fall_gt是你自己的标注比对函数,判断这一帧是否真的有人跌倒。把漏检帧存下来后,重新标注并加入训练集,第二轮训练时把fall类的损失权重调高,YOLOv5 里可以通过复制fall类样本来近似实现。
参数说明:难例回采一般做 2~3 轮就够了,再多容易过拟合到特定场景。每轮回采后重新划分验证集,确保验证集里也有难例,否则指标还是虚的。
我自己的习惯是,任何摔倒检测项目在交付前,必须在一段「没参与训练的真实视频」上跑满 24 小时,统计误报次数和漏报次数。误报超过 5 次/天,就回去加负样本;漏报超过 1 次,就降阈值加难例。这个笨办法比任何花哨的注意力模块都管用。希望帮到你。
本文还有配套的精品资源,点击获取