import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import signal, interpolate
from scipy.spatial.distance import euclidean
from scipy.signal import find_peaks, savgol_filter
# 假设数据加载函数 - 需要根据实际数据格式调整
def load_motion_data(file_path):
"""
加载运动数据
返回: DataFrame,包含帧号和33个关键点的坐标
"""
# 这里需要根据实际数据格式实现
# 假设数据格式为: frame, x1, y1, x2, y2, ... x33, y33
data = pd.read_csv(file_path)
return data
# 计算质心函数
def calculate_center_of_mass(data, weights=None):
"""
计算每一帧的质心坐标
weights: 各关键点的权重,如果不提供则使用均匀权重
"""
if weights is None:
weights = np.ones(33) / 33 # 均匀权重
x_cols = [f'x{i}' for i in range(1, 34)]
y_cols = [f'y{i}' for i in range(1, 34)]
com_x = np.average(data[x_cols], weights=weights, axis=1)
com_y = np.average(data[y_cols], weights=weights, axis=1)
return com_x, com_y
# 计算垂直速度函数
def calculate_vertical_velocity(y, fps=30):
"""
计算垂直速度
fps: 视频帧率
"""
# 使用中心差分法计算速度
dy = np.gradient(y, 1/fps)
return dy
# 确定起跳和落地时刻
def detect_takeoff_landing(ankle_y, fps=30, threshold=0.1):
"""
通过脚踝关键点的垂直速度确定起跳和落地时刻
ankle_y: 脚踝关键点的y坐标序列
fps: 视频帧率
threshold: 速度阈值
"""
# 计算垂直速度
v_y = calculate_vertical_velocity(ankle_y, fps)
# 平滑速度曲线
v_y_smooth = savgol_filter(v_y, 11, 3)
# 寻找起跳时刻 (速度由负转正)
takeoff_frame = None
for i in range(1, len(v_y_smooth)):
if v_y_smooth[i-1] <= threshold and v_y_smooth[i] > threshold:
takeoff_frame = i
break
# 寻找落地时刻 (速度由正急剧变负)
landing_frame = None
if takeoff_frame:
for i in range(takeoff_frame + 1, len(v_y_smooth)):
if v_y_smooth[i-1] > -threshold and v_y_smooth[i] < -threshold:
landing_frame = i
break
return takeoff_frame, landing_frame, v_y_smooth
# 计算身体角度
def calculate_body_angles(data, frame):
"""
计算特定帧的身体角度
"""
# 获取关键点坐标
# 假设关键点索引按照标准人体姿态估计模型 (如OpenPose)
# 这里需要根据实际关键点索引调整
# 躯干前倾角: 髋部中点与颈部关键点的连线与垂直方向的夹角
mid_hip_x = (data.loc[frame, 'x8'] + data.loc[frame, 'x11']) / 2
mid_hip_y = (data.loc[frame, 'y8'] + data.loc[frame, 'y11']) / 2
neck_x = data.loc[frame, 'x1']
neck_y = data.loc[frame, 'y1']
# 计算向量
vec_x = neck_x - mid_hip_x
vec_y = neck_y - mid_hip_y # 注意坐标系方向
# 计算与垂直方向的夹角
trunk_angle = np.degrees(np.arctan2(vec_x, vec_y))
# 类似方法可以计算其他角度
# 大腿与躯干夹角、小腿与大腿夹角等
return trunk_angle
# 主分析函数
def analyze_jump_process(data_file):
"""
分析跳远过程的主函数
"""
# 加载数据
data = load_motion_data(data_file)
# 计算质心
com_x, com_y = calculate_center_of_mass(data)
# 获取脚踝关键点 (假设索引为7和10)
left_ankle_y = data['y7']
right_ankle_y = data['y10']
ankle_y = (left_ankle_y + right_ankle_y) / 2 # 使用双脚平均值
# 确定起跳和落地时刻
takeoff_frame, landing_frame, v_y = detect_takeoff_landing(ankle_y)
# 滞空阶段分析
if takeoff_frame and landing_frame:
print(f"起跳时刻: 第{takeoff_frame}帧")
print(f"落地时刻: 第{landing_frame}帧")
print(f"滞空时间: {(landing_frame - takeoff_frame) / 30:.2f}秒") # 假设30fps
# 分析滞空阶段身体姿态变化
flight_frames = range(takeoff_frame, landing_frame + 1)
trunk_angles = [calculate_body_angles(data, f) for f in flight_frames]
# 绘制结果
plt.figure(figsize=(12, 8))
plt.subplot(2, 2, 1)
plt.plot(com_x, com_y)
plt.plot(com_x[takeoff_frame], com_y[takeoff_frame], 'go', label='Takeoff')
plt.plot(com_x[landing_frame], com_y[landing_frame], 'ro', label='Landing')
plt.xlabel('X Position')
plt.ylabel('Y Position')
plt.title('Center of Mass Trajectory')
plt.legend()
plt.subplot(2, 2, 2)
plt.plot(v_y)
plt.axvline(x=takeoff_frame, color='g', linestyle='--', label='Takeoff')
plt.axvline(x=landing_frame, color='r', linestyle='--', label='Landing')
plt.xlabel('Frame')
plt.ylabel('Vertical Velocity')
plt.title('Vertical Velocity of Ankles')
plt.legend()
plt.subplot(2, 2, 3)
plt.plot(flight_frames, trunk_angles)
plt.xlabel('Frame')
plt.ylabel('Trunk Angle (degrees)')
plt.title('Trunk Angle During Flight')
plt.subplot(2, 2, 4)
# 可以添加其他分析,如膝关节角度等
plt.tight_layout()
plt.show()
return takeoff_frame, landing_frame, flight_frames, trunk_angles
else:
print("未能检测到起跳或落地时刻")
return None, None, None, None
最新发布