feat(exercise): 优化死虫式训练姿态检测算法
- 调整视频处理频率从每帧处理改为每2帧处理 - 添加膝角趋势平滑算法减少单帧抖动误判 - 改进对角伸展检测逻辑支持准备位手臂上举 - 优化状态机确保严格回到准备姿态才计数 - 添加姿态丢失时的候选帧清理机制 - 更新音频文件生成路径至resources目录 - 改进macOS音频生成使用AIFF格式提高质量 - 添加详细的帧处理日志输出间隔配置
This commit is contained in:
@@ -26,6 +26,36 @@ class TestDeadBugStateMachine:
|
||||
feedback=[],
|
||||
)
|
||||
|
||||
def _both_legs_extended(self) -> DeadBugMetrics:
|
||||
"""构建双腿同时伸展的非标准姿态"""
|
||||
return DeadBugMetrics(
|
||||
left_arm_extended=True, right_arm_extended=True,
|
||||
left_leg_extended=True, right_leg_extended=True,
|
||||
left_elbow_angle=160, right_elbow_angle=160,
|
||||
left_knee_angle=160, right_knee_angle=160,
|
||||
feedback=[],
|
||||
)
|
||||
|
||||
def _arms_extended_ready_legs(self) -> DeadBugMetrics:
|
||||
"""构建腿已收回但手臂未收回的姿态"""
|
||||
return DeadBugMetrics(
|
||||
left_arm_extended=True, right_arm_extended=True,
|
||||
left_leg_extended=False, right_leg_extended=False,
|
||||
left_elbow_angle=160, right_elbow_angle=160,
|
||||
left_knee_angle=100, right_knee_angle=100,
|
||||
feedback=[],
|
||||
)
|
||||
|
||||
def _right_knee_angle(self, angle: float) -> DeadBugMetrics:
|
||||
"""构建右膝角连续变化但伸展布尔值尚未稳定的姿态"""
|
||||
return DeadBugMetrics(
|
||||
left_arm_extended=True, right_arm_extended=True,
|
||||
left_leg_extended=False, right_leg_extended=False,
|
||||
left_elbow_angle=160, right_elbow_angle=160,
|
||||
left_knee_angle=90, right_knee_angle=angle,
|
||||
feedback=[],
|
||||
)
|
||||
|
||||
def test_initial_state(self):
|
||||
"""测试:状态机初始化后应为READY且计数为0"""
|
||||
sm = DeadBugStateMachine()
|
||||
@@ -46,3 +76,58 @@ class TestDeadBugStateMachine:
|
||||
assert sm.phase == DeadBugPhase.READY
|
||||
sm.update(self._extended_left())
|
||||
assert sm.phase == DeadBugPhase.EXTENDING
|
||||
|
||||
def test_confirm_extension_from_knee_angle_trend(self):
|
||||
"""测试:膝角连续上升时,不依赖单帧伸展布尔值也能确认伸展"""
|
||||
sm = DeadBugStateMachine(extension_confirm_frames=2, reset_confirm_frames=2)
|
||||
|
||||
sm.update(self._right_knee_angle(100))
|
||||
sm.update(self._right_knee_angle(130))
|
||||
assert sm.phase == DeadBugPhase.READY
|
||||
sm.update(self._right_knee_angle(145))
|
||||
sm.update(self._right_knee_angle(150))
|
||||
|
||||
assert sm.phase == DeadBugPhase.EXTENDING
|
||||
|
||||
def test_full_rep_counts_once_after_strict_reset(self):
|
||||
"""测试:确认伸展后,只有严格回到准备姿态才计一次"""
|
||||
sm = DeadBugStateMachine(extension_confirm_frames=2, reset_confirm_frames=2)
|
||||
|
||||
sm.update(self._extended_left())
|
||||
sm.update(self._extended_left())
|
||||
assert sm.phase == DeadBugPhase.EXTENDING
|
||||
|
||||
sm.update(self._arms_extended_ready_legs())
|
||||
assert sm.rep_count == 0
|
||||
assert sm.phase == DeadBugPhase.NEED_RESET
|
||||
|
||||
sm.update(self._ready_metrics())
|
||||
result = sm.update(self._ready_metrics())
|
||||
assert result.rep_count == 1
|
||||
assert sm.phase == DeadBugPhase.READY
|
||||
|
||||
result = sm.update(self._ready_metrics())
|
||||
assert result.rep_count == 1
|
||||
|
||||
def test_both_legs_do_not_start_rep(self):
|
||||
"""测试:双腿同时伸展不进入计数流程"""
|
||||
sm = DeadBugStateMachine(extension_confirm_frames=2, reset_confirm_frames=2)
|
||||
sm.update(self._both_legs_extended())
|
||||
result = sm.update(self._both_legs_extended())
|
||||
|
||||
assert result.rep_count == 0
|
||||
assert sm.phase == DeadBugPhase.READY
|
||||
|
||||
def test_no_pose_preserves_confirmed_rep_until_reset(self):
|
||||
"""测试:已确认伸展后短暂丢姿态,回到准备位仍能完成计数"""
|
||||
sm = DeadBugStateMachine(extension_confirm_frames=2, reset_confirm_frames=2)
|
||||
sm.update(self._extended_left())
|
||||
sm.update(self._extended_left())
|
||||
assert sm.phase == DeadBugPhase.EXTENDING
|
||||
|
||||
sm.mark_no_pose()
|
||||
sm.update(self._ready_metrics())
|
||||
result = sm.update(self._ready_metrics())
|
||||
|
||||
assert result.rep_count == 1
|
||||
assert sm.phase == DeadBugPhase.READY
|
||||
|
||||
Reference in New Issue
Block a user