news 2026/11/3 0:13:51

YOLOv5+OpenPose摔倒检测实战:从训练到部署的完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
YOLOv5+OpenPose摔倒检测实战:从训练到部署的完整指南

简介:面向计算机专业毕业设计与课程设计需求,这份人工智能深度学习项目整合YOLOv5人体检测与OpenPose姿态估计,实现视频场景中的摔倒行为识别,可作为高分毕业设计(评审98分)的完整参考。项目源码与模型打包为zip,压缩包约40.25MB,核心代码和预训练权重均包含在内,便于直接复现与二次开发。项目亮点在于将目标检测与关键点姿态估计相结合:YOLOv5负责实时定位人体,OpenPose提取骨骼关键点,再通过角度、速度等特征判定摔倒状态,覆盖数据预处理、模型加载、推理逻辑到结果可视化的完整流程。读者可从中学习两套算法的协作方式、参数调优思路以及摔倒判断阈值设计,对于做大作业、期末项目或毕设开题均有实用价值。当前已有167人学习下载,适合具备一定Python和深度学习基础、希望快速搭建完整落地方案的学习者。

1. 摔倒检测为什么绕不开YOLOv5人体检测+OpenPose姿态检测

在养老院、独居老人家庭和医院病房的监控画面里,摔倒检测真正要回答的问题不是“画面里有没有人”,而是“这个人是不是以异常姿态倒到地面”。标题把 YOLOv5 人体检测和 OpenPose 姿态检测放在一起,是实际项目里最常见的组合:YOLOv5 先把人从背景里捞出来,OpenPose 再提取骨骼关键点,最后真正判断摔倒的是关键点之上的规则。只做人体框加宽高比判断,遇到弯腰和下蹲会误报;只上 OpenPose,多人遮挡时关键点会互相串,速度也不够。

这个方向适合正在做监控告警、银发经济相关产品的工程师,也适合拿这套组合做毕业设计的学生。本文会按我自己的工程习惯拆开讲:模型选型、训练数据、摔倒判据、组合代码骨架、常见坑和验收方法。你可以照着写一套能跑的流程,也能提前避开那些让人反复返工的问题。

2. 用YOLOv5训练和部署人体检测:网络结构、微调命令与最小推理

2.1 YOLOv5网络结构图和人体检测的最小模型选型

YOLOv5 不是单个黑盒模型,它由三块组成:CSPDarknet 骨干网络负责提取图像特征,PANet 路径聚合结构负责把不同尺度的特征融合起来,最后的检测头在三个尺度上分别输出预测框。yolov5网络结构图里最容易看到的是两个关键点:骨干网络借鉴了 CSPNet 的做法,把特征图分成两路再合并,减少重复梯度计算;检测头输出三层特征,分别对应小目标、中目标和大目标。对摔倒检测来说,小目标这一层尤其重要,因为远端摄像头下的人可能只占几十个像素。

我一般会选 YOLOv5s 作为默认起点。摔倒检测需要的是“人框”和“框内裁剪区域”,不需要像素级精细分割,也不需要对人的身份做长期识别,所以没必要上 YOLOv5l 或更重的模型。如果部署在树莓派这类设备上,可以再降一档到 YOLOv5n,后续通过量化把推理速度拉回来。选型时还要看摄像头安装高度:斜向下 45 度视角最舒服,人体的长宽比变化和关键点可见度都比较理想;真正的俯视视角压力很大,建议不要只依赖预训练权重。

还有一种常见误区:拿 COCO 预训练模型直接做人体检测,认为已经包含 person 类,就不用再训练了。COCO 的 person 类在水平视角、日常场景下效果很好,但在病房、楼道、单人间这类固定视角下,会出现很多异常姿态,比如人蜷缩在地上、被被褥部分遮挡、只露出腿,预训练模型很容易漏检。所以凡是长期固定安装的摄像头,我都建议抽帧补训。后面几节就按“微调自有数据”来写。

2.2 用YOLOv5训练自己的数据集:数据准备、配置YAML和超参数

先解决标注。用 LabelImg 或 Labelme 都可以,导出 YOLO 格式的 txt 文件。每行是class x_center y_center width height,四个坐标值都除以了图片宽高,所以是 0 到 1 之间的比例值。标注时有个容易踩的问题:人体框只框可见部分还是框完整身体?我的经验是,可见部分超过一半就框可见区域,被严重遮挡的不要硬框。摔倒检测中“半个人”的框会造成关键点裁剪不完整,反而干扰后续 OpenPose。

标注内容不要只标行人。要从部署摄像头的真实视频里抽帧,既包含站姿、走路、坐姿,也要包含倒地、侧卧、蜷缩、被椅子遮挡。负样本也很重要,空房间、无人时段、光影变化剧烈的帧都留一部分,防止模型在没人时把其他物体当成人。数据规模上,我做过最小可用的项目是 2000 张左右,其中 400 张是倒地姿态,效果已经能支撑后续报警逻辑;如果只有几百张,建议直接用公开人体检测数据集的 person 类先凑。

目录结构按这样组织:

datasets/person/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── person.yaml

person.yaml的内容很简单:

path: datasets/person train: images/train val: images/val nc: 1 names: 0: person

这个文件告诉训练脚本只有一类,类别名是 person。path建议写相对路径,或者写你当前机器上的绝对路径;换机器训练时,第一件事就是检查这个路径有没有对应错。

训练命令我常用下面这条:

python train.py --img 640 --batch 16 --epochs 50 \ --data datasets/person/person.yaml \ --weights yolov5s.pt \ --freeze 10

--img 640是训练输入尺寸。监控画面如果超过 1080p,可以保留 640,因为人体检测不需要看清人脸。--batch 16在 8G 显存上下比较稳妥,显存紧张可以改成 8;批量太小时 BN 层统计会不稳定。--freeze 10表示冻结前 10 层,也就是 backbone 的大部分,让训练只更新 neck 和 head,用少量数据也能微调成功。--epochs 50对这种单类微调足够,更多轮次反而容易把预训练特征学坏。

训练超参数要改的话,我一般关注学习率、数据增强和早停。yolov5 的--hyp参数可以指定 hyp 文件,其中lr0控制初始学习率,微调时建议从 0.01 降到 0.005;mosaic是马赛克增强,开启后小幅提升目标检测能力,但会把人切成碎片,对监控场景不是越强越好。还有一点要克制:不要给degrees设置太大,监控摄像头不会旋转画面,旋转增强过多会让模型学习到“倒着的人”这种错误先验。训练结束看runs/train/exp/weights/best.pt,推理和后续组合都用这个权重。

2.3 人体检测最小推理脚本:一个人体框怎么从帧里出来

拿到best.pt后,先单独验证人体检测,不要急着接 OpenPose。下面这个脚本从本地 YOLOv5 仓库加载模型,推理一帧图并画出框:

import cv2 import torch # 从本地仓库加载自定义权重 model = torch.hub.load('.', 'custom', path='runs/train/exp/weights/best.pt', source='local') model.conf = 0.25 # 置信度阈值,摔倒检测常用 0.25~0.35 model.iou = 0.45 # NMS 的 IoU 阈值,yolov5 后处理默认 0.45 model.classes = [0] # 只保留 person 类,过滤其他 79 类 model.imgsz = 640 # 推理分辨率 cap = cv2.VideoCapture(0) while True: ret, frame = cap.read() if not ret: break results = model(frame) dets = results.xyxy[0].cpu().numpy() # 每行: x1 y1 x2 y2 conf cls persons = [d for d in dets if int(d[5]) == 0] for x1, y1, x2, y2, conf, cls in persons: cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2) cv2.imshow('person detect', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()

torch.hub.load('.', 'custom', path=..., source='local')是从本地仓库加载,source='local'避免了每次都去访问远端库。model.conf和model.iou对应 YOLOv5 后处理里的两个关键参数:先按置信度阈值挑出候选框,再通过非极大值抑制去掉重叠框。model.classes = [0]会让所有非 person 类不出现在结果里,也减少后处理时间。

results.xyxy[0]是单张图的检测结果,每一行是x1, y1, x2, y2, conf, cls。这里我只保留了cls == 0的项,因为训练时 person 的类别 id 就是 0。需要注意conf不要调太高,监控场景中存在俯视、遮挡,0.5 以上的阈值会把倒地的人漏掉。我通常先用 0.25,把更多候选交给后面的姿态检测和状态机去过滤。待会把persons里的 x1 y1 x2 y2 传给 OpenPose 时,很多坑都出在“框太紧”“框太偏”上。

3. OpenPose姿态检测:摔倒的关键点特征从哪来

3.1 OpenPose在做什么:从关键点检测到摔倒判定的距离

OpenPose 的输出不是“这个人摔了”,而是每一个人的关键点坐标和置信度。它的核心思想是同时预测关键点热图(每个像素是某个关节的概率)和部分亲和场 PAF(编码关节之间连接方向的矢量场),再通过图匹配把关键点组装成完整骨架。常见权重输出 COCO 17 点或者 BODY_25 的 25 点,摔倒检测真正关心的是头、双肩、双肘、双髋、双膝、双踝这几组点。

很多人第一次用 OpenPose 会有错觉:既然它能输出所有人体的骨架,是不是可以替代 YOLOv5,直接用关键点框住人?实践里不行。OpenPose 在多人场景下的关键点匹配会互相串,尤其是两个人靠近、交叉、遮挡时,左肩可能接上另一个人的右手。摔倒检测要求的是“对同一个人的连续帧判断”,串点之后特征完全失真。另一个现实问题是速度:OpenPose 原版全图推理很慢,直接放在实时视频流里会卡。

所以我更愿意把 OpenPose 当“单人体检器”用:先用 YOLOv5 给出人的框,从框里裁剪出一个人,再让 OpenPose 输出这一人的关键点。这样既降低匹配难度,也减少算力消耗。不要被“项目源码”里的网络结构带偏,真正要设计的不是两个模型怎么拼接,而是关键点怎么变成告警信号。

3.2 摔倒检测三种特征:人体倾角、高度比率、速度突变

在关键点之上,我常用三种特征判断摔倒。第一个是躯干倾角,取左右肩中点与左右髋中点连线,计算它和竖直方向的夹角。正常站立时这个夹角接近 0 度,倒下去时会到 50 到 90 度。第二个是高度比率,用肩髋距离除以图片高度,或者除以这个人自己的站姿基准高度。倒地后这个值会明显变小。第三个是速度突变,取髋部中心的垂直速度,摔倒过程通常伴随一个明显加速下跌。

下面这个函数把三组特征都算出来:

def get_fall_features(kps, prev_kps, img_h): # kps 为 dict: {"left_shoulder":(x,y,conf), "right_shoulder":...} shoulder_c = midpoint(kps["left_shoulder"], kps["right_shoulder"]) hip_c = midpoint(kps["left_hip"], kps["right_hip"]) # 特征1:肩髋连线与重力方向的夹角 angle = angle_with_gravity(shoulder_c, hip_c) # 特征2:肩髋距离归一化到图像高度 body_h = distance(shoulder_c, hip_c) / img_h # 特征3:髋部垂直速度,单位像素/帧 vert_vel = 0.0 if prev_hip_c is not None: vert_vel = hip_c[1] - prev_hip_c[1] return angle, body_h, vert_vel

单独用倾角一定会误判,弯腰捡东西时躯干倾角也能超过 50 度。所以判定逻辑要组合:先出现速度突变,随后 0.5 秒内倾角超过阈值,同时高度比率跌到该人的站立基准以下。用代码表达就是:

if vert_vel > 15 and angle > 50 and body_h < fall_ref_height * 0.6: fall_count += 1 else: fall_count = 0

这里的fall_ref_height是这个人最初进入画面时记录下来的肩髋距离。为什么要用“该人自己的基准”?因为摄像头远近不同,同样的像素高度在不同距离代表不同真实高度。如果不做归一化,靠近摄像头的人弯腰会被当成摔倒,远处的人真摔了也检测不到。OpenPose 给出的关键点坐标是像素值,必须先除以基准尺度,再做阈值比较。

3.3 防抖与关键点置信:别让姿态噪声骗过判定器

关键点不是每次都可靠。OpenPose 输出的每个点带着置信度,遮挡、低分辨率、快速运动都会让置信度掉到 0.3 以下。如果直接拿低置信点算角度,会出现单帧内倾角来回跳 20 度。我的处理分两步:先过滤,再平滑。

过滤规则是:低于MIN_CONF的关键点直接置空,不参与计算;两个肩点缺一个时用另一个代替,两个都缺就跳过当前帧的倾角计算。平滑用指数移动平均,也就是常见的 EMA:

smooth_kps = alpha * current_kps + (1 - alpha) * previous_smooth_kps

alpha取 0.6 左右比较合适。太高会跟随噪声,太低会把摔倒那个“突然加速下跌”的信号抹平。摔倒过程通常在 0.5 到 1 秒内完成,如果 alpha 超过 0.8,速度突变几乎看不见。还有一个细节:左右肩点会在人体转身时交换,导致肩线方向突变。我不会直接用左右肩坐标算角度,而是先算肩线中点,再把“距离图像顶部更近的那个肩”记为上方,避免左右互换造成倾角虚假跳变。

4. YOLOv5+OpenPose组合工程:代码骨架、状态机与告警参数

4.1 组合流程和帧间关联:同一人跨帧怎么对应

组合流程我一般这样拆:第一,YOLOv5 检测当前帧,拿到所有人框;第二,对每个框做外扩裁剪,送入 OpenPose 得到该人的关键点;第三,用 IoU 方式把当前帧的人框和上一帧的人框关联起来,给同一人分配同一个轨迹 ID;第四,每个轨迹内部维护关键点历史和平滑结果,由摔倒状态机判断是否触发告警。顺序必须是检测、裁剪、姿态、跟踪、判定,不能反过来。

为什么要先做裁剪而不是全图姿态?因为 OpenPose 对输入分辨率很敏感。全图 1920x1080 直接送进去,人体只占很小区域,小目标关键点置信度普遍偏低;先用 YOLOv5 把范围缩小到一个人,再缩放到姿态模型输入尺寸,关键点质量会好很多。同时也能省算力。

裁剪时有个坑:不要按检测框严丝合缝地切。YOLOv5 的框通常紧贴身体,但 OpenPose 需要看到脚踝、手腕和头顶,框太紧会把关键点切掉一半。我会把检测框外扩 15% 左右:

def crop_person(frame, box, expand=0.15): x1, y1, x2, y2 = [int(v) for v in box] w, h = x2 - x1, y2 - y1 x1 = max(0, int(x1 - expand * w)) y1 = max(0, int(y1 - expand * h)) x2 = min(frame.shape[1], int(x2 + expand * w)) y2 = min(frame.shape[0], int(y2 + expand * h)) return frame[y1:y2, x1:x2]

expand可以根据人体框长宽比调整:站立的人上下各留多一些,倒地的人左右留多一些。这块没有统一标准,建议先固定 0.15,再用几段真实视频看关键点缺失情况。

帧间关联采用 IoU 追踪器。对当前帧每个检测框,和上一帧所有轨迹的框计算 IoU,最大 IoU 超过 0.3 就认为属于同一个人,否则新建轨迹。这个阈值比多目标跟踪常用的 0.5 低,因为摔倒过程中人体框形变很大,同一人前后两帧的框重叠度不一定高。跌倒检测不要求长期身份识别,只要求摔倒前后 1 秒内不要换 ID,所以 0.3 够用。

4.2 摔倒状态机与告警代码骨架

组合工程的代码骨架,关键是维护每个轨迹的“连续摔倒帧数”。下面是一个简化实现,但结构可以迁移到你的项目里:

class FallDetector: def __init__(self, angle_thresh=50, vel_thresh=15, need_frames=5): self.angle_thresh = angle_thresh self.vel_thresh = vel_thresh self.need_frames = need_frames self.tracks = {} def update(self, dets, poses, frame_id): alerts = [] for det, pose in zip(dets, poses): track_id = self._match_track(det) if track_id is None: track_id = self._create_track(det) tr = self.tracks[track_id] features = tr.update_features(det, pose) if features and self._is_fall(features, tr): tr.fall_cnt += 1 else: tr.fall_cnt = 0 if tr.fall_cnt >= self.need_frames: alerts.append(track_id) tr.fall_cnt = 0 tr.last_alert_frame = frame_id return alerts def _is_fall(self, feat, tr): # tr.ref_height 是该人站姿基准 if tr.ref_height is None: return False return (feat.angle > self.angle_thresh and feat.vert_vel > self.vel_thresh and feat.body_h < tr.ref_height * 0.6)

这个类没有包含追踪匹配的全部细节,但已经能表达核心:fall_cnt连续累加,累计到 5 帧才告警。need_frames=5按 25 帧视频算约 0.2 秒,既能滤掉单帧毛刺,也不会把告警拖到倒地之后好几秒。vel_thresh=15要小心,像素速度受图像分辨率影响,1080p 下取 15 像素/帧,如果改到 720p 需要等比缩小,改成 4K 则要放大。更稳妥的做法是把垂直速度除以肩髋基准高度,得到“每秒下跌几个身位”,这样阈值基本不随分辨率变化。

状态机里还有一个容易被忽略的点:告警后不要连续报警。同一个摔倒事件,如果状态机一直保持躺姿,fall_cnt可能会再累积,导致后台收到十几条重复消息。我习惯在告警后进入 10 秒冷却,冷却期间即使fall_cnt达标也不再推送。真正的中风和晕厥是摔倒后一直不动,需要的是 10 秒后进行一次“长时间未起身”复核,而不是反复报警。

4.3 yolov5后处理、量化与边缘部署参数取舍

把组合模型部署到边缘设备前,先要分清瓶颈在哪。yolov5 后处理包括缩放、锚框解码、NMS,这部分在 GPU 上耗时很低;OpenPose 的关键点热图计算才是大头。如果跑在树莓派 4B 这类设备上,官方 OpenPose 基本没有实时可能,常见做法是换用轻量姿态估计模型,或者把姿态分支输入降到 192x192。我自己在树莓派上部署时,把 YOLOv5 输入从 640 降到 320,再把 OpenPose 换成 ONNX 导出的单人姿态模型,勉强能跑到可用帧率,代价是远距离小目标会漏检。

对 rk3568 这类 NPU 平台,量化是绕不开的。YOLOv5 可以导出 ONNX 后用 RKNN Toolkit 做 int8 量化,姿态模型也可以量,但关键点热图对量化更敏感。量化后一定重新跑一遍测试集,不要只看正常帧,要看低对比度、暗光、快速倒地这几类帧。我的经验是姿态模型量化后误报概率会上升,常表现为脚踝点漂移到墙上、肩点跳到另一个人身上,所以边缘端更推荐把角度阈值调严格 5 到 10 度,用漏报率换误报率。

如果用 ROS 做机器人平台,可以单独把 YOLOv5 检测结果发成人体检测话题,姿态节点订阅话题后只处理人体框。这套解耦能让树莓派上的检测和姿态两个进程分开调度,避免一帧卡死整条链路崩溃。给后续维护留一点余地,代码结构比模型本身更重要。

5. 摔倒检测常见问题排查:五个坑与对应解法

5.1 俯视相机下YOLO漏检,人体框时有时无

【现象】摄像头装在屋顶或墙角高处,人走到画面正下方时,YOLOv5 经常不输出框;人侧躺在地上时,框只框住上半身,下半身被切掉。摔倒检测流程里最关键的人框都拿不到,后续姿态检测直接被跳过。

【原因】预训练 COCO 权重学到的“人”大多是水平视角的直立形象。俯视视角下,头顶、肩背占据画面大部分,腿脚被遮挡,这种特征分布和 COCO 差得很远。单纯把置信度阈值从 0.25 降到 0.1,只会把椅子、阴影、地上的包全检测成人,问题并没有解决。

【解决】必须从实际摄像头角度补样本。部署几台摄像头后抽 24 小时视频,把俯视、斜俯视、倒地蜷缩的姿态专门标出来,重新微调 YOLOv5。训练时关闭旋转增强,限制degrees=0,不然模型会学到“倒过来的人”这种不存在的情况。如果短期内拿不到足够的俯视数据,可以先保留预训练模型,同时加一个兜底检测规则:当 OpenPose 在全图模式下的关键点数量异常但 YOLO 没框时,触发一次弱置信度检测,不要直接丢掉。

5.2 关键点抖动导致摔倒误判,脚踝跳来跳去

【现象】OpenPose 输出的脚踝坐标在相邻帧之间跳动 20 到 30 像素,有时左脚踝和右脚踝互换位置。肩点在人体转身时也会左右交换,导致倾角特征瞬间从 10 度跳到 70 度,状态机因此误报。

【原因】一是单人裁剪图分辨率不够,脚踝只占十几个像素,热图峰值定位不稳定;二是 OpenPose 对左右关键点的匹配本身就按邻近关系,转身和遮挡时容易出现标签互换;三是对关键点没有做时间域平滑,单帧噪声直接进入判定。

【解决】把裁剪框外扩到 0.15 以上,并保留原始宽高比,用 letterbox 而不是拉伸方式缩放。关键点进入特征计算前做 EMA 平滑,alpha取 0.6 左右。左右肩、左右髋的计算改用中点,不要直接依赖某一侧坐标。如果脚踝抖动特别严重,可以在摔倒判定中降低脚踝权重,把主要判据放在肩髋连线和髋部下落速度上,脚踝只用来确认“人体已经接触地面”而不是用来计算角度。

5.3 弯腰捡东西误报成摔倒,特征阈值失效

【现象】老人在画面里弯腰捡钥匙,躯干倾角达到 60 度,持续时间超过 0.5 秒,状态机里fall_cnt一路累加,最后触发误报,护理人员在后台白跑一趟。

【原因】弯腰和摔倒的瞬间姿态非常像:躯干前倾、头部下移、肩髋连线倾斜。如果只靠倾角单特征判断,无论如何调阈值都会误伤。区别在于过程:弯腰时髋部高度变化不大,站立速度和倒地速度差一个数量级,而且弯腰结束后会主动恢复站姿,真正摔倒后基本不会在 1 秒内站起来。

【解决】把判定条件改成“速度突变 + 姿态保持”。先要求髋部垂直速度超过阈值,比如vert_vel > 12,再要求倾角大于 50 度且持续多帧。加入“倒地保持”后验条件:触发预备状态后,如果 0.8 秒内人体没有恢复到倾角小于 30 度,才推送告警。捡东西的人通常在 0.5 秒内恢复,不会跨过后验条件。代价是告警延迟增加 0.8 秒,对摔倒检测来说可以接受,因为摔倒过程本身会持续更久。

5.4 推理太慢帧率不足,管线串行卡成PPT

【现象】GPU 工作站上单看 YOLOv5 只要几毫秒,单看 OpenPose 也还好,但组合起来帧率掉到 5 到 8 帧,视频明显卡顿,摔倒动作被跳过很多细节。

【原因】很多工程把两个模型简单串在同一线程里,YOLOv5 跑完才跑 OpenPose,整帧延迟就是两者相加。OpenPose 在全图输入时计算量很大,而且 CPU 和 GPU 之间频繁拷贝图像数据,真正耗时在等待和数据搬运上。

【解决】先给系统分层。YOLOv5 固定跑在 GPU 上,只输出人体框;OpenPose 只对裁剪后的小图推理,不要全图跑。用两个线程或者两个队列解耦:检测线程持续出框,姿态线程从队列里取裁剪图处理,允许姿态结果比当前帧慢 100 到 200 毫秒。你可以在代码里把queue_size控制在 5,超过就丢弃最旧的帧,防止内存堆积。更极端的做法是每两帧跑一次姿态检测,中间帧用上一帧关键点线性插值,这样速度提升接近一倍,摔倒判断仍然连续。部署到树莓派 5 这类设备时,把 YOLOv5 输入降到 320,姿态输入降到 192,再做模型量化,比买更贵的硬件更实际。

5.5 画面边缘的小人体关键点全低置信,倒地检测不到

【现象】摔倒发生在画面左上角或者远端走廊,YOLOv5 给出的框只有 60x100 像素,裁剪后送入 OpenPose,所有关键点置信度都低于 0.3,过滤器直接把这些关键点置空,摔倒判定无法启动。最危险的是远处老人倒地,画面不是完全没人,但算法就是没反应。

【原因】OpenPose 对输入分辨率非常敏感。60x100 的人体缩小到姿态模型输入尺寸后,关键点真实信息只有几个像素,热图峰值不明确。另一方面,监控视频本身可能有 2K 甚至 4K 分辨率,但我们在读取帧时往往直接缩到 640,远端信息在预处理阶段就丢了一部分。

【解决】不要一上来就缩全图。用cv2.VideoCapture保持原始分辨率,YOLOv5 推理时使用 960 或 1280 输入,等拿到人体框再裁剪。注意model.imgsz越大,GPU 显存占用越高,实测时要看显存余量。另一个办法是为远端小目标单独开一路低置信度检测,conf=0.15,把结果交给跟踪器,用前一帧的姿态作为当前帧的预测先验,而不是直接丢弃。如果项目允许,优先调整摄像头点位,让关键区域的人体高度不小于画面的 5%,这是成本最低的解决方式。

6. 校准阈值:用难例视频做验收,别只看训练指标

模型训练完,yolov5 的 mAP 和 pose 的关键点准确率再高,也不代表报警系统能用。我在每个摔倒检测项目里都会单独建一个“验收视频集”,里面是现场采集的片段,标注出每一段是否真的摔倒、摔倒发生在第几秒。验收指标不用多,就要三个:召回率、误报次数、平均告警延迟。

计算方式可以很简单。把真实摔倒时间点记为true_fall,报警时间点记为alarm,在 2 秒内算一次命中:

true_fall = [12.5, 45.2] alarm = [12.4, 47.0, 103.8] tp = 0 for a in alarm: if any(abs(a - t) < 2 for t in true_fall): tp += 1 fp = len(alarm) - tp fn = len(true_fall) - tp recall = tp / len(true_fall) precision = tp / len(alarm)

这段代码不是统计级严谨,但足够衡量状态机是否“能用”。真正要盯的是fp,也就是误报次数。养老院场景里,一周超过 3 次误报,护理人员就会习惯性忽略告警,系统直接失效。

我的调参习惯是:先把阈值调到偏灵敏,让所有可疑事件都触发,把angle_thresh降到 40、need_frames降到 3,跑完整个难例集;然后逐条看误报,把弯腰、下蹲、跪地这些片段对应的特征值打印出来,再决定阈值放宽还是收紧到多少。比如发现弯腰片段角度是 55 度,但髋部速度只有 3,就把“速度阈值从 12 提到 15”或“增加持续时间确认”作为对策,而不是单纯提高角度阈值。

最后一次调完,我会把难例视频单独存成一个目录,不删掉,每次改网络结构或者更换部署平台都重新跑一遍。方法是从这套代码帮你解决上线 80% 问题,但真正能不能上线,取决于你手里的难例视频够不够真实。摔倒检测最怕的不是模型不聪明,而是你以为它已经稳定工作了,结果被一个蹲下系鞋带的人轻易骗过。希望这套流程能帮你少走一段弯路,也希望你调试得顺手。

希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 8:23:15

联邦学习+图像分类:VGG19/ResNet50/EfficientNet车载分心驾驶检测实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/19 16:30:09

context-mode:用命令行管理AI对话上下文,告别多项目“失忆”

你有没有遇到过这种情况&#xff1a;上午刚让AI帮你梳理完A项目的接口方案&#xff0c;下午切到B项目&#xff0c;希望AI还记得A项目里那个技术选型的限制条件&#xff0c;结果它一脸茫然&#xff0c;甚至给出跟之前完全相反的建议。我一度以为这是模型能力问题&#xff0c;后来…

作者头像 李华
网站建设 2026/10/20 5:55:39

Agent-Reach:用CLI统一AI Agent能力接入层,告别胶水代码

1. 从"Agent-Reach"这个名字说起&#xff1a;它到底想解决什么问题第一次看到 Agent-Reach 这个项目名&#xff0c;我的直觉是&#xff1a;这又是一个给 AI Agent 做"手脚延长"的工具。事实也确实如此——Reach 这个词本身就带着"触达、延伸、够得着&…

作者头像 李华
网站建设 2026/10/21 6:57:33

裸金属芯片适配实战:SoC/外设/专用芯片三类适配方法论

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/20 5:55:40

冷站通讯中断引发联锁停机?PLC控制逻辑优化与故障排查实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/20 5:55:38

嵌入式工业电源路径保护:TPS259483+R7FA4C1B智能防护设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华