简介基于Python的YOLOv7人员跌倒检测系统完整项目包面向计算机视觉方向的学生、研究者与开发人员可用于在养老机构、公共区域或家庭等场景中实时识别跌倒行为并触发警报。压缩包共20个文件包含1个Python源码脚本、1个Markdown说明文档、1个txt使用说明文本和17张检测效果与样本图片整体体积14.9MB结构清晰便于本地运行与二次开发。系统采用YOLOv7目标检测框架结合OpenCV与PyTorch等常用库覆盖数据准备、模型训练、评估优化到系统集成的完整流程教程部分对库安装与部署步骤给出了可操作的指引。代码具备良好扩展性除跌倒检测外还可迁移至危险动作识别、异常停留监测等安全监控场景。目前已有199人学习使用源码注释简洁效果图直观适合作为课程设计、毕设项目或入门YOLO算法实践的参考资料。1. 跌倒检测为什么绕不开 YOLOv7帧率才是监控场景的硬指标在养老院或者独居老人的客厅里架一台摄像头跌倒检测的价值只有一个老人倒地后能不能在几十秒内被发现。真正做过实时监控的人会明白这个场景里精度高但帧率上不去的检测器在四路视频流同时推流时会被直接拖死。YOLOv7把重参数化卷积和辅助训练头用在同一个框架里在同等算力下能跑到远超两阶段模型的FPS所以跌倒检测这类必须实时响应的任务选它基本没有悬念。这套资源把训练代码、运行教程和跌倒数据集打包在一起目标是让有Python基础的人从零复现出可用的跌倒识别原型。它适配的人群很清晰做毕设的本科生、想快速验证方案的算法工程师以及给安防或养老场景做POC的集成商。2. 源码包拆解从解压到首轮推理的完整走读拿到压缩包之后第一件事不是急着看代码而是先把目录结构和运行入口摸清楚。跌倒检测本质上就是YOLOv7目标检测的一个分支应用因此整个项目沿用了YOLOv7的骨架训练入口、推理入口、模型配置、数据配置各占一块只要分清这些模块后面的操作就有了明确坐标。2.1 目录结构与每个文件的职责清单解压后你会看到一批文件和若干截图。README.md是这个包的说明书里面写明了训练步骤和常见问题listdir.py是一个辅助脚本用来递归列出图片目录的完整路径方便你在准备数据集时核对文件名和目录层级剩下的PNG是运行效果截图和标注预览图帮你在还没跑通之前先看到预期结果。文件/目录本包中的体现职责train.py训练入口源码加载yaml配置并启动YOLOv7训练detect.py推理入口源码对图片、视频或摄像头做跌倒检测export.py模型导出源码把PyTorch权重转成ONNX等格式data/fall.yaml数据配置定义训练集/验证集路径和类别名cfg/training/yolov7.yaml模型配置定义网络深度、宽度与anchorsrequirements.txt依赖清单列出Python库及版本号方便复现环境README.md教程文档安装、训练、部署的完整说明listdir.py辅助工具遍历目录输出完整路径用来核对数据集文件名实际运行时YOLOv7源码的执行路径一般是先有图片和标签再改yaml配置然后用train.py训练出权重接着用detect.py做推理验证最后用export.py导成ONNX/TorchScript。这套包把三个入口都放在根目录下适合按推理、训练、导出的顺序操作。绝大多数情况下你不必改网络内部结构真正的改动都发生在两个yaml文件和后处理逻辑上。如果解压后目录结构对不上多半是解压工具的问题而不是源码缺失。2.2 依赖安装与第一轮推理验证我习惯先把推理链路跑通再去碰训练。理由是推理链路更短能一次性验证环境、权重、解码和后处理是否连通一旦通了后面的训练和部署就都有了参照基准。先建一个干净的虚拟环境并安装依赖conda create -n fall python3.8 conda activate fall pip install torch1.13.1 torchvision0.14.1 pip install opencv-python numpy matplotlib pyyaml tqdm pillow tensorboard这里固定PyTorch版本的原因很现实YOLOv7的导出脚本对TorchScript和ONNX的边角兼容性比较敏感用发布方验证过的版本可以减少前后不兼容带来的麻烦。如果换用更高的PyTorch版本训练大概率没问题但在export.py转ONNX时偶尔会碰到“不支持的op”一类报错排查起来反而浪费时间。安装完依赖后把包内的训练权重放到weights目录下执行第一轮推理python detect.py --weights weights/best.pt --source data/fall_video.mp4 --conf 0.35 --img-size 640 --save-txt这段命令的含义是用best.pt做推理输入是data目录下的跌倒视频置信度阈值取0.35输入图像缩放到640x640同时把检测结果保存成txt坐标文件。置信度阈值取0.35是跌倒场景的常见起点——跌倒是小概率高价值事件宁可误报多一点也不能漏报所以比默认的0.25高一些但又不至于高到0.5那样把躺姿漏掉。如果这一步能正常输出带框的视频说明环境与源码是通的。此时建议顺手打开输出目录的txt文件从坐标反推一下框的位置确认类别索引对应的正是fall这个类。这一步能省掉训练时很多对不上号的困惑也能让你对YOLOv7的输出结构建立直观认知。如果手边没有现成视频把source参数改成0可以调起USB摄像头做实时推理用来验证流程同样有效。3. 跌倒数据集的处理标注格式、类名核对与样本分布训练能不能出效果一半取决于数据集而数据集的第一道坎不是数量而是标注格式是否与YOLOv7对齐。很多第一次跑的人在这一步翻车不是因为模型不行而是标签压根没有被正确解析。3.1 标签格式与目录组织YOLOv7使用的标签是纯TXT格式每行对应一个目标结构固定为类别ID和归一化坐标。跌倒数据集中一般只有两个类0对应person1对应fall或者反过来具体以data/fall.yaml里的names顺序为准。在动手训练之前务必先用脚本核对标签里出现的类别ID和data配置里的names顺序是否一致顺序不一致会直接导致模型把人和跌倒的人学反。标签字段列序号取值范围含义class_id00或1跌倒数据集中0代表person、1代表fallx_center10.0~1.0目标框中心点的横坐标相对图片宽y_center20.0~1.0目标框中心点的纵坐标相对图片高width30.0~1.0目标框宽度相对图片宽height40.0~1.0目标框高度相对图片高归一化坐标的好处是训练时图片无论怎么缩放标签都不会失效这也是YOLOv7内部加载器能够直接使用的格式。目录组织上训练时必须保证图片路径和标签路径按固定规则对应标签与图片同名且labels目录和images目录同级。我曾见过有人把标签导出成XML或者多加了1个坐标维度结果训练时YOLOv7直接把第五列当成了类别IDloss曲线一路乱跳训练结束后怎么调都调不回来。这里给出一个五分钟能跑完的校对脚本它的逻辑很简单依次遍历训练图片找到同名txt标签检查每行是否正好5列并确认坐标值没有越界from pathlib import Path img_dir Path(datasets/fall/images/train) label_dir Path(datasets/fall/labels/train) empty_txt [] for img in img_dir.glob(*.jpg): label_path label_dir / (img.stem .txt) if not label_path.exists(): empty_txt.append(img.name) continue lines label_path.read_text().strip().splitlines() for line in lines: parts line.split() if len(parts) ! 5: print(f格式异常: {label_path} - {line}) print(f共发现 {len(empty_txt)} 个无标签图片文件)这段脚本只是最基础的体检建议在正式训练前每天都跑一遍。它存在的最大价值不是打印几个警告而是迫使你在一开始就确定标签格式是干净的后面训练报错时可以第一时间排除数据问题。3.2 样本分布检查与清洗脚本只检查格式远远不够样本分布不均匀的训练集会让模型在场景切换时突然失灵。跌倒数据集里最典型的问题是站姿样本特别多、躺姿样本稀缺因为采集跌倒动作时大多是从站立到倒地这一小段。如果两类样本数量差距超过10比1模型很容易把所有站姿都当成背景漏检率居高不下。我一般会做两步第一步统计每张图片的目标数量和类别ID占比算出哪些图片包含困难样本比如被遮挡的人、只露出一半身体的跌倒第二步把包含多个目标的复杂图片单独挑出来和简单样本按比例混着训练而不是让它们淹没在大量零目标图片里。这一步在YOLOv7里尤其值得做因为它的辅助训练头会把正负样本分配做得更激进复杂样本带来的梯度信息比简单样本宝贵得多。统计类别占比的脚本也很基础直接遍历标签目录就能得出分布from collections import Counter class_counter Counter() total_frames 0 for label_path in label_dir.glob(*.txt): lines label_path.read_text().strip().splitlines() if not lines: continue total_frames 1 for line in lines: class_id int(line.split()[0]) class_counter.update([class_id]) for cid, cnt in class_counter.most_common(): print(f类别 {cid}: {cnt} 个目标框) print(f有效 TXT 文件数: {total_frames})跑完后重点看fall类框数与person类框数的比例。如果fall明显偏少一种可操作的做法是从现有视频里抽帧补标另一种是保留下载包里提供的数据增强配置用YOLOv7自带的Mosaic增强来扩充上下文。Mosaic在训练配置里由超参文件控制默认开启它会把四张图拼成一张训练对跌倒这种单帧内目标姿态变化剧烈的场景收益非常明显比手动多标几百张图省力得多。4. 训练自己的跌倒模型从 yaml 配置到损失曲线数据准备到位后训练阶段的关键改动集中在两个yaml文件上。YOLOv7官方代码对这两个文件的管理比较明确数据配置几乎每个项目必改模型结构配置大多数情况直接沿用默认。4.1 数据 yaml 与模型 yaml 的改动点数据yaml比如fall.yaml需要改的部分只有三块训练集路径、验证集路径、类别名列表。跌倒检测通常只有两类写法如下train: datasets/fall/images/train val: datasets/fall/images/val nc: 2 names: [person, fall]这里nc必须与names列表长度一致并且与标签文件里的类别ID一一对应。很多第一次跑的人会在这里把person和fall顺序写反训练过程一切正常推理时却把所有跌倒的人都画成person这个坑在部署阶段非常难用肉眼发现。模型yaml即cfg/training/yolov7.yaml重点保持nc和fall.yaml一致其他depth_multiple、width_multiple、anchors参数一律不动因为这些参数与预训练权重的结构绑定擅自改动会让迁移学习失效。4.2 启动训练与超参调整启动训练的命令在官方代码里是标准写法。常见做法是把数据集的父目录和预训练权重放在同一级然后执行python train.py --data data/fall.yaml \ --cfg cfg/training/yolov7.yaml \ --weights yolov7.pt \ --batch-size 8 \ --epochs 100 \ --img-size 640 \ --hyp data/hyp.scratch.yaml几个核心参数单独说明。batch-size取8是因为跌倒数据集里的图片普遍分辨率不低而多数开发机的显卡显存只有12G左右8是一个安全起步值。如果显存不够先把batch-size降到4而不是去降低img-size因为跌倒检测里小目标本来就多图片缩小会把细节全部吞掉。epochs取100是建立在预训练权重已经对通用目标有很好表征的基础上从头训练则至少需要250个epoch以上。超参文件hyp.scratch.yaml里真正值得动的是学习率lr0和Mosaic开关。lr0默认约0.01配合预热阶段完全够用不要盲目调大。Mosaic增强默认开启训练跌倒数据时建议保留它对跨场景泛化的贡献比想象中大。训练过程中用tensorboard实时盯两条曲线loss和mAP0.5。第一次训练结束后不要急着改参数先根据曲线形态判断是欠拟合还是过拟合再做第二轮微调。如果loss降得很慢而mAP也不涨优先检查数据配置而不是怀疑网络结构。4.3 评估指标与模型导出训练结束后脚本输出的评估结果中mAP0.5、mAP0.5:0.95以及precision/recall是三个核心参考。对跌倒检测场景我更看重recall而不是precision。原因很简单误报可以靠后端的时序滤波压下去漏报却直接威胁人身安全。指标含义跌倒场景的预期做法mAP0.5IoU0.5时的平均精度均值重点看它跌倒检测对定位精度不敏感mAP0.5:0.95多IoU阈值下的综合精度说明框的贴合程度要求不必过苛刻recall所有跌倒目标中被检出的比例尽量提高漏检代价高于误报precision检出框中真正正例的比例稍低可接受靠时序滤波修正导出模型时使用官方export.py即可python export.py --weights runs/train/exp/best.pt \ --img-size 640 \ --batch-size 1 \ --grid \ --simplify这里--grid确保导出后的模型输出带有完整的网格感知结构--simplify对ONNX做计算图简化两个参数缺一不可。不带上它们导出的模型在部分推理引擎里会出现输出维度错位看起来精度没变但框的位置全乱。5. 部署推理避坑指南四个高频翻车点与排查方法训练和推理跑通只算成功了一半把模型搬到监控场景以后问题才开始显形。下面四个翻车点都是我实际踩过的按现象、原因、解决三步写清楚。5.1 检测不到“跌倒”这一类别现象验证集上mAP挺高但对真实场景视频做推理时跌倒的人要么不出框要么被识别成person。原因通常有两类第一是许多人跌倒时的姿态与弯腰捡东西、蹲下系鞋带高度重叠模型在训练数据里把蹲也学成了正样本第二是标签类别ID写反导致推理时把跌倒框全画成了人。解决方法是先跑一遍标签统计脚本确认类别ID分布再看归一化坐标里是否有大量中心点相同的重复框排除标注错位。如果都不是就把conf阈值下调到0.2观察是否出现置信度在0.2到0.3之间的跌倒框。有的话说明模型学对了特征只是阈值卡太严属于正常的工艺调整而不是模型坏了。5.2 摄像头推理掉帧严重现象本地视频推理流畅换成USB摄像头或者RTSP流之后FPS从30掉到个位数。原因是摄像头读帧默认串行处理YOLOv7的预处理、推理、后处理三块都阻塞在同一线程里任何一块慢都会把整条流水线拖垮。解决方法是把读帧放到独立线程里让检测线程永远能拿到最新一帧同时把输入尺寸从640降到480或416。这样换来的精度损失在跌倒这类大目标场景里几乎感知不到FPS却能翻倍。另一个隐性开销是摄像头解码格式建议把摄像头输出强制设为MJPG而不是默认的YUYV后者在USB带宽紧张时会进一步拖慢取帧。5.3 导出 ONNX 后精度掉了一截现象PyTorch直接推理mAP有0.85转成ONNX后在相同的测试集上跌到0.6左右。原因大多是导出时没带--grid和--simplify以及用了PyTorch新版本里不支持的算子导致部分op被回退。另一类原因跟模型本身无关导出时的batch-size和推理引擎的batch-size不一致。解决方法是先用官方export.py带上--grid --simplify重新导出再用onnxruntime做一个单样本推理对比输出维度与推理引擎的解析结果。如果维度一致但精度仍然掉检查推理引擎是否开启了FP16。跌倒数据集中目标尺寸偏大FP16通常无感但背景纹理复杂的帧会出现明显的精度抖动。5.4 一开训练就 OOM现象把batch-size设成4还报CUDA out of memory。原因多半是data yaml里开了cache-images把整个数据集一次性缓存在显存或内存里另一类原因是workers并行加载图片过多数据加载线程占用了过多CPU资源GPU长时间等待而显存被临时张量占满。解决方法是把cache-images关掉、batch-size降到2并把workers设为0跑一遍确认稳定后再逐步加回。还有一个常见误操作是同时开着tensorboard和多个验证脚本显存的预留给挤占之后训练自然容易溢出。6. 让检测结果更稳帧级预测的时序滤波与报警小技巧单帧检测结果直接拿去触发报警在真实监控环境中就是每小时误报几十次的灾难。摄像头的轻微抖动、光影变化、一个人蹲下来系鞋带都能让单帧置信度瞬间冲高。所以做跌倒检测项目时我一定会加一道时序滤波层作用是把某一帧检测到跌倒变成连续一段时间内多次检测到跌倒。一个简单好用的实现是滑动窗口投票维护一个长度为N的队列每来一帧就推入当前帧的检测结果跌倒为1否则为0队列满时把队首弹出。当队列中跌倒帧的比例超过阈值且最近一次命中与当前帧的时间差不大于M秒时才触发报警。from collections import deque class FallWindowVote: def __init__(self, window_size10, vote_ratio0.6, expire_sec3.0, fps15): self.queue deque(maxlenwindow_size) self.vote_ratio vote_ratio self.expire_frames int(expire_sec * fps) self.last_hit -1_000_000 def update(self, is_fall): now len(self.queue) self.last_hit self.queue.append(int(is_fall)) if is_fall: self.last_hit now recent sum(self.queue) / len(self.queue) fresh now - self.last_hit self.expire_frames return recent self.vote_ratio and fresh参数含义window_size为10意味着看最近10帧vote_ratio为0.6表示10帧里至少6帧判定跌倒才给报警信号expire_sec是过期时间防止几秒前的旧帧造成延迟报警。实际部署时把fps换成你的推理帧率即可不同摄像头按需调整。时序滤波加上之后还有一个容易忽视的点报警信号不要在检测循环里写死封装成独立回调更好。检测线程只负责输出是否跌倒和最后的框坐标报警线程单独消费这个信号。这样后面接短信、微信或声光报警器推送逻辑时不影响检测主循环的帧率。我从那以后做监控类目标检测都会强制让帧级检测结果先过一道时序滤波再谈告警这套过滤参数并不玄学但在跌倒场景里真的避免了一大批看似命中、实际误报的尴尬。整个项目的训练代码、教程和跌倒数据集已随资源打包解压后按README走一遍就能复现希望帮到你。本文还有配套的精品资源点击获取