YOLO如何结合opencv实现视觉实时摔倒检测?
网友回复
用 YOLOv8 Pose + ByteTrack 对视频中的“人”进行跟踪,同时用关键点和边界框的几何特征做简易规则,实时判定“站立/行走/摔倒/躺卧”。代码包含完整可运行脚本与参数可调,适合先跑通再迭代优化。
准备环境
Python 3.8+
安装依赖
pip install ultralytics opencv-python numpy
说明
模型:yolov8n-pose.pt(轻量),可换 yolov8s/m/l-pose 提高精度。
跟踪:内置 ByteTrack,自动给每个人分配 track id。
判定逻辑(可调阈值):
使用躯干角度(髋-肩连线相对竖直角度)、框的长宽比、髋部向下速度、中心速度等。
突然由“竖直”到“水平”且髋部下坠速度快,判定为“摔倒”。
竖直且中心移动速度较大,判定“行走”;竖直且速度较小,判定“站立”。
长时间水平,判定“躺卧”。
代码(保存为 yolo_fall_walk.py)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import argparse
from collections import deque
import cv2
import numpy as np
from ultralytics import YOLO
# COCO关键点索引
L_SHOULDER, R_SHOULDER = 5, 6
L_HIP, R_HIP = 11, 12
STATE_COLORS = {
    "walking": (0, 200, 0),     # 绿
    "standing": (200, 200, 0),  # 黄
    "falling": (0, 0, 255),     # 红
    "lying": (0, 140, 255),     # 橙
    "unknown": (180, 180, 180), # 灰
}
def torso_angle_deg(kps_xy):
    # 返回“躯干相对竖直的角度”,0度=笔直竖立,90度=水平
    if kps_xy is None or len(kps_xy) < 17:
        return None, None
    ls, rs = kps_xy[L_SHOULDER], kps_xy[R_SHOULDER]
    lh, rh = kps_xy[L_HIP], kps_xy[R_HIP]
    # 如果关键点缺失,用None
    if (ls == 0).all() or (rs == 0).all() or (lh == 0).all() or (rh == 0).all():
        return None, None
    shoulder = (ls + rs) / 2.0
    hip = (lh + rh) / 2.0
    v = shoulder - hip
    vx, vy = float(v[0]), float(v[1])
    if abs(vx) < 1e-6 and abs(vy) < 1e-6:
        return None, hip
    # 与竖直的夹角:用atan2(|vx|, |vy|)
    ang = np.degrees(np.arctan2(abs(vx), abs(vy)))
    return ang, hip
class TrackState:
    def __init__(self, hist=15):
        self.history = deque(maxlen=hist)  # 存最近几帧的指标
        self.state = "unknown"
        self.last_state = "unknown"
        self.stable_count = 0
        self.falling_frames = 0
        self.lying_frames = 0
        self.missed = 0
class FallWalkingDetector:
    def __init__(self, fps=30.0, hist=15):
        self.fps = fps if fps and fps > 0 else 30.0
        self.dt = 1.0 / self.fps
        self.tracks = {}
        self.hist = hist
        # 参数阈值(可调)
        self.AR_VERT = 1.2     # 竖直:高宽比
        self.AR_HORI = 0.85    # 水平:高宽比
        self.ANG_VERT = 35.0   # 竖直角阈
        self.ANG_HORI = 55.0   # 水平角阈
        self.SPD_WALK = 0.35   # 步行速度阈(按框高度归一化,单位:高/秒)
        self.VHIP_FALL = 1.2   # 髋部向下速度触发摔倒(高/秒)
        self.ANG_JUMP = 20.0   # 角度突然变化阈
        self.AR_DROP = 0.3     # 高宽比快速下降比例阈
        self.MIN_FALL_FRAMES = max(2, int(self.fps * 0.1))
        self.MIN_LYING_FRAMES = max(4, int(self.fps * 0.2))
    def _get_track(self, tid):
        if tid not in self.tracks:
            self.tracks[tid] = TrackState(hist=self.hist)
        return self.tracks[tid]
    def _geom_flags(self, ar, ang):
        vertical = (ar is not None and ar > self.AR_VERT) or (ang is not None and ang < self.ANG_VERT)
        horizontal = (ar is not None and ar < self.AR_HORI) or (ang is not None and ang > self.ANG_HORI)
        return vertical, horizontal
    def update(self, tid, bbox, kps_xy):
        st = self._get_track(tid)
        x1, y1, x2, y2 = bbox
        w = max(1.0, x2 - x1)
        h = max(1.0, y2 - y1)
        cx, cy = (x1 + x2) / 2.0, (y1 + y2) / 2.0
        ar = h / w
        ang, hip = torso_angle_deg(kps_xy)
        hip_y = hip[1] if isinstance(hip, (list, tuple, np.ndarray)) else None
        # 前一帧数据
        prev = st.history[-1] if len(st.history) > 0 else None
        spd = 0.0
        vhi...点击查看剩余70%
- threejs如何做个三维搭积木的游戏?
- three如何实现标记多个起始路过地点位置后选择旅行工具(飞机汽车高铁等),最后三维模拟行驶动画导出mp4?
- ai实时驱动的3d数字人可视频聊天的开源技术有吗
- swoole+phpfpm如何实现不同域名指向不同目录的多租户模式?
- 如何用go替换nginx实现请求phpfpm解析运行php脚本?
- 有没有浏览器离线运行进行各种文档、图片、视频格式转换的开源工具?
- 如何使用go语言搭建一个web防火墙?
- linux如何检测特定网络协议比如http协议中报文是否包含特点关键词并阻止返回给客户?
- 如果在nginx外过滤包含某些关键词的网页并阻止打开?
- 程序员怎么做副业赚钱?



 
				 
			 
			 
				 
			