File size: 14,207 Bytes
2114261
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
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