python案例如何评估门将扑救反应速度?

wen python案例 1

本文目录导读:

python案例如何评估门将扑救反应速度?

  1. 案例一:基于惯性传感器(IMU)的爆发力与反应时分析(入门级)
  2. 案例二:基于视频的姿态检测(OpenCV + MediaPipe 进阶版)
  3. 案例三:基于“球-手”距离的数学建模(运动学分析)
  4. 关键评估指标(你要在代码中计算的)
  5. 总结建议

这是一个很好的问题!评估门将的扑救反应速度,在体育科学和数据分析中,通常分为物理测试视频/数据模型分析两大类。

下面我提供几个不同层次的 Python 案例,从基于传感器数据的算法分析基于视频的自动化检测,你可以根据手头数据的情况选择。


基于惯性传感器(IMU)的爆发力与反应时分析(入门级)

场景:门将佩戴智能手套或护具(内含加速度计和陀螺仪),当对手射门时,系统记录手腕或身体的加速度变化。 评估指标反应延迟时间(从射门时刻到开始移动时刻)和爆发力指数

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import find_peaks
# 模拟数据:假设采样频率为 1000Hz (每秒1000个点)
# 假设第 1000ms 时,系统发出“射门”信号(模拟球被踢出的时间)
# 加速度计数据 (X轴: 横向扑救)
sample_rate = 1000  # Hz
t = np.arange(0, 3000) / sample_rate  # 3秒长度
np.random.seed(42)
# 生成模拟X轴加速度:前1秒安静,1秒后出现大幅度摆动(门将扑救)
x_acc = np.random.normal(0, 0.1, len(t))
x_acc[1000:] += 2.0 * np.sin(np.linspace(0, 10, 2000)) * 1.5  # 模拟扑救动作
# 添加噪声
x_acc += np.random.normal(0, 0.3, len(t))
# 记录事件时间(射门发生的时刻,单位:秒)
shoot_time = 1.0  # 1000ms
# 1. 找出加速度的显著峰值(即门将开始发力的时刻)
# 设置阈值,略高于静息状态
threshold = 1.5 * np.std(x_acc[:1000]) + np.mean(x_acc[:1000])  # 基于前1秒计算基线
peaks, properties = find_peaks(x_acc, height=threshold, distance=50)  # 确保峰值间隔不超过50ms
# 2. 找到第一个超过阈值的点(这通常是反应动作的起始点)
if len(peaks) > 0:
    first_peak_index = peaks[0]
    # 实际扑救开始时间
    reaction_start_time = t[first_peak_index]
    # 计算反应时间
    reaction_time_ms = (reaction_start_time - shoot_time) * 1000
    # 3. 计算爆发力(前100ms内的加速度变化率,即Jerk)
    # Jerk = d(acc)/dt
    jerk = np.diff(x_acc[max(0, first_peak_index-50): first_peak_index+50]) / (1/sample_rate)
    explosive_power = np.max(np.abs(jerk))
    print(f"门将反应时间: {reaction_time_ms:.2f} ms")
    print(f"爆发力指数 (Jerk): {explosive_power:.2f} m/s^3")
else:
    print("未检测到显著扑救动作")
# 可视化
plt.figure(figsize=(10, 4))
plt.plot(t*1000, x_acc, label='X轴加速度')
plt.axvline(x=shoot_time*1000, color='r', linestyle='--', label='射门时刻')
if len(peaks) > 0:
    plt.scatter(t[peaks[0]]*1000, x_acc[peaks[0]], color='g', s=100, label='反应开始点')
plt.legend()
plt.xlabel('时间 (ms)')
plt.ylabel('加速度 (m/s^2)')'门将扑救加速度曲线')
plt.show()

基于视频的姿态检测(OpenCV + MediaPipe 进阶版)

场景:使用摄影机捕捉门将动作,通过姿态识别提取关键点(如手腕、膝盖),计算“射门”到“手腕位移距离超过X像素”的时间差。

# 依赖: pip install opencv-python mediapipe numpy
import cv2
import mediapipe as mp
import numpy as np
import time
# 初始化姿态检测模型
mp_pose = mp.solutions.pose
pose = mp_pose.Pose()
# 假设我们有一个视频文件或摄像头流 (这里以视频文件为例)
cap = cv2.VideoCapture('goalkeeper_save.mp4')
fps = cap.get(cv2.CAP_PROP_FPS)  # 获取帧率
shoot_frame_time = 0.5  # 假设人在第0.5秒时射门 (也可以由目标追踪算法从球的位置判断)
# 存储手腕位置的列表
wrist_positions = []
frame_times = []
while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break
    # 记录当前帧的时间
    frame_times.append(cap.get(cv2.CAP_PROP_POS_MSEC) / 1000.0)  # 毫秒转秒
    # BGR转RGB
    rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    results = pose.process(rgb_frame)
    if results.pose_landmarks:
        # 获取右手腕坐标 (33 是右腕索引)
        # 归一化坐标 (0-1) 转换为图像尺寸
        h, w, _ = frame.shape
        wrist_x = int(results.pose_landmarks.landmark[15].x * w)  # 或者 [16] 左腕
        wrist_y = int(results.pose_landmarks.landmark[15].y * h)
        wrist_positions.append((wrist_x, wrist_y))
        # 画点
        cv2.circle(frame, (wrist_x, wrist_y), 5, (0, 255, 0), -1)
    cv2.imshow('Frame', frame)
    if cv2.waitKey(25) & 0xFF == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()
# 后处理:计算反应时间
if wrist_positions:
    # 初始化基线(比如前10帧手腕的平均位置)
    baseline_x = np.mean([p[0] for p in wrist_positions[:10]])
    threshold_displacement = 20  # 像素位移阈值,表示球员开始动了
    # 查找手腕移动超过阈值的帧
    start_index = None
    for i, (x, y) in enumerate(wrist_positions):
        if abs(x - baseline_x) > threshold_displacement:
            start_index = i
            break
    if start_index:
        # 需要知道射门时刻对应的帧索引 (可以通过球的位置变化来计算,这里简化处理)
        # 假设 shoot_frame_index 我们通过某种方法(例如目标检测球)确定了
        # 这里我们简单假设射门发生在 start_index 之前 N 帧(由视频时间确定)
        # 假设 video shoot_time 已知 (0.5秒)
        shoot_time_index = int(shoot_frame_time * fps)
        reaction_ms = (start_index - shoot_time_index) / fps * 1000
        print(f"门将反应时间: {reaction_ms:.2f} ms")

基于“球-手”距离的数学建模(运动学分析)

场景:使用高速摄像机,追踪足球和门将手部的二维坐标,通过计算距离差来评估反应时间。

import numpy as np
from scipy.signal import savgol_filter
# 模拟数据:排球在空中飞行,门将手部移动
# 时间序列 (单位: 秒)
t = np.linspace(0, 1, 100)
# 球的位置 (从球门中心向左侧运动)
ball_pos = 100 - 50 * t**2  # 抛物线加速
# 门将手指尖的位置 (在0.3秒前保持不动,之后开始移动扑救)
hand_pos = np.piecewise(t, [t < 0.3, t >= 0.3], [0, lambda t: 20*(t-0.3)**2])
# 噪声
ball_pos += np.random.normal(0, 1, len(t))
hand_pos += np.random.normal(0, 0.5, len(t))
# 运用Savitzky-Golay滤波器去噪并求导
ball_smooth = savgol_filter(ball_pos, window_length=11, polyorder=3)
hand_smooth = savgol_filter(hand_pos, window_length=11, polyorder=3)
# 计算相对距离
distance = hand_smooth - ball_smooth
# 评估逻辑:门将何时开始“有效移动”?
# 定义:当手部速度超过某个阈值,且距离在缩小时,我们记录该时刻为“决策完成”
velocity_hand = np.diff(hand_smooth, prepend=0)
dynamic_threshold = 0.1 * np.max(velocity_hand)
# 找到手部速度首次超过阈值的点
start_move_idx = np.where(velocity_hand > dynamic_threshold)[0][0]
shoot_time = 0.1  # 假设球在0.1秒被踢出
reaction_time = t[start_move_idx] - shoot_time
print(f"反应时间: {reaction_time*1000:.2f} ms")

关键评估指标(你要在代码中计算的)

为了全面评估反应速度,建议你计算以下指标:

  1. 初始反应时间(RT):刺激(球射门)到肌肉开始放电或关节产生动作的时间,典型值小于200ms。
  2. 到达峰值速度时间:从开始移动到达到最大移动速度的时间,这反映了爆发力。
  3. 决策时间:门将判断出球的方向(左/右)并做出适应性调整的时间。
  4. 手控时间:从触球到稳定控制球的时间,这考验的是“稳定度”。

总结建议

  • 最高效案例一,如果你有穿戴设备数据,这是最专业的运动科学方法。
  • 最直观案例二,适合分析比赛录像,无需额外设备,但受摄像头帧率和光线影响较大。
  • 最精确:结合视频追踪和IMU数据,用 Python 将两者同步。

重要提示:在真实世界中,反应时间是包含感知-认知-动作的综合过程,代码通常只能分析“动作阶段”(从肌肉活动开始到移动结束),而无法准确捕捉“感知阶段”(视觉到大脑处理),如果将射门画面逐帧分析(案例二),时间段会包含认知延迟,这是最接近实战测量的。

抱歉,评论功能暂时关闭!