NSAQA / dive_recognition_functions.py
laurenok24's picture
Upload 16 files
2114261 verified
import pickle
import numpy as np
import os
import math
from scipy.signal import find_peaks
from matplotlib import pyplot as plt
def get_scale_factor(dive_data):
# distance between thorax and pelvis
distances = []
for pose_pred in dive_data['pose_pred']:
if pose_pred is not None:
distances.append(math.dist(pose_pred[0][6], pose_pred[0][7]))
distances.sort()
return np.median(distances)
def find_angle(vector1, vector2):
unit_vector_1 = vector1 / np.linalg.norm(vector1)
unit_vector_2 = vector2 / np.linalg.norm(vector2)
dot_product = np.dot(unit_vector_1, unit_vector_2)
angle = math.degrees(np.arccos(dot_product))
return angle
def is_back_facing(dive_data, board_side):
directions = []
for i in range(len(dive_data['pose_pred'])):
pose_pred = dive_data['pose_pred'][i]
if pose_pred is None or dive_data['above_boards'][i] == 0:
continue
pose_pred = pose_pred[0]
## left knee bend ###
l_knee = pose_pred[4]
l_ankle = pose_pred[5]
l_hip = pose_pred[3]
l_knee_ankle = [l_ankle[0] - l_knee[0], 0-(l_ankle[1] - l_knee[1])]
l_knee_hip = [l_hip[0] - l_knee[0], 0-(l_hip[1] - l_knee[1])]
l_direction = rotation_direction(l_knee_hip, l_knee_ankle)
## right knee bend ###
r_knee = pose_pred[1]
r_ankle = pose_pred[0]
r_hip = pose_pred[2]
r_knee_ankle = [r_ankle[0] - r_knee[0], 0-(r_ankle[1] - r_knee[1])]
r_knee_hip = [r_hip[0] - r_knee[0], 0-(r_hip[1] - r_knee[1])]
r_direction = rotation_direction(r_knee_hip, r_knee_ankle)
if l_direction == r_direction and l_direction != 0 and board_side == 'left':
# we're looking for more clockwise
return l_direction < 0
elif l_direction == r_direction and l_direction != 0:
# we're looking for more counterclockwise
return l_direction > 0
return False
def rotation_direction(vector1, vector2, threshold=0.4):
# Calculate the determinant to determine rotation direction
determinant = vector1[0] * vector2[1] - vector1[1] * vector2[0]
mag1= np.linalg.norm(vector1)
mag2= np.linalg.norm(vector2)
norm_det = determinant/(mag1*mag2)
# print("determinant", determinant/(mag1*mag2))
# print(norm_det)
if norm_det > threshold:
# return "counterclockwise"
return 1
elif norm_det < 0-threshold:
# return "clockwise"
return -1
else:
# return "not determinent"
return 0
def find_position(dive_data):
angles = []
three_in_a_row = 0
for i in range(1, len(dive_data['pose_pred'])):
pose_pred = dive_data['pose_pred'][i]
if pose_pred is None or dive_data['som'][i]==0:
continue
pose_pred = pose_pred[0]
l_knee = pose_pred[4]
l_ankle = pose_pred[5]
l_hip = pose_pred[3]
l_knee_ankle = [l_ankle[0] - l_knee[0], 0-(l_ankle[1] - l_knee[1])]
l_knee_hip = [l_hip[0] - l_knee[0], 0-(l_hip[1] - l_knee[1])]
angle = find_angle(l_knee_ankle, l_knee_hip)
angles.append(angle)
# print(angle)
if angle < 70:
three_in_a_row += 1
if three_in_a_row >=3:
return 'tuck'
else:
three_in_a_row =0
if twist_counter_full_dive(dive_data) > 0 and som_counter_full_dive(dive_data)[0] < 5:
return 'free'
return 'pike'
def distance_point_to_line_segment(px, py, x1, y1, x2, y2):
# Calculate the squared distance from point (px, py) to the line segment [(x1, y1), (x2, y2)]
def sqr_distance_point_to_segment():
line_length_sq = (x2 - x1)**2 + (y2 - y1)**2
if line_length_sq == 0:
return (px - x1)**2 + (py - y1)**2
t = max(0, min(1, ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / line_length_sq))
return ((px - (x1 + t * (x2 - x1)))**2 + (py - (y1 + t * (y2 - y1)))**2)
# Calculate the closest point on the line segment to the given point (px, py)
def closest_point_on_line_segment():
line_length_sq = (x2 - x1)**2 + (y2 - y1)**2
if line_length_sq == 0:
return x1, y1
t = max(0, min(1, ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / line_length_sq))
closest_x = x1 + t * (x2 - x1)
closest_y = y1 + t * (y2 - y1)
return closest_x, closest_y
closest_point = closest_point_on_line_segment()
distance = math.sqrt(sqr_distance_point_to_segment())
return closest_point, distance
def min_distance_from_line_to_circle(line_start, line_end, circle_center, circle_radius):
closest_point, distance = distance_point_to_line_segment(circle_center[0], circle_center[1],
line_start[0], line_start[1],
line_end[0], line_end[1])
min_distance = max(0, distance - circle_radius)
return min_distance
def twister(pose_pred, prev_pose_pred=None, in_petal=False, petal_count=0, outer=10, inner=9, valid=17, middle=0.5):
if pose_pred is None:
return petal_count, in_petal
min_dist = 0
# Users/lokamoto/Comprehensive_AQA/output/joint_plots/FINAWorldChampionships2019_Women10m_final_r1_0
pose_pred = pose_pred[0]
vector1 = [pose_pred[2][0] - pose_pred[3][0], 0-(pose_pred[2][1] - pose_pred[3][1])]
if prev_pose_pred is not None:
prev_pose_pred = prev_pose_pred[0]
prev_pose_pred = [prev_pose_pred[2][0] - prev_pose_pred[3][0], 0-(prev_pose_pred[2][1] - prev_pose_pred[3][1])]
min_dist = min_distance_from_line_to_circle(prev_pose_pred, vector1, (0, 0), middle)
if np.linalg.norm(vector1) > valid:
return petal_count, in_petal
if min_dist is not None and in_petal and np.linalg.norm(vector1) > outer and min_dist == 0: #and np.linalg.norm(vector1) > 8
petal_count += 1
# print('leaving petal')
# print('going in new petal')
elif not in_petal and np.linalg.norm(vector1) > outer: #and min_dist > 3: #and np.linalg.norm(vector1) > 8
in_petal = True
petal_count += 1
# print('going in petal')
elif in_petal and np.linalg.norm(vector1) < inner:
in_petal = False
# print('leaving petal')
# print(vector)
return petal_count, in_petal
def twist_counter_full_dive(dive_data, visualize=False):
twists_gt = []
twists_gt.extend(range(29, 36))
twists_gt.extend([41, 42])
start = [1, 2, 3, 4, 5, 6, 7]
# key = ('01',17)
# print(ground_truth[key][0])
# print(dive_data['twist_counts'])
dist_hip = []
prev_pose_pred = None
in_petal=False
petal_count=0
scale = get_scale_factor(dive_data)
valid = scale / 1.5
outer = scale / 3.2
inner = scale / 3.4
middle = 0.5
next_next_pose_pred = dive_data['pose_pred'][4]
# bad_poses = invalid_poses(key)
for i in range(len(dive_data['pose_pred'])):
# if ground_truth[key][4][i] not in twists_gt:
# continue
# if i in bad_poses:
# continue
pose_pred = dive_data['pose_pred'][i]
if i < len(dive_data['pose_pred']) - 1:
next_pose_pred = dive_data['pose_pred'][i + 1]
if i < len(dive_data['pose_pred']) - 4 and next_next_pose_pred is not None:
next_next_pose_pred = dive_data['pose_pred'][i + 4]
if pose_pred is None or dive_data['on_boards'][i] == 1 or dive_data['position_tightness'][i] <= 80 or next_next_pose_pred is None:
continue
petal_count, in_petal = twister(pose_pred, prev_pose_pred=prev_pose_pred, in_petal=in_petal, petal_count=petal_count, outer=outer, inner=inner, middle=middle, valid=valid)
prev_pose_pred = pose_pred
# print(petal_count)
if visualize:
pose_pred = pose_pred[0]
dist_hip.append([pose_pred[2][0] - pose_pred[3][0], 0-(pose_pred[2][1] - pose_pred[3][1])])
if visualize:
dist_hip = np.array(dist_hip)
plt.plot(dist_hip[:, 0], dist_hip[:, 1], label="right-to-left hip")
circle1 = plt.Circle((0, 0), outer, fill=False)
plt.gca().add_patch(circle1)
circle2 = plt.Circle((0, 0), inner, fill=False)
plt.gca().add_patch(circle2)
circle3 = plt.Circle((0, 0), valid, fill=False)
plt.gca().add_patch(circle3)
plt.legend()
plt.show()
return petal_count
def rotation_direction_som(vector1, vector2, threshold=0.4):
# Calculate the determinant to determine rotation direction
determinant = vector1[0] * vector2[1] - vector1[1] * vector2[0]
mag1= np.linalg.norm(vector1)
mag2= np.linalg.norm(vector2)
norm_det = determinant/(mag1*mag2)
theta = np.arcsin(norm_det)
return math.degrees(theta)
def is_handstand(dive_data):
first_frame_pose_pred = dive_data['pose_pred'][0]
handstand = False
if first_frame_pose_pred[0][6][1] < first_frame_pose_pred[0][7][1]:
handstand = True
return handstand
def som_counter_full_dive(dive_data, visualize=False):
start = [1, 2, 3, 4, 5, 6, 7]
entry = [36]
half_som_count = 0
# key = ('04', 47)
# print(ground_truth[key][0])
dist_body = []
handstand = is_handstand(dive_data)
# key = ('04',42)
next_next_pose_pred = dive_data['pose_pred'][2]
# bad_poses = invalid_poses(key)
prev = None
for i in range(len(dive_data['pose_pred'])):
# if i in bad_poses:
# continue
pose_pred = dive_data['pose_pred'][i]
if i < len(dive_data['pose_pred']) - 2 and next_next_pose_pred is not None:
next_next_pose_pred = dive_data['pose_pred'][i + 2]
if pose_pred is None or next_next_pose_pred is None or dive_data['on_boards'][i] == 1: # ground_truth[key][4][i] in start:
continue
pose_pred = pose_pred[0]
vector1 = [pose_pred[7][0] - pose_pred[6][0], 0-(pose_pred[7][1] - pose_pred[6][1])] # flip y axis
if (not handstand and half_som_count % 2 == 0) or (handstand and half_som_count % 2 == 1):
vector2 = [0, -1]
else:
vector2 = [0, 1]
sensitivity = 115
if prev is not None and find_angle(vector1, prev) > sensitivity:
continue
is_clockwise = is_rotating_clockwise(dive_data)
if prev is not None and ((is_clockwise and rotation_direction_som(vector1, prev)<0) or (not is_clockwise and rotation_direction_som(vector1, prev)>0)):
continue
angle = find_angle(vector1, vector2)
# print("unit_vector_1:", unit_vector_1)
# print("looking for vector:", vector2)
# print(half_som_count)
# print(angle)
if angle <= 75:
half_som_count += 1
if visualize:
dist_body.append([pose_pred[7][0] - pose_pred[6][0], 0-(pose_pred[7][1] - pose_pred[6][1])])
prev = vector1
if visualize:
dist_body = np.array(dist_body)
plt.plot(dist_body[:, 0], dist_body[:, 1], label="pelvis-to-thorax")
plt.xlabel("x-coord")
plt.ylabel("y-coord")
plt.legend()
plt.show()
return half_som_count, handstand
def getDiveInfo(diveNum):
handstand = (diveNum[0] == '6')
expected_som = int(diveNum[2])
if len(diveNum) == 5:
expected_twists = int(diveNum[3])
else:
expected_twists = 0
if diveNum[0] == '1' or diveNum[0] == '3' or diveNum[:2] == '51' or diveNum[:2] == '53' or diveNum[:2] == '61' or diveNum[:2] == '63':
back_facing = False
else:
back_facing = True
if diveNum[0] == '1' or diveNum[:2] == '51' or diveNum[:2] == '61':
expected_direction = 'front'
elif diveNum[0] == '2' or diveNum[:2] == '52' or diveNum[:2] == '62':
expected_direction = 'back'
elif diveNum[0] == '3' or diveNum[:2] == '53' or diveNum[:2] == '63':
expected_direction = 'reverse'
elif diveNum[0] == '4':
expected_direction = 'inward'
if diveNum[-1] == 'b':
position = 'pike'
elif diveNum[-1] == 'c':
position = 'tuck'
else:
position = 'free'
return handstand, expected_som, expected_twists, back_facing, expected_direction, position
def get_direction(dive_data):
clockwise = is_rotating_clockwise(dive_data)
board_side = dive_data['board_side']
if board_side == "right":
back_facing = is_back_facing(dive_data, 'right')
if back_facing and clockwise:
direction = 'inward'
elif back_facing and not clockwise:
direction = 'back'
elif not back_facing and clockwise:
direction = 'reverse'
elif not back_facing and not clockwise:
direction = 'front'
else:
back_facing = is_back_facing(dive_data, 'left')
if back_facing and clockwise:
direction = 'back'
elif back_facing and not clockwise:
direction = 'inward'
elif not back_facing and clockwise:
direction = 'front'
elif not back_facing and not clockwise:
direction = 'reverse'
return direction
def is_rotating_clockwise(dive_data):
directions = []
for i in range(1, len(dive_data['pose_pred'])):
if dive_data['pose_pred'][i] is None or dive_data['pose_pred'][i-1] is None:
continue
if dive_data['on_boards'][i] == 0:
prev_pose_pred_hip = dive_data['pose_pred'][i-1][0][3]
curr_pose_pred_hip = dive_data['pose_pred'][i][0][3]
prev_pose_pred_knee = dive_data['pose_pred'][i-1][0][4]
curr_pose_pred_knee = dive_data['pose_pred'][i][0][4]
prev_hip_knee = [prev_pose_pred_knee[0] - prev_pose_pred_hip[0], 0-(prev_pose_pred_knee[1] - prev_pose_pred_hip[1])]
curr_hip_knee = [curr_pose_pred_knee[0] - curr_pose_pred_hip[0], 0-(curr_pose_pred_knee[1] - curr_pose_pred_hip[1])]
direction = rotation_direction(prev_hip_knee, curr_hip_knee, threshold=0)
directions.append(direction)
return np.sum(directions) < 0