多人跳绳智能计数系统设计文档
1. 文档概述
1.1 系统目标
本系统旨在基于计算机视觉技术,实现对视频中多名人员同时进行跳绳计数的自动化处理。系统融合了目标检测、姿态估计、多目标跟踪、数字信号处理及状态机逻辑,能够应对遮挡、绊脚、暂停、人员进出画面等复杂场景,并通过 WebSocket 实时推送计数结果。
1.2 核心特性
-
多人并发追踪:改进的 DeepSORT 算法,结合骨骼点与外观特征,支持多人同时跳绳计数。
-
鲁棒的计数逻辑:基于卡尔曼滤波、Savitzky-Golay 平滑与峰值检测的信号处理,配合五阶段状态机(就绪、计数、暂停、遮挡、绊脚)。
-
防误判机制:包含身体倾斜检测、摇绳姿势校验、节奏突变检测,以及 READY/PAUSED 超时重置机制。
-
全局身份绑定:跨跟踪器 ID 的全局身份映射,防止因跟踪丢失导致计数重置。
-
实时数据推送:内置异步 WebSocket 服务器,实时广播计数状态。
2. 系统架构设计
系统采用模块化流水线架构,数据单向流转,整体分为五个核心模块:
-
视频预处理模块:负责视频解码、降帧、仿射变换与 ROI 裁剪。
-
目标跟踪模块:基于 YOLOv8-Pose 检测,结合改进的 DeepSORT 进行多目标追踪。
-
独立计数模块:单人的信号处理与状态机演进,输出跳绳次数与频率。
-
数据输出模块:WebSocket 实时推送与历史数据持久化。
-
主系统编排模块:协调各模块,处理全局身份映射(GID)与视频渲染输出。
3. 模块详细设计
3.1 视频预处理模块
-
类名:
VideoPreprocessor -
职责:消除视频背景干扰,矫正透视畸变,控制帧率以降低计算负荷。
-
核心逻辑:
-
降帧策略:根据源视频 FPS 与目标 FPS(默认30),计算帧间隔
frame_interval,仅处理整除帧。 -
仿射变换:若配置
affine_params,调用cv2.warpAffine矫正画面倾斜。 -
ROI裁剪:提取感兴趣区域,自动校正坐标越界问题。
-
帧生成器:
stream_frames()以生成器模式 yield(frame_idx, processed_frame),节省内存。
-
3.2 改进的DeepSORT跟踪模块
-
类名:
Track,ImprovedDeepSORT -
职责:在 YOLO 检测基础上,维持跨帧的人员身份,解决短暂遮挡后的重关联。
3.2.1 Track (单目标轨迹)
-
维护目标的 BBox、关键点、外观特征(HSV 直方图)、中心点历史。
-
集成
cv2.KalmanFilter(4维状态[x, y, vx, vy], 2维观测[x, y]) 预测下一帧中心位置。 -
静止判定:
is_stationary()判断最近10帧中心位移是否小于阈值,用于区分跳绳者(原地不动)与走动者。
3.2.2 ImprovedDeepSORT (跟踪器)
-
轻量级外观提取:截取 BBox 区域,Resize至32x64,计算 HSV 直方图并归一化为512维向量。
-
代价矩阵计算 (
_compute_cost_matrix):-
高 IoU 优先:若 IoU > 0.3,直接采用 IoU 代价,跳过复杂计算。
-
静止目标约束:若目标静止且预测中心与检测中心距离>50,拒绝匹配。
-
多特征融合:代价 = $\alpha \times \text{外观代价} \times 100 + (1 - \alpha) \times \text{骨骼点运动代价} + \text{中心距离代价}$。其中 $\alpha$ 由关键点置信度动态决定。
-
-
数据关联:使用匈牙利算法 (
scipy.optimize.linear_sum_assignment) 解决二分图匹配。 -
生命周期管理:未匹配检测创建新 Track,未匹配轨迹
missing_frames累加,超过max_missing(90帧) 删除。
3.3 独立计数与信号处理模块
-
类名:
PersonJumpCounter -
职责:针对单人进行跳绳动作的信号提炼、特征校验与状态管理。
3.3.1 信号处理管线
-
关键点时序滤波:对17个关键点分别建立双卡尔曼滤波器(x, y独立),置信度<0.3时采用预测值,平滑抖动。
-
质心提取:取左右髋关节(11,12)的Y坐标均值作为身体质心高度
raw_y。 -
归一化:滑动窗口(60帧)计算均值与标准差,进行 Z-Score 归一化,消除不同身高及距离带来的幅度差异。
-
平滑去噪:应用 Savgol 滤波器(窗口7,3阶多项式)。
-
倒相寻峰:因跳绳起跳时Y坐标减小,对信号取反,使用
find_peaks提取波峰,要求最小峰距为5帧,峰度使用动态自适应阈值。
3.3.2 辅助校验机制
-
身体倾斜检测 (
_check_body_tilt):左右肩/髋部Y坐标差异归一化后>0.15视为倾斜(排除侧身走动误判)。 -
摇绳姿态检测 (
_check_holding_rope_posture):-
计算手腕相对髋部的Y偏移历史。
-
判据:偏移方差足够大(手在动)、过零率>=1(手在上下挥动)、摆幅满足最低要求。
-
-
节奏中断检测 (
_is_rhythm_break):最近波峰间隔与历史均值间隔偏差超过±60%/40%视为节奏破坏。
3.3.3 状态机设计
系统定义了5个状态,转换规则如下:
| 当前状态 | 触发条件 | 下一状态 | 动作 |
|---|---|---|---|
| READY | 检测到连续2次有效波峰,且幅度/膝角满足启动阈值 | COUNTING | 累加 pending_peak_frames 到 jump_count |
| READY | 停留在 READY 超过 ready_pause_timeout(10s) |
READY | 清零所有计数与历史,重新计时 |
| COUNTING | 检测到有效波峰 | COUNTING | jump_count++,记录节奏间隔 |
| COUNTING | 物理幅度低于最小阈值 / 波峰超时 | PAUSED | 可能执行回退减3操作 _retract_last_jump |
| COUNTING | 节奏突变或身体严重倾斜 | STUMBLED | 回退上一次计数,记录绊脚开始帧 |
| PAUSED | 幅度恢复且达到重启阈值(1.3x) | COUNTING | 恢复计数 |
| PAUSED | 停留在 PAUSED 超过 ready_pause_timeout(10s) |
READY | 清零所有计数与历史 |
| STUMBLED | 绊脚状态持续15帧以上 | PAUSED/READY | 若有过计数去PAUSED,否则去READY |
| 任意 | 关键点可见率<0.3 | OCCLUDED | 暂停逻辑,清空部分历史 |
| OCCLUDED | 关键点恢复可见 | PAUSED | 若之前在COUNTING则回退计数 |
★ 核心修改点:引入
_set_state统一记录状态进入帧号,并在_check_ready_pause_timeout中实现了超时重置逻辑,避免人员长时间站在画面中发呆导致的历史数据污染。
3.4 数据输出模块
-
类名:
DataOutputManager -
职责:将内存中的计数状态实时推送至前端,并落盘历史记录。
-
机制:
-
主线程调用
update_state更新最新快照。 -
Daemon 线程运行
asyncio事件循环,维持 WebSocket 服务器。 -
以固定频率(
push_interval,默认2Hz)向所有连接的客户端广播 JSON 数据。 -
处理结束后,调用
export_history将全量帧记录写入jump_history.json。
-
3.5 主系统编排模块
-
函数名:
run_rope_counting_system -
职责:串联所有模块,处理业务闭环。
3.5.1 全局身份映射
由于 DeepSORT 的 Track ID (TID) 在目标长时间丢失后会消亡,再次出现会分配新 TID。为维持跳绳计数的连续性,设计了 GID (Global ID) 映射机制:
-
维护
tracker_to_gid(TID -> GID) 和gid_last_info(GID最后出现的信息)。 -
当出现新 TID 时,遍历已丢失的 GID:
-
计算中心点距离代价与外观直方图距离代价。
-
若 GID 处于 COUNTING 状态,施加更严格的距离惩罚。
-
-
若最小代价 < 200,复用该 GID;否则分配新 GID。
-
对于超过600帧未更新的 GID,执行内存清理。
3.5.2 渲染与输出
-
根据 GID 状态渲染不同颜色的 BBox 与文本:
-
COUNTING (绿), PAUSED (黄), READY (橙), STUMBLED (红), OCCLUDED (紫)
-
-
同步写入
cv2.VideoWriter输出结果视频,并调用cv2.imshow实时预览。
4. 数据结构设计
4.1 WebSocket 推送数据格式
{
"timestamp_ms": 12345,
"frame_idx": 370,
"persons": {
"1": {
"id": 1,
"total_jumps": 25,
"state": "COUNTING",
"frequency_jpm": 76.2
},
"2": {
"id": 2,
"total_jumps": 0,
"state": "READY",
"frequency_jpm": 0.0
}
}
}
*(注:frequency_jpm 算法为:过去10秒内跳跃次数 * 6,且需满足至少2次跳跃及持续时间超过1秒)*
4.2 核心队列尺寸限制
| 变量名 | 长度限制 | 用途 |
|---|---|---|
center_history |
30 | 判定人员是否静止 |
raw_y_history |
300 | 存储原始质心高度序列 |
norm_y_history |
300 | 存储归一化后的高度序列 |
knee_angle_history |
300 | 存储膝角变化序列 |
wrist_offset_history |
30 | 摇绳手势判定窗口 |
recent_peak_amplitudes |
5 | 动态自适应峰度阈值计算 |
rhythm_intervals |
10 | 节奏突变判定窗口 |
5. 关键算法参数配置说明
| 参数 | 默认值 | 作用 |
|---|---|---|
target_fps |
30 | 视频降帧目标值,影响信号采样的时间分辨率 |
max_missing |
90 | 跟踪器允许目标消失的最大帧数 (约3秒) |
ready_pause_timeout_sec |
10 | READY/PAUSED 状态超时重置时间 (秒) |
dynamic_min_amplitude |
max(2.5, bbox_size*0.02) |
动态计算的最小物理振幅,随目标远近自适应 |
kf_center processNoiseCov |
0.5 | 跟踪器中心点卡尔曼滤波过程噪声 |
kf_group processNoiseCov |
0.5/5.0 | 关键点卡尔曼滤波过程噪声 (位置/速度) |
adaptive_threshold |
max(0.1, mean*0.35) |
寻峰算法的峰度自适应阈值 |
6. 系统执行流程图


7. 部署与运行约束
-
模型依赖:运行目录下需包含
yolov8n-pose.pt权重文件。 -
批量处理:
__main__入口默认扫描cloud/*.mp4目录下的视频进行批量处理,结果视频在原名后追加_vis.mp4。 -
并发模型:UI渲染与算法推理在主线程同步执行,WebSocket 服务器在独立 Daemon 线程异步运行。
-
中断机制:实时预览窗口按
q键可中断当前视频处理。
