laurenok24 commited on
Commit
2114261
1 Parent(s): 0b41ec0

Upload 16 files

Browse files
.gitattributes CHANGED
@@ -33,3 +33,10 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ 01_10.mp4 filter=lfs diff=lfs merge=lfs -text
37
+ 01_11.mp4 filter=lfs diff=lfs merge=lfs -text
38
+ 01_140.mp4 filter=lfs diff=lfs merge=lfs -text
39
+ 01_16.mp4 filter=lfs diff=lfs merge=lfs -text
40
+ 01_33.mp4 filter=lfs diff=lfs merge=lfs -text
41
+ 01_40.mov filter=lfs diff=lfs merge=lfs -text
42
+ 01_76.mp4 filter=lfs diff=lfs merge=lfs -text
01_10.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4c6723fdcc6e1749ec60a76357db49dfcd4d152e6546c1927614854cc0b990f3
3
+ size 1303693
01_11.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ac78a8b402e1eb8be9a2d57e74f239677c4f70649476ad556e83c0851b94e77c
3
+ size 2621440
01_140.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c3bbec0ec1ede19c4d93208ece51bf4c08f7889864a8adb31a4d9535f4cc0599
3
+ size 2621440
01_16.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f708564d62eb74888e5d62c851b5c63cdda6e6dc2c2d3a6f04f6605e3b8263c6
3
+ size 2474745
01_33.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:26a28bb4634266170a39c7828f3f7d0017df151a828e77a491cf58dd2eaf814f
3
+ size 2621440
01_40.mov ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8a7468bc1e790f101608b0648604573fa5e76e89dc861f9a05d03a8538174a8d
3
+ size 2621440
01_76.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bfde107e6b7b4b9e813a963b668ba772bed5d4bf16633cf0fb350b6ea5318d6c
3
+ size 2621440
dive_recognition_functions.py ADDED
@@ -0,0 +1,351 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pickle
2
+ import numpy as np
3
+ import os
4
+ import math
5
+ from scipy.signal import find_peaks
6
+ from matplotlib import pyplot as plt
7
+
8
+ def get_scale_factor(dive_data):
9
+ # distance between thorax and pelvis
10
+ distances = []
11
+ for pose_pred in dive_data['pose_pred']:
12
+ if pose_pred is not None:
13
+ distances.append(math.dist(pose_pred[0][6], pose_pred[0][7]))
14
+ distances.sort()
15
+ return np.median(distances)
16
+
17
+ def find_angle(vector1, vector2):
18
+ unit_vector_1 = vector1 / np.linalg.norm(vector1)
19
+ unit_vector_2 = vector2 / np.linalg.norm(vector2)
20
+ dot_product = np.dot(unit_vector_1, unit_vector_2)
21
+ angle = math.degrees(np.arccos(dot_product))
22
+ return angle
23
+
24
+ def is_back_facing(dive_data, board_side):
25
+ directions = []
26
+ for i in range(len(dive_data['pose_pred'])):
27
+ pose_pred = dive_data['pose_pred'][i]
28
+ if pose_pred is None or dive_data['above_boards'][i] == 0:
29
+ continue
30
+ pose_pred = pose_pred[0]
31
+
32
+ ## left knee bend ###
33
+ l_knee = pose_pred[4]
34
+ l_ankle = pose_pred[5]
35
+ l_hip = pose_pred[3]
36
+ l_knee_ankle = [l_ankle[0] - l_knee[0], 0-(l_ankle[1] - l_knee[1])]
37
+ l_knee_hip = [l_hip[0] - l_knee[0], 0-(l_hip[1] - l_knee[1])]
38
+ l_direction = rotation_direction(l_knee_hip, l_knee_ankle)
39
+
40
+ ## right knee bend ###
41
+ r_knee = pose_pred[1]
42
+ r_ankle = pose_pred[0]
43
+ r_hip = pose_pred[2]
44
+ r_knee_ankle = [r_ankle[0] - r_knee[0], 0-(r_ankle[1] - r_knee[1])]
45
+ r_knee_hip = [r_hip[0] - r_knee[0], 0-(r_hip[1] - r_knee[1])]
46
+ r_direction = rotation_direction(r_knee_hip, r_knee_ankle)
47
+ if l_direction == r_direction and l_direction != 0 and board_side == 'left':
48
+ # we're looking for more clockwise
49
+ return l_direction < 0
50
+ elif l_direction == r_direction and l_direction != 0:
51
+ # we're looking for more counterclockwise
52
+ return l_direction > 0
53
+ return False
54
+
55
+ def rotation_direction(vector1, vector2, threshold=0.4):
56
+ # Calculate the determinant to determine rotation direction
57
+ determinant = vector1[0] * vector2[1] - vector1[1] * vector2[0]
58
+ mag1= np.linalg.norm(vector1)
59
+ mag2= np.linalg.norm(vector2)
60
+ norm_det = determinant/(mag1*mag2)
61
+ # print("determinant", determinant/(mag1*mag2))
62
+ # print(norm_det)
63
+ if norm_det > threshold:
64
+ # return "counterclockwise"
65
+ return 1
66
+ elif norm_det < 0-threshold:
67
+ # return "clockwise"
68
+ return -1
69
+ else:
70
+ # return "not determinent"
71
+ return 0
72
+
73
+ def find_position(dive_data):
74
+ angles = []
75
+ three_in_a_row = 0
76
+ for i in range(1, len(dive_data['pose_pred'])):
77
+ pose_pred = dive_data['pose_pred'][i]
78
+ if pose_pred is None or dive_data['som'][i]==0:
79
+ continue
80
+ pose_pred = pose_pred[0]
81
+ l_knee = pose_pred[4]
82
+ l_ankle = pose_pred[5]
83
+ l_hip = pose_pred[3]
84
+ l_knee_ankle = [l_ankle[0] - l_knee[0], 0-(l_ankle[1] - l_knee[1])]
85
+ l_knee_hip = [l_hip[0] - l_knee[0], 0-(l_hip[1] - l_knee[1])]
86
+ angle = find_angle(l_knee_ankle, l_knee_hip)
87
+ angles.append(angle)
88
+ # print(angle)
89
+ if angle < 70:
90
+ three_in_a_row += 1
91
+ if three_in_a_row >=3:
92
+ return 'tuck'
93
+ else:
94
+ three_in_a_row =0
95
+ if twist_counter_full_dive(dive_data) > 0 and som_counter_full_dive(dive_data)[0] < 5:
96
+ return 'free'
97
+ return 'pike'
98
+
99
+
100
+ def distance_point_to_line_segment(px, py, x1, y1, x2, y2):
101
+ # Calculate the squared distance from point (px, py) to the line segment [(x1, y1), (x2, y2)]
102
+ def sqr_distance_point_to_segment():
103
+ line_length_sq = (x2 - x1)**2 + (y2 - y1)**2
104
+ if line_length_sq == 0:
105
+ return (px - x1)**2 + (py - y1)**2
106
+ t = max(0, min(1, ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / line_length_sq))
107
+ return ((px - (x1 + t * (x2 - x1)))**2 + (py - (y1 + t * (y2 - y1)))**2)
108
+
109
+ # Calculate the closest point on the line segment to the given point (px, py)
110
+ def closest_point_on_line_segment():
111
+ line_length_sq = (x2 - x1)**2 + (y2 - y1)**2
112
+ if line_length_sq == 0:
113
+ return x1, y1
114
+ t = max(0, min(1, ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / line_length_sq))
115
+ closest_x = x1 + t * (x2 - x1)
116
+ closest_y = y1 + t * (y2 - y1)
117
+ return closest_x, closest_y
118
+
119
+ closest_point = closest_point_on_line_segment()
120
+ distance = math.sqrt(sqr_distance_point_to_segment())
121
+
122
+ return closest_point, distance
123
+
124
+ def min_distance_from_line_to_circle(line_start, line_end, circle_center, circle_radius):
125
+ closest_point, distance = distance_point_to_line_segment(circle_center[0], circle_center[1],
126
+ line_start[0], line_start[1],
127
+ line_end[0], line_end[1])
128
+
129
+ min_distance = max(0, distance - circle_radius)
130
+ return min_distance
131
+
132
+
133
+ def twister(pose_pred, prev_pose_pred=None, in_petal=False, petal_count=0, outer=10, inner=9, valid=17, middle=0.5):
134
+ if pose_pred is None:
135
+ return petal_count, in_petal
136
+ min_dist = 0
137
+ # Users/lokamoto/Comprehensive_AQA/output/joint_plots/FINAWorldChampionships2019_Women10m_final_r1_0
138
+ pose_pred = pose_pred[0]
139
+ vector1 = [pose_pred[2][0] - pose_pred[3][0], 0-(pose_pred[2][1] - pose_pred[3][1])]
140
+ if prev_pose_pred is not None:
141
+ prev_pose_pred = prev_pose_pred[0]
142
+ prev_pose_pred = [prev_pose_pred[2][0] - prev_pose_pred[3][0], 0-(prev_pose_pred[2][1] - prev_pose_pred[3][1])]
143
+ min_dist = min_distance_from_line_to_circle(prev_pose_pred, vector1, (0, 0), middle)
144
+ if np.linalg.norm(vector1) > valid:
145
+ return petal_count, in_petal
146
+ 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
147
+ petal_count += 1
148
+ # print('leaving petal')
149
+ # print('going in new petal')
150
+ elif not in_petal and np.linalg.norm(vector1) > outer: #and min_dist > 3: #and np.linalg.norm(vector1) > 8
151
+ in_petal = True
152
+ petal_count += 1
153
+ # print('going in petal')
154
+ elif in_petal and np.linalg.norm(vector1) < inner:
155
+ in_petal = False
156
+
157
+ # print('leaving petal')
158
+ # print(vector)
159
+ return petal_count, in_petal
160
+
161
+
162
+ def twist_counter_full_dive(dive_data, visualize=False):
163
+ twists_gt = []
164
+ twists_gt.extend(range(29, 36))
165
+ twists_gt.extend([41, 42])
166
+ start = [1, 2, 3, 4, 5, 6, 7]
167
+ # key = ('01',17)
168
+ # print(ground_truth[key][0])
169
+ # print(dive_data['twist_counts'])
170
+ dist_hip = []
171
+ prev_pose_pred = None
172
+ in_petal=False
173
+ petal_count=0
174
+ scale = get_scale_factor(dive_data)
175
+ valid = scale / 1.5
176
+ outer = scale / 3.2
177
+ inner = scale / 3.4
178
+ middle = 0.5
179
+ next_next_pose_pred = dive_data['pose_pred'][4]
180
+ # bad_poses = invalid_poses(key)
181
+ for i in range(len(dive_data['pose_pred'])):
182
+ # if ground_truth[key][4][i] not in twists_gt:
183
+ # continue
184
+ # if i in bad_poses:
185
+ # continue
186
+ pose_pred = dive_data['pose_pred'][i]
187
+ if i < len(dive_data['pose_pred']) - 1:
188
+ next_pose_pred = dive_data['pose_pred'][i + 1]
189
+ if i < len(dive_data['pose_pred']) - 4 and next_next_pose_pred is not None:
190
+ next_next_pose_pred = dive_data['pose_pred'][i + 4]
191
+ 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:
192
+ continue
193
+ 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)
194
+ prev_pose_pred = pose_pred
195
+ # print(petal_count)
196
+ if visualize:
197
+ pose_pred = pose_pred[0]
198
+ dist_hip.append([pose_pred[2][0] - pose_pred[3][0], 0-(pose_pred[2][1] - pose_pred[3][1])])
199
+ if visualize:
200
+ dist_hip = np.array(dist_hip)
201
+ plt.plot(dist_hip[:, 0], dist_hip[:, 1], label="right-to-left hip")
202
+ circle1 = plt.Circle((0, 0), outer, fill=False)
203
+ plt.gca().add_patch(circle1)
204
+ circle2 = plt.Circle((0, 0), inner, fill=False)
205
+ plt.gca().add_patch(circle2)
206
+ circle3 = plt.Circle((0, 0), valid, fill=False)
207
+ plt.gca().add_patch(circle3)
208
+ plt.legend()
209
+ plt.show()
210
+ return petal_count
211
+
212
+ def rotation_direction_som(vector1, vector2, threshold=0.4):
213
+ # Calculate the determinant to determine rotation direction
214
+ determinant = vector1[0] * vector2[1] - vector1[1] * vector2[0]
215
+ mag1= np.linalg.norm(vector1)
216
+ mag2= np.linalg.norm(vector2)
217
+ norm_det = determinant/(mag1*mag2)
218
+ theta = np.arcsin(norm_det)
219
+ return math.degrees(theta)
220
+
221
+ def is_handstand(dive_data):
222
+ first_frame_pose_pred = dive_data['pose_pred'][0]
223
+ handstand = False
224
+ if first_frame_pose_pred[0][6][1] < first_frame_pose_pred[0][7][1]:
225
+ handstand = True
226
+ return handstand
227
+
228
+ def som_counter_full_dive(dive_data, visualize=False):
229
+ start = [1, 2, 3, 4, 5, 6, 7]
230
+ entry = [36]
231
+ half_som_count = 0
232
+ # key = ('04', 47)
233
+ # print(ground_truth[key][0])
234
+ dist_body = []
235
+ handstand = is_handstand(dive_data)
236
+ # key = ('04',42)
237
+ next_next_pose_pred = dive_data['pose_pred'][2]
238
+ # bad_poses = invalid_poses(key)
239
+ prev = None
240
+ for i in range(len(dive_data['pose_pred'])):
241
+ # if i in bad_poses:
242
+ # continue
243
+ pose_pred = dive_data['pose_pred'][i]
244
+ if i < len(dive_data['pose_pred']) - 2 and next_next_pose_pred is not None:
245
+ next_next_pose_pred = dive_data['pose_pred'][i + 2]
246
+ 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:
247
+ continue
248
+
249
+ pose_pred = pose_pred[0]
250
+ vector1 = [pose_pred[7][0] - pose_pred[6][0], 0-(pose_pred[7][1] - pose_pred[6][1])] # flip y axis
251
+ if (not handstand and half_som_count % 2 == 0) or (handstand and half_som_count % 2 == 1):
252
+ vector2 = [0, -1]
253
+ else:
254
+ vector2 = [0, 1]
255
+ sensitivity = 115
256
+ if prev is not None and find_angle(vector1, prev) > sensitivity:
257
+ continue
258
+ is_clockwise = is_rotating_clockwise(dive_data)
259
+ 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)):
260
+ continue
261
+ angle = find_angle(vector1, vector2)
262
+ # print("unit_vector_1:", unit_vector_1)
263
+ # print("looking for vector:", vector2)
264
+ # print(half_som_count)
265
+ # print(angle)
266
+ if angle <= 75:
267
+ half_som_count += 1
268
+ if visualize:
269
+ dist_body.append([pose_pred[7][0] - pose_pred[6][0], 0-(pose_pred[7][1] - pose_pred[6][1])])
270
+ prev = vector1
271
+
272
+ if visualize:
273
+ dist_body = np.array(dist_body)
274
+ plt.plot(dist_body[:, 0], dist_body[:, 1], label="pelvis-to-thorax")
275
+ plt.xlabel("x-coord")
276
+ plt.ylabel("y-coord")
277
+
278
+ plt.legend()
279
+ plt.show()
280
+ return half_som_count, handstand
281
+
282
+ def getDiveInfo(diveNum):
283
+ handstand = (diveNum[0] == '6')
284
+ expected_som = int(diveNum[2])
285
+ if len(diveNum) == 5:
286
+ expected_twists = int(diveNum[3])
287
+ else:
288
+ expected_twists = 0
289
+ if diveNum[0] == '1' or diveNum[0] == '3' or diveNum[:2] == '51' or diveNum[:2] == '53' or diveNum[:2] == '61' or diveNum[:2] == '63':
290
+ back_facing = False
291
+ else:
292
+ back_facing = True
293
+ if diveNum[0] == '1' or diveNum[:2] == '51' or diveNum[:2] == '61':
294
+ expected_direction = 'front'
295
+ elif diveNum[0] == '2' or diveNum[:2] == '52' or diveNum[:2] == '62':
296
+ expected_direction = 'back'
297
+ elif diveNum[0] == '3' or diveNum[:2] == '53' or diveNum[:2] == '63':
298
+ expected_direction = 'reverse'
299
+ elif diveNum[0] == '4':
300
+ expected_direction = 'inward'
301
+ if diveNum[-1] == 'b':
302
+ position = 'pike'
303
+ elif diveNum[-1] == 'c':
304
+ position = 'tuck'
305
+ else:
306
+ position = 'free'
307
+ return handstand, expected_som, expected_twists, back_facing, expected_direction, position
308
+
309
+ def get_direction(dive_data):
310
+ clockwise = is_rotating_clockwise(dive_data)
311
+ board_side = dive_data['board_side']
312
+ if board_side == "right":
313
+ back_facing = is_back_facing(dive_data, 'right')
314
+ if back_facing and clockwise:
315
+ direction = 'inward'
316
+ elif back_facing and not clockwise:
317
+ direction = 'back'
318
+ elif not back_facing and clockwise:
319
+ direction = 'reverse'
320
+ elif not back_facing and not clockwise:
321
+ direction = 'front'
322
+ else:
323
+ back_facing = is_back_facing(dive_data, 'left')
324
+ if back_facing and clockwise:
325
+ direction = 'back'
326
+ elif back_facing and not clockwise:
327
+ direction = 'inward'
328
+ elif not back_facing and clockwise:
329
+ direction = 'front'
330
+ elif not back_facing and not clockwise:
331
+ direction = 'reverse'
332
+ return direction
333
+
334
+ def is_rotating_clockwise(dive_data):
335
+ directions = []
336
+ for i in range(1, len(dive_data['pose_pred'])):
337
+ if dive_data['pose_pred'][i] is None or dive_data['pose_pred'][i-1] is None:
338
+ continue
339
+ if dive_data['on_boards'][i] == 0:
340
+ prev_pose_pred_hip = dive_data['pose_pred'][i-1][0][3]
341
+ curr_pose_pred_hip = dive_data['pose_pred'][i][0][3]
342
+ prev_pose_pred_knee = dive_data['pose_pred'][i-1][0][4]
343
+ curr_pose_pred_knee = dive_data['pose_pred'][i][0][4]
344
+ prev_hip_knee = [prev_pose_pred_knee[0] - prev_pose_pred_hip[0], 0-(prev_pose_pred_knee[1] - prev_pose_pred_hip[1])]
345
+ curr_hip_knee = [curr_pose_pred_knee[0] - curr_pose_pred_hip[0], 0-(curr_pose_pred_knee[1] - curr_pose_pred_hip[1])]
346
+ direction = rotation_direction(prev_hip_knee, curr_hip_knee, threshold=0)
347
+ directions.append(direction)
348
+ return np.sum(directions) < 0
349
+
350
+
351
+
generate_reports.py ADDED
@@ -0,0 +1,551 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from jinja2 import Environment, FileSystemLoader
2
+ import pickle
3
+ import os
4
+ import numpy as np
5
+ from PIL import Image, ImageDraw
6
+ from io import BytesIO
7
+ import cv2
8
+ import base64
9
+ from pathlib import Path
10
+ import torch
11
+ import gradio as gr
12
+
13
+ ############ Generate GIF functions ###################################################################################
14
+ def generate_gif(local_directory, image_names, speed_factor=1, loop=0):
15
+ """
16
+ Generate a GIF from a sequence of images paths saved in a local directory.
17
+
18
+ Parameters:
19
+ - local_directory (str): Directory path where the images are located
20
+ - image_paths (list): List of filenames of the input images.
21
+ - speed_factor (int): How fast the GIF is, the higher the less the delay is between frames
22
+ - loop (int): Number of loops (0 for infinite loop).
23
+
24
+ Returns:
25
+ - Bytes of GIF
26
+ """
27
+ images = []
28
+ durations = []
29
+ for image_name in image_names:
30
+ img = Image.open(os.path.join(local_directory, image_name))
31
+ images.append(img)
32
+ try:
33
+ duration = img.info['duration']
34
+ except KeyError:
35
+ duration = 100 # Default duration in case 'duration' is not available
36
+ durations.append(duration)
37
+
38
+ # Calculate the adjusted durations based on the speed factor
39
+ adjusted_durations = [int(duration / speed_factor) for duration in durations]
40
+
41
+ # Save as GIF to an in-memory buffer
42
+ gif_buffer = BytesIO()
43
+ images[0].save(gif_buffer, format='GIF', save_all=True, append_images=images[1:], duration=adjusted_durations, loop=loop)
44
+
45
+ # Get the content of the buffer as bytes
46
+ gif_content = gif_buffer.getvalue()
47
+ gif_content = base64.b64encode(gif_content).decode('utf-8')
48
+ return gif_content
49
+
50
+ def generate_gif_from_frames(frames, speed_factor=1, loop=0, progress=gr.Progress()):
51
+ """
52
+ Generate a GIF from a sequence of images.
53
+
54
+ Parameters:
55
+ - frames (list): List of cv2 frames
56
+ - speed_factor (int): How fast the GIF is, the higher the less the delay is between frames
57
+ - loop (int): Number of loops (0 for infinite loop).
58
+
59
+ Returns:
60
+ - Bytes of GIF
61
+ """
62
+ durations = []
63
+ images = []
64
+ i = 0
65
+ for frame in frames:
66
+ # progress((len(frames)+i)/(2*len(frames)), desc="Abstracting Symbols")
67
+ image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
68
+ images.append(image)
69
+ duration = 100 # Default duration in case 'duration' is not available
70
+ durations.append(duration)
71
+ i+=1
72
+
73
+ # Calculate the adjusted durations based on the speed factor
74
+ adjusted_durations = [int(duration / speed_factor) for duration in durations]
75
+
76
+ # images[0].save('test.gif',
77
+ # save_all = True, append_images = images[1:],
78
+ # optimize = False, duration =adjusted_durations, loop=loop)
79
+
80
+ # Save as GIF to an in-memory buffer
81
+ gif_buffer = BytesIO()
82
+ images[0].save(gif_buffer, format='GIF', save_all=True, append_images=images[1:], duration=adjusted_durations, loop=loop)
83
+
84
+ # Get the content of the buffer as bytes
85
+ gif_content = gif_buffer.getvalue()
86
+ gif_content = base64.b64encode(gif_content).decode('utf-8')
87
+ return gif_content
88
+
89
+ ##########################################################################################################
90
+ ############ Overlay Symbols on Frames ######################################################################
91
+ SKELETON = [
92
+ [1,2],[1,0],[2,6],[3,6],[4,5],[3,4],[6,7],[7,8],[9,8],[7,12],[7,13],[11,12],[13,14],[14,15],[10,11]
93
+ ]
94
+ CocoColors = [[255, 0, 0], [255, 85, 0], [255, 170, 0], [255, 255, 0], [170, 255, 0], [85, 255, 0], [0, 255, 0],
95
+ [0, 255, 85], [0, 255, 170], [0, 255, 255], [0, 170, 255], [0, 85, 255], [0, 0, 255], [85, 0, 255],
96
+ [170, 0, 255], [255, 0, 255], [255, 0, 170], [255, 0, 85]]
97
+ NUM_KPTS = 16
98
+ def draw_pose(keypoints,img, board_end_coord):
99
+ """draw the keypoints and the skeletons.
100
+ :params keypoints: the shape should be equal to [17,2]
101
+ :params img:
102
+ """
103
+ assert keypoints.shape == (NUM_KPTS,2)
104
+ for i in range(len(SKELETON)):
105
+ kpt_a, kpt_b = SKELETON[i][0], SKELETON[i][1]
106
+ x_a, y_a = keypoints[kpt_a][0],keypoints[kpt_a][1]
107
+ x_b, y_b = keypoints[kpt_b][0],keypoints[kpt_b][1]
108
+ cv2.circle(img, (int(x_a), int(y_a)), 6, CocoColors[i], -1)
109
+ cv2.circle(img, (int(x_b), int(y_b)), 6, CocoColors[i], -1)
110
+ cv2.line(img, (int(x_a), int(y_a)), (int(x_b), int(y_b)), CocoColors[i], 2)
111
+ # cv2.circle(img, board_end_coord, 4, [0, 0, 0], -1)
112
+
113
+ def draw_symbols(opencv_image, pose_preds, board_end_coord, plat_outputs, splash_pred_mask, above_board=None):
114
+ # Open image using openCV2
115
+ # opencv_image = cv2.imread(image_path)
116
+ if pose_preds is not None:
117
+ draw_pose(np.array(pose_preds)[0],opencv_image, board_end_coord)
118
+ if above_board is None or above_board==1:
119
+ draw_platform(opencv_image, plat_outputs)
120
+ draw_splash(opencv_image, splash_pred_mask)
121
+ # # Notice the COLOR_BGR2RGB which means that the color is
122
+ # # converted from BGR to RGB
123
+ # color_converted = cv2.cvtColor(opencv_image, cv2.COLOR_BGR2RGB)
124
+
125
+ # # Displaying the converted image
126
+ # pil_image = Image.fromarray(color_converted)
127
+ return opencv_image
128
+
129
+ def draw_platform(opencv_image, output):
130
+ pred_classes = output['instances'].pred_classes.cpu().numpy()
131
+ platforms = np.where(pred_classes == 0)[0]
132
+ scores = output['instances'].scores[platforms]
133
+ if len(scores) == 0:
134
+ return
135
+ pred_masks = output['instances'].pred_masks[platforms]
136
+ max_instance = torch.argmax(scores)
137
+ pred_mask = np.array(pred_masks[max_instance].cpu())
138
+ # Convert the mask to a binary image
139
+ binary_mask = pred_mask.squeeze().astype(np.uint8)
140
+ contours, hierarchy = cv2.findContours(binary_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
141
+
142
+ cv2.drawContours(opencv_image, contours[0], -1, (36, 255, 12), thickness=5)
143
+
144
+ def draw_splash(opencv_image, pred_mask):
145
+ # Convert the mask to a binary image
146
+ if pred_mask is None:
147
+ return
148
+ binary_mask = pred_mask.squeeze().astype(np.uint8)
149
+ contours, hierarchy = cv2.findContours(binary_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
150
+
151
+ cv2.drawContours(opencv_image, contours[0], -1, (0, 0, 0), thickness=5)
152
+
153
+ ##########################################################################################################
154
+ ############ Generate HTML template ######################################################################
155
+
156
+ def generate_report(template_path, data, directory, local_directory, progress=gr.Progress()):
157
+ # Load the template environment
158
+ env = Environment(loader=FileSystemLoader('.'))
159
+
160
+ file_names = os.listdir(local_directory)
161
+ file_names.sort()
162
+ file_names = np.array(file_names)
163
+ progress(0.9, desc="Generating Score Report")
164
+ # Load the template
165
+ is_twister = data['twist_position_tightness']['raw_score'] is not None
166
+ overall_score_desc = data['overall_score']['description']
167
+ overall_score = '%.1f' % data['overall_score']['raw_score']
168
+
169
+ feet_apart_score = round(float('%.2f' % data['feet_apart']['raw_score']))
170
+ feet_apart_peaks = file_names[data['feet_apart']['peaks']]
171
+ feet_apart_gif = None
172
+ has_feet_apart_peaks = False
173
+ if len(feet_apart_peaks) > 0:
174
+ has_feet_apart_peaks = True
175
+ feet_apart_gif = generate_gif(local_directory, feet_apart_peaks, speed_factor = 0.05)
176
+ feet_apart_percentile = round(float('%.2f' % (data['feet_apart']['percentile'] *100)))
177
+ feet_apart_percentile_divided_by_ten = '%.1f' % (data['feet_apart']['percentile'] *10)
178
+
179
+ include_height_off_platform = False
180
+ height_off_board_score = data['height_off_board']['raw_score']
181
+ height_off_board_percentile = data['height_off_board']['percentile']
182
+ height_off_board_description = None
183
+ height_off_board_percentile_divided_by_ten = None
184
+ encoded_height_off_board_frame = None
185
+ if height_off_board_score is not None:
186
+ include_height_off_platform = True
187
+ height_off_board_score = round(float('%.2f' % data['height_off_board']['raw_score']))
188
+ height_off_board_frame = file_names[data['height_off_board']['frame_index']]
189
+ height_off_board_frame_path = os.path.join(local_directory, height_off_board_frame)
190
+ with open(height_off_board_frame_path, "rb") as image_file:
191
+ encoded_height_off_board_frame = base64.b64encode(image_file.read()).decode('utf-8')
192
+ height_off_board_percentile = round(float('%.2f' % (data['height_off_board']['percentile'] *100)))
193
+ height_off_board_percentile_divided_by_ten = '%.1f' % (data['height_off_board']['percentile'] *10)
194
+ if float(height_off_board_percentile_divided_by_ten) > 5:
195
+ height_off_board_description = "good"
196
+ else:
197
+ height_off_board_description = "a bit on the lower side"
198
+
199
+ dist_from_board_score = '%.2f' % data['distance_from_board']['raw_score']
200
+ dist_from_board_frame = file_names[data['distance_from_board']['frame_index']]
201
+ dist_from_board_frame_path = os.path.join(local_directory, dist_from_board_frame)
202
+ with open(dist_from_board_frame_path, "rb") as image_file:
203
+ encoded_dist_from_board_frame = base64.b64encode(image_file.read()).decode('utf-8')
204
+ dist_from_board_percentile = data['distance_from_board']['percentile']
205
+ if 'good' in dist_from_board_percentile:
206
+ dist_from_board_percentile_status = "Good"
207
+ elif 'far' in dist_from_board_percentile:
208
+ dist_from_board_percentile_status = "Too Far"
209
+ else:
210
+ dist_from_board_percentile_status = "Too Close"
211
+
212
+ knee_bend_score = data['knee_bend']['raw_score']
213
+ knee_bend_percentile = data['knee_bend']['percentile']
214
+ knee_bend_frames = []
215
+ knee_bend_percentile_divided_by_ten = None
216
+ if knee_bend_score is not None:
217
+ knee_bend_score = round(float('%.2f' % (data['knee_bend']['raw_score'])))
218
+ knee_bend_frames = file_names[data['knee_bend']['frame_indices']]
219
+ knee_bend_percentile = round(float('%.2f' % (knee_bend_percentile * 100)))
220
+ knee_bend_percentile_divided_by_ten = '%.1f' % (data['knee_bend']['percentile'] * 10)
221
+
222
+ som_position_tightness_score = data['som_position_tightness']['raw_score']
223
+ som_position_tightness_percentile = data['som_position_tightness']['percentile']
224
+ som_position_tightness_position = data['som_position_tightness']['position']
225
+ som_position_tightness_frames = file_names[data['som_position_tightness']['frame_indices']]
226
+ som_position_tightness_gif = None
227
+ som_position_tightness_percentile_divided_by_ten = None
228
+ if som_position_tightness_score is not None:
229
+ if is_twister:
230
+ som_position_tightness_score = round(float('%.2f' % (data['som_position_tightness']['raw_score'] + 15)))
231
+ else:
232
+ som_position_tightness_score = round(float('%.2f' % (data['som_position_tightness']['raw_score'])))
233
+ som_position_tightness_gif = generate_gif(local_directory, som_position_tightness_frames)
234
+ som_position_tightness_percentile = round(float('%.2f' % (som_position_tightness_percentile * 100)))
235
+ som_position_tightness_percentile_divided_by_ten = '%.1f' % (data['som_position_tightness']['percentile'] * 10)
236
+ twist_position_tightness_score = data['twist_position_tightness']['raw_score']
237
+ twist_position_tightness_frames = []
238
+ twist_position_tightness_gif = None
239
+ twist_position_tightness_percentile = None
240
+ twist_position_tightness_percentile_divided_by_ten = None
241
+ if twist_position_tightness_score is not None:
242
+ twist_position_tightness_score = round(float('%.2f' % twist_position_tightness_score))
243
+ twist_position_tightness_frames = file_names[data['twist_position_tightness']['frame_indices']]
244
+ twist_position_tightness_gif = generate_gif(local_directory, twist_position_tightness_frames)
245
+ twist_position_tightness_percentile = round(float('%.2f' % (data['twist_position_tightness']['percentile'] * 100)))
246
+ twist_position_tightness_percentile_divided_by_ten = '%.1f' % (data['twist_position_tightness']['percentile'] * 10)
247
+ over_under_rotation_score = round(float('%.2f' % data['over_under_rotation']['raw_score']))
248
+ over_under_rotation_frame = file_names[data['over_under_rotation']['frame_index']]
249
+ over_under_rotation_percentile = round(float('%.2f' % (data['over_under_rotation']['percentile'] * 100)))
250
+ over_under_rotation_percentile_divided_by_ten = '%.1f' % (data['over_under_rotation']['percentile'] * 10)
251
+ straightness_during_entry_score = round(float('%.2f' % data['straightness_during_entry']['raw_score']))
252
+ straightness_during_entry_frames = file_names[data['straightness_during_entry']['frame_indices']]
253
+ straightness_during_entry_gif = generate_gif(local_directory, straightness_during_entry_frames, speed_factor = 0.5)
254
+ straightness_during_entry_percentile = round(float('%.2f' % (data['straightness_during_entry']['percentile'] * 100)))
255
+ straightness_during_entry_percentile_divided_by_ten = '%.1f' % (data['straightness_during_entry']['percentile'] * 10)
256
+ splash_score = round(float('%.2f' % data['splash']['raw_score']))
257
+ splash_frame = file_names[data['splash']['maximum_index']]
258
+ splash_indices = file_names[data['splash']['frame_indices']]
259
+ splash_gif = None
260
+ if len(splash_indices) > 0:
261
+ splash_gif = generate_gif(local_directory, splash_indices)
262
+ splash_percentile = round(float('%.2f' % (data['splash']['percentile'] * 100)))
263
+ splash_percentile_divided_by_ten = '%.1f' % (data['splash']['percentile'] * 10)
264
+ if float(splash_percentile) < 50:
265
+ splash_description = 'on the larger side'
266
+ else:
267
+ splash_description = 'small'
268
+ template = env.get_template(template_path)
269
+ data = {
270
+ 'directory' : directory,
271
+ 'local_directory': local_directory,
272
+ 'is_twister' : is_twister,
273
+ 'overall_score_desc' : overall_score_desc,
274
+ 'overall_score' : overall_score,
275
+ 'feet_apart_score' : feet_apart_score,
276
+ 'feet_apart_peaks' : feet_apart_peaks,
277
+ 'has_feet_apart_peaks' : has_feet_apart_peaks,
278
+ 'feet_apart_gif' : feet_apart_gif,
279
+ 'feet_apart_percentile' : feet_apart_percentile,
280
+ 'feet_apart_percentile_divided_by_ten': feet_apart_percentile_divided_by_ten,
281
+
282
+ 'include_height_off_platform': include_height_off_platform,
283
+ 'height_off_board_score' : height_off_board_score,
284
+ 'height_off_board_percentile' : height_off_board_percentile,
285
+ 'encoded_height_off_board_frame' : encoded_height_off_board_frame,
286
+ 'height_off_board_percentile_divided_by_ten': height_off_board_percentile_divided_by_ten,
287
+ 'height_off_board_description' : height_off_board_description,
288
+
289
+ 'dist_from_board_score' : dist_from_board_score,
290
+ 'dist_from_board_frame' : dist_from_board_frame,
291
+ 'encoded_dist_from_board_frame': encoded_dist_from_board_frame,
292
+ 'dist_from_board_percentile' : dist_from_board_percentile,
293
+ 'dist_from_board_percentile_status': dist_from_board_percentile_status,
294
+
295
+ 'knee_bend_score' : knee_bend_score,
296
+ 'knee_bend_frames' : knee_bend_frames,
297
+ 'knee_bend_percentile' : knee_bend_percentile,
298
+ 'knee_bend_percentile_divided_by_ten' : knee_bend_percentile_divided_by_ten,
299
+
300
+ 'som_position_tightness_score' : som_position_tightness_score,
301
+ 'som_position_tightness_frames' : som_position_tightness_frames,
302
+ 'som_position_tightness_gif' : som_position_tightness_gif,
303
+ 'som_position_tightness_position' : som_position_tightness_position,
304
+ 'som_position_tightness_percentile' : som_position_tightness_percentile,
305
+ 'som_position_tightness_percentile_divided_by_ten' : som_position_tightness_percentile_divided_by_ten,
306
+ 'twist_position_tightness_score' : twist_position_tightness_score,
307
+ 'twist_position_tightness_frames': twist_position_tightness_frames,
308
+ 'twist_position_tightness_percentile' : twist_position_tightness_percentile,
309
+ 'twist_position_tightness_percentile_divided_by_ten' : twist_position_tightness_percentile_divided_by_ten,
310
+ 'twist_position_tightness_gif' : twist_position_tightness_gif,
311
+ 'over_under_rotation_score' : over_under_rotation_score,
312
+ 'over_under_rotation_frame' : over_under_rotation_frame,
313
+ 'over_under_rotation_percentile' : over_under_rotation_percentile,
314
+ 'over_under_rotation_percentile_divided_by_ten' : over_under_rotation_percentile_divided_by_ten,
315
+ 'straightness_during_entry_score' : straightness_during_entry_score,
316
+ 'straightness_during_entry_gif' : straightness_during_entry_gif,
317
+ 'straightness_during_entry_percentile' : straightness_during_entry_percentile,
318
+ 'straightness_during_entry_percentile_divided_by_ten': straightness_during_entry_percentile_divided_by_ten,
319
+ 'splash_score' : splash_score,
320
+ 'splash_frame' : splash_frame,
321
+ 'splash_gif' : splash_gif,
322
+ 'splash_percentile' : splash_percentile,
323
+ 'splash_percentile_divided_by_ten': splash_percentile_divided_by_ten,
324
+ 'splash_description' : splash_description,
325
+ }
326
+ # Render the template with the provided data
327
+ report_content = template.render(data)
328
+ return report_content
329
+
330
+
331
+ def generate_report_from_frames(template_path, data, frames):
332
+ # Load the template environment
333
+ env = Environment(loader=FileSystemLoader('.'))
334
+
335
+ frames = np.array(frames)
336
+ # Load the template
337
+ is_twister = data['twist_position_tightness']['raw_score'] is not None
338
+ overall_score_desc = data['overall_score']['description']
339
+ overall_score = '%.1f' % data['overall_score']['raw_score']
340
+
341
+ feet_apart_score = round(float('%.2f' % data['feet_apart']['raw_score']))
342
+ feet_apart_peaks = frames[data['feet_apart']['peaks']]
343
+ feet_apart_gif = None
344
+ has_feet_apart_peaks = False
345
+ if len(feet_apart_peaks) > 0:
346
+ has_feet_apart_peaks = True
347
+ feet_apart_gif = generate_gif_from_frames(feet_apart_peaks, speed_factor = 0.05)
348
+ feet_apart_percentile = round(float('%.2f' % (data['feet_apart']['percentile'] *100)))
349
+ feet_apart_percentile_divided_by_ten = '%.1f' % (data['feet_apart']['percentile'] *10)
350
+
351
+ include_height_off_platform = False
352
+ height_off_board_score = data['height_off_board']['raw_score']
353
+ height_off_board_frame = None
354
+ height_off_board_percentile = None
355
+ height_off_board_percentile_divided_by_ten = None
356
+ height_off_board_description = None
357
+ encoded_height_off_board_frame = None
358
+ if height_off_board_score is not None:
359
+ include_height_off_platform = True
360
+ height_off_board_score = round(float('%.2f' % data['height_off_board']['raw_score']))
361
+ height_off_board_frame = Image.fromarray(cv2.cvtColor(frames[data['height_off_board']['frame_index']], cv2.COLOR_BGR2RGB))
362
+ height_buffer = BytesIO()
363
+ height_off_board_frame.save(height_buffer, format='JPEG')
364
+ encoded_height_off_board_frame = base64.b64encode(height_buffer.getvalue()).decode('utf-8')
365
+ height_off_board_percentile = round(float('%.2f' % (data['height_off_board']['percentile'] *100)))
366
+ height_off_board_percentile_divided_by_ten = '%.1f' % (data['height_off_board']['percentile'] *10)
367
+ if float(height_off_board_percentile_divided_by_ten) > 5:
368
+ height_off_board_description = "good"
369
+ else:
370
+ height_off_board_description = "a bit on the lower side"
371
+
372
+ dist_from_board_score = '%.2f' % data['distance_from_board']['raw_score']
373
+ dist_from_board_frame = Image.fromarray(cv2.cvtColor(frames[data['distance_from_board']['frame_index']], cv2.COLOR_BGR2RGB))
374
+ dist_buffer = BytesIO()
375
+ dist_from_board_frame.save(dist_buffer, format='JPEG')
376
+ encoded_dist_from_board_frame = base64.b64encode(dist_buffer.getvalue()).decode('utf-8')
377
+ dist_from_board_percentile = data['distance_from_board']['percentile']
378
+ if 'good' in dist_from_board_percentile:
379
+ dist_from_board_percentile_status = "Good"
380
+ elif 'far' in dist_from_board_percentile:
381
+ dist_from_board_percentile_status = "Too Far"
382
+ else:
383
+ dist_from_board_percentile_status = "Too Close"
384
+
385
+ knee_bend_score = data['knee_bend']['raw_score']
386
+ knee_bend_percentile = data['knee_bend']['percentile']
387
+ knee_bend_frames = []
388
+ knee_bend_percentile_divided_by_ten = None
389
+ if knee_bend_score is not None:
390
+ knee_bend_score = round(float('%.2f' % knee_bend_score))
391
+ knee_bend_percentile = round(float('%.2f' % (knee_bend_percentile * 100)))
392
+ knee_bend_frames = frames[data['knee_bend']['frame_indices']]
393
+ knee_bend_percentile_divided_by_ten = '%.1f' % (data['knee_bend']['percentile'] * 10)
394
+
395
+ som_position_tightness_score = data['som_position_tightness']['raw_score']
396
+ som_position_tightness_percentile = data['som_position_tightness']['percentile']
397
+ som_position_tightness_position = data['som_position_tightness']['position']
398
+ som_position_tightness_frames = []
399
+ som_position_tightness_gif = None
400
+ som_position_tightness_percentile_divided_by_ten = None
401
+ if som_position_tightness_score is not None:
402
+ if is_twister:
403
+ som_position_tightness_score = round(float('%.2f' % (data['som_position_tightness']['raw_score'] + 15)))
404
+ else:
405
+ som_position_tightness_score = round(float('%.2f' % (data['som_position_tightness']['raw_score'])))
406
+ som_position_tightness_frames = frames[data['som_position_tightness']['frame_indices']]
407
+ som_position_tightness_gif = generate_gif_from_frames(som_position_tightness_frames)
408
+ som_position_tightness_percentile = round(float('%.2f' % (som_position_tightness_percentile * 100)))
409
+ som_position_tightness_percentile_divided_by_ten = '%.1f' % (data['som_position_tightness']['percentile'] * 10)
410
+
411
+ twist_position_tightness_score = data['twist_position_tightness']['raw_score']
412
+ twist_position_tightness_frames = []
413
+ twist_position_tightness_gif = None
414
+ twist_position_tightness_percentile = None
415
+ twist_position_tightness_percentile_divided_by_ten = None
416
+ if twist_position_tightness_score is not None:
417
+ twist_position_tightness_score = round(float('%.2f' % twist_position_tightness_score))
418
+ twist_position_tightness_frames = frames[data['twist_position_tightness']['frame_indices']]
419
+ twist_position_tightness_gif = generate_gif_from_frames(twist_position_tightness_frames)
420
+ twist_position_tightness_percentile = round(float('%.2f' % (data['twist_position_tightness']['percentile'] * 100)))
421
+ twist_position_tightness_percentile_divided_by_ten = '%.1f' % (data['twist_position_tightness']['percentile'] * 10)
422
+
423
+ over_under_rotation_score = round(float('%.2f' % data['over_under_rotation']['raw_score']))
424
+ over_under_rotation_frame = frames[data['over_under_rotation']['frame_index']]
425
+ over_under_rotation_percentile = round(float('%.2f' % (data['over_under_rotation']['percentile'] * 100)))
426
+ over_under_rotation_percentile_divided_by_ten = '%.1f' % (data['over_under_rotation']['percentile'] * 10)
427
+
428
+ straightness_during_entry_score = round(float('%.2f' % data['straightness_during_entry']['raw_score']))
429
+ straightness_during_entry_frames = frames[data['straightness_during_entry']['frame_indices']]
430
+ straightness_during_entry_gif = generate_gif_from_frames(straightness_during_entry_frames, speed_factor = 0.5)
431
+ straightness_during_entry_percentile = round(float('%.2f' % (data['straightness_during_entry']['percentile'] * 100)))
432
+ straightness_during_entry_percentile_divided_by_ten = '%.1f' % (data['straightness_during_entry']['percentile'] * 10)
433
+
434
+ splash_score = round(float('%.2f' % data['splash']['raw_score']))
435
+ splash_frame = frames[data['splash']['maximum_index']]
436
+ splash_indices = frames[data['splash']['frame_indices']]
437
+ splash_gif = None
438
+ if len(splash_indices) > 0:
439
+ splash_gif = generate_gif_from_frames(splash_indices)
440
+ splash_percentile = round(float('%.2f' % (data['splash']['percentile'] * 100)))
441
+ splash_percentile_divided_by_ten = '%.1f' % (data['splash']['percentile'] * 10)
442
+ if float(splash_percentile) < 50:
443
+ splash_description = 'on the larger side'
444
+ else:
445
+ splash_description = 'small'
446
+ template = env.get_template(template_path)
447
+ data = {
448
+ 'is_twister' : is_twister,
449
+ 'overall_score_desc' : overall_score_desc,
450
+ 'overall_score' : overall_score,
451
+ 'feet_apart_score' : feet_apart_score,
452
+ 'feet_apart_peaks' : feet_apart_peaks,
453
+ 'has_feet_apart_peaks' : has_feet_apart_peaks,
454
+ 'feet_apart_gif' : feet_apart_gif,
455
+ 'feet_apart_percentile' : feet_apart_percentile,
456
+ 'feet_apart_percentile_divided_by_ten': feet_apart_percentile_divided_by_ten,
457
+ 'include_height_off_platform': include_height_off_platform,
458
+ 'height_off_board_score' : height_off_board_score,
459
+ 'height_off_board_percentile' : height_off_board_percentile,
460
+ 'encoded_height_off_board_frame' : encoded_height_off_board_frame,
461
+ 'height_off_board_percentile_divided_by_ten': height_off_board_percentile_divided_by_ten,
462
+ 'height_off_board_description' : height_off_board_description,
463
+ 'dist_from_board_score' : dist_from_board_score,
464
+ 'dist_from_board_frame' : dist_from_board_frame,
465
+ 'encoded_dist_from_board_frame': encoded_dist_from_board_frame,
466
+ 'dist_from_board_percentile' : dist_from_board_percentile,
467
+ 'dist_from_board_percentile_status': dist_from_board_percentile_status,
468
+ 'knee_bend_score' : knee_bend_score,
469
+ 'knee_bend_frames' : knee_bend_frames,
470
+ 'knee_bend_percentile' : knee_bend_percentile,
471
+ 'knee_bend_percentile_divided_by_ten' : knee_bend_percentile_divided_by_ten,
472
+ 'som_position_tightness_score' : som_position_tightness_score,
473
+ 'som_position_tightness_frames' : som_position_tightness_frames,
474
+ 'som_position_tightness_gif' : som_position_tightness_gif,
475
+ 'som_position_tightness_position' : som_position_tightness_position,
476
+ 'som_position_tightness_percentile' : som_position_tightness_percentile,
477
+ 'som_position_tightness_percentile_divided_by_ten' : som_position_tightness_percentile_divided_by_ten,
478
+ 'twist_position_tightness_score' : twist_position_tightness_score,
479
+ 'twist_position_tightness_frames': twist_position_tightness_frames,
480
+ 'twist_position_tightness_percentile' : twist_position_tightness_percentile,
481
+ 'twist_position_tightness_percentile_divided_by_ten' : twist_position_tightness_percentile_divided_by_ten,
482
+ 'twist_position_tightness_gif' : twist_position_tightness_gif,
483
+ 'over_under_rotation_score' : over_under_rotation_score,
484
+ 'over_under_rotation_frame' : over_under_rotation_frame,
485
+ 'over_under_rotation_percentile' : over_under_rotation_percentile,
486
+ 'over_under_rotation_percentile_divided_by_ten' : over_under_rotation_percentile_divided_by_ten,
487
+ 'straightness_during_entry_score' : straightness_during_entry_score,
488
+ 'straightness_during_entry_gif' : straightness_during_entry_gif,
489
+ 'straightness_during_entry_percentile' : straightness_during_entry_percentile,
490
+ 'straightness_during_entry_percentile_divided_by_ten': straightness_during_entry_percentile_divided_by_ten,
491
+ 'splash_score' : splash_score,
492
+ 'splash_frame' : splash_frame,
493
+ 'splash_gif' : splash_gif,
494
+ 'splash_percentile' : splash_percentile,
495
+ 'splash_percentile_divided_by_ten': splash_percentile_divided_by_ten,
496
+ 'splash_description' : splash_description,
497
+ }
498
+ # Render the template with the provided data
499
+ report_content = template.render(data)
500
+ return report_content
501
+
502
+ def generate_symbols_report(template_path, dive_data, frames):
503
+ # Load the template environment
504
+ env = Environment(loader=FileSystemLoader('.'))
505
+ template = env.get_template(template_path)
506
+ pose_frames = []
507
+ for i in range(len(dive_data['pose_pred'])):
508
+ # if dive_data['pose_pred'][i] is not None:
509
+ pose_frame = draw_symbols(frames[i], dive_data['pose_pred'][i], dive_data['board_end_coords'][i], dive_data['plat_outputs'][i], dive_data['splash_pred_masks'][i])
510
+ pose_frames.append(pose_frame)
511
+ pose_gif = generate_gif_from_frames(pose_frames, speed_factor=2)
512
+ # image_buffer = BytesIO()
513
+ # pose_frame.save(image_buffer, format='JPEG')
514
+ # encoded_pose_frame = base64.b64encode(image_buffer.getvalue()).decode('utf-8')
515
+ pose_data = {}
516
+ pose_data['pose_gif'] = pose_gif
517
+ html = template.render(pose_data)
518
+ return html
519
+
520
+ def generate_symbols_report_precomputed(template_path, dive_data, local_directory, progress=gr.Progress()):
521
+ # Load the template environment
522
+ file_names = os.listdir(local_directory)
523
+ file_names.sort()
524
+ file_names = np.array(file_names)
525
+
526
+ if 'above_boards' in dive_data:
527
+ above_boards = dive_data['above_boards']
528
+ else:
529
+ above_boards = [None] * len(file_names)
530
+
531
+ env = Environment(loader=FileSystemLoader('.'))
532
+ template = env.get_template(template_path)
533
+ pose_frames = []
534
+ counter = 0
535
+ for i in range(len(file_names)):
536
+ progress(i/(len(file_names)+10), desc="Abstracting Symbols")
537
+ if file_names[i][-4:] != ".jpg":
538
+ continue
539
+ # if dive_data['pose_pred'][i] is not None:
540
+ opencv_image = cv2.imread(local_directory+file_names[i])
541
+ pose_frame = draw_symbols(opencv_image, dive_data['pose_pred'][counter], dive_data['board_end_coords'][counter], dive_data['plat_outputs'][counter], dive_data['splash_pred_masks'][counter], above_board=above_boards[counter])
542
+ pose_frames.append(pose_frame)
543
+ counter +=1
544
+ pose_gif = generate_gif_from_frames(pose_frames, speed_factor=2, progress=progress)
545
+ # image_buffer = BytesIO()
546
+ # pose_frame.save(image_buffer, format='JPEG')
547
+ # encoded_pose_frame = base64.b64encode(image_buffer.getvalue()).decode('utf-8')
548
+ pose_data = {}
549
+ pose_data['pose_gif'] = pose_gif
550
+ html = template.render(pose_data)
551
+ return html
platform.png ADDED
pose_estimation.png ADDED
report_template_tables.html ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <br>
4
+ <style>
5
+ table, th, td {
6
+ border:1px solid black;
7
+ }
8
+ </style>
9
+ <!-- <br> -->
10
+ <table style="width:100%">
11
+ <tr>
12
+ <td>Your dive was {{overall_score_desc}}, and scored a <strong>{{overall_score}}</strong>. Here is how we scored each component of the dive. Each percentile is relative to dives in the semifinals and finals of Olympic and World Championship competitions.</td>
13
+ </tr>
14
+ </table>
15
+ <table style="width:100%">
16
+ <tr>
17
+ <th style="width:10%">Error</th>
18
+ <th style="width:70%">Description</th>
19
+ <th style="width:60%">Visuals</th>
20
+ <th style="width:10%">Score</th>
21
+ </tr>
22
+ <tr>
23
+ <td>Feet Apart</td>
24
+ <td>We found that your leg separation angle was on average {{feet_apart_score}}° for your dive.
25
+ This is rated as {{feet_apart_percentile}} percentile.</td>
26
+ <td>
27
+ {% if has_feet_apart_peaks %}
28
+ <!-- gif -->
29
+ <img src="data:image/gif;base64,{{feet_apart_gif}}" alt="Feet Apart GIF" width="400" height="200">
30
+ {%else%}
31
+ There were no particular instances to show where your feet came apart.
32
+ {%endif%}
33
+ </td>
34
+ <td>
35
+ {{feet_apart_percentile_divided_by_ten}}
36
+ </td>
37
+ </tr>
38
+ {% if include_height_off_platform %}
39
+ <tr>
40
+ <td>Height off platform</td>
41
+ <td>Your jump was {{height_off_board_description}}, and was rated as {{height_off_board_percentile}} percentile. Here is the highest you jumped off the platform.</td>
42
+ <td>
43
+ <img src='data:image/jpg;base64, {{encoded_height_off_board_frame}}' width="400" height="200">
44
+ </td>
45
+ <td>
46
+ {{height_off_board_percentile_divided_by_ten}}
47
+ </td>
48
+ </tr>
49
+ {% endif %}
50
+ <tr>
51
+ <td>Distance from platform</td>
52
+ <td>You were {{dist_from_board_percentile}} the platform. Here is where you came closest to the platform.</td>
53
+ <td>
54
+ <!-- <img src='{{local_directory}}/{{dist_from_board_frame}}' width="200" height="100"> -->
55
+ <img src='data:image/jpg;base64, {{encoded_dist_from_board_frame}}' width="400" height="200">
56
+ </td>
57
+ <td>
58
+ {{dist_from_board_percentile_status}}
59
+ </td>
60
+ </tr>
61
+ {% if som_position_tightness_frames|length > 0 %}
62
+ <tr>
63
+ <td>Somersault tightness</td>
64
+ <td>
65
+ We found that the tightness of your {{som_position_tightness_position}} was {{som_position_tightness_score}}° on average.
66
+ This is rated as {{som_position_tightness_percentile}} percentile. Here are some examples of your position in the somersault.
67
+ </td>
68
+ {% if knee_bend_frames|length > 0 %}
69
+ <td rowspan="2">
70
+ <!-- gif -->
71
+ <img src="data:image/gif;base64,{{som_position_tightness_gif}}" alt="Somersault GIF" width="400" height="200">
72
+ </td>
73
+ {% else %}
74
+ <td>
75
+ <!-- gif -->
76
+ <img src="data:image/gif;base64,{{som_position_tightness_gif}}" alt="Somersault GIF" width="400" height="200">
77
+ </td>
78
+ {% endif %}
79
+ <td>
80
+ {{som_position_tightness_percentile_divided_by_ten}}
81
+ </td>
82
+ </tr>
83
+ {% endif %}
84
+ {% if knee_bend_frames|length > 0 %}
85
+ <tr>
86
+ <td>Knee straightness</td>
87
+ <td>
88
+ We found that your knees bent {{knee_bend_score}}° on average.
89
+ This is rated as {{knee_bend_percentile}} percentile.
90
+ </td>
91
+ <td>
92
+ {{knee_bend_percentile_divided_by_ten}}
93
+ </td>
94
+ </tr>
95
+ {% endif %}
96
+ {% if is_twister %}
97
+ <tr>
98
+ <td>
99
+ Twist Straightness
100
+ </td>
101
+ <td>
102
+ We found that the tightness of your {{twist_position_tightness_position}} was {{twist_position_tightness_score}}° on average.
103
+ This is rated as {{twist_position_tightness_percentile}} percentile. Here are some examples of your position in the somersault.
104
+ </td>
105
+ <td>
106
+ <!-- gif -->
107
+ <img src="data:image/gif;base64,{{twist_position_tightness_gif}}" alt="Twist GIF" width="400" height="200">
108
+ </td>
109
+ <td>
110
+ {{twist_position_tightness_percentile_divided_by_ten}}
111
+ </td>
112
+ </tr>
113
+ {% endif %}
114
+ <tr>
115
+ <td>
116
+ Verticalness (over/under rotation)
117
+ </td>
118
+ <td>
119
+ We found that you deviated from vertical by {{over_under_rotation_score}}°, which was the {{over_under_rotation_percentile}} percentile.
120
+ </td>
121
+ <td rowspan="2">
122
+ <!-- gif -->
123
+ <img src="data:image/gif;base64,{{straightness_during_entry_gif}}" alt="Entry GIF" width="400" height="200">
124
+ </td>
125
+ <td>
126
+ {{over_under_rotation_percentile_divided_by_ten}}
127
+ </td>
128
+ </tr>
129
+ <tr>
130
+ <td>Body straightness during entry</td>
131
+ <td>The straightness of your body during entry deviated by {{straightness_during_entry_score}}°, which was the {{straightness_during_entry_percentile}} percentile. </td>
132
+ <td>{{straightness_during_entry_percentile_divided_by_ten}}</td>
133
+ </tr>
134
+ <tr>
135
+ <td>Splash</td>
136
+ <td>Your splash was {{splash_description}} and rated as {{splash_percentile}} percentile. </td>
137
+ <td>
138
+ <!-- gif -->
139
+ <img src="data:image/gif;base64,{{splash_gif}}" alt="Splash GIF" width="400" height="200">
140
+ </td>
141
+ <td>
142
+ {{splash_percentile_divided_by_ten}}
143
+ </td>
144
+ </tr>
145
+
146
+ </table>
147
+ </html>
148
+
149
+
scoring_functions.py ADDED
@@ -0,0 +1,579 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pickle
2
+ import numpy as np
3
+ import os
4
+ import math
5
+ from scipy.signal import find_peaks
6
+ from dive_recognition_functions import *
7
+
8
+ ### All functions (excluding helper functions) take "dive_data" as input, which is the dictionary with all the information outputted by getAllErrorsAndSegmentation() in tempSegAndAllErrorsForAllFrames.py ###
9
+
10
+ ############## HELPER FUNCTIONS ######################################
11
+ def rotation_direction(vector1, vector2, threshold=0.4):
12
+ # Calculate the determinant to determine rotation direction
13
+ determinant = vector1[0] * vector2[1] - vector1[1] * vector2[0]
14
+ mag1= np.linalg.norm(vector1)
15
+ mag2= np.linalg.norm(vector2)
16
+ norm_det = determinant/(mag1*mag2)
17
+ # print("determinant", determinant/(mag1*mag2))
18
+ # print(norm_det)
19
+ if norm_det > threshold:
20
+ # return "counterclockwise"
21
+ return 1
22
+ elif norm_det < 0-threshold:
23
+ # return "clockwise"
24
+ return -1
25
+ else:
26
+ # return "not determinent"
27
+ return 0
28
+
29
+ def find_angle(vector1, vector2):
30
+ unit_vector_1 = vector1 / np.linalg.norm(vector1)
31
+ unit_vector_2 = vector2 / np.linalg.norm(vector2)
32
+ dot_product = np.dot(unit_vector_1, unit_vector_2)
33
+ angle = math.degrees(np.arccos(dot_product))
34
+ return angle
35
+
36
+ #################################################################
37
+
38
+ def height_off_board_score(dive_data):
39
+ above_board_indices = [i for i in range(0, len(dive_data['distance_from_board'])) if dive_data['above_boards'][i]==1]
40
+ takeoff_indices = [i for i in range(0, len(dive_data['takeoff'])) if dive_data['takeoff'][i]==1]
41
+ final_indices = []
42
+ prev_board_end_coord = None
43
+ for i in range(len(above_board_indices)):
44
+ board_end_coord = dive_data['board_end_coords'][i]
45
+ if board_end_coord is not None and board_end_coord[1] < 30:
46
+ continue
47
+ if board_end_coord is not None and prev_board_end_coord is not None and math.dist(board_end_coord, prev_board_end_coord) > 150:
48
+ continue
49
+ if above_board_indices[i] not in takeoff_indices:
50
+ final_indices.append(above_board_indices[i])
51
+ prev_board_end_coord = board_end_coord
52
+
53
+ heights = []
54
+ for i in range(len(final_indices)):
55
+ pose_pred = dive_data['pose_pred'][final_indices[i]]
56
+ board_end_coord = dive_data['board_end_coords'][final_indices[i]]
57
+ if pose_pred is None or board_end_coord is None:
58
+ continue
59
+ pose_pred = pose_pred[0]
60
+ min_height = float('inf')
61
+ for j in range(len(pose_pred)):
62
+ if board_end_coord[1] - pose_pred[j][1]< min_height:
63
+ min_height = board_end_coord[1] - pose_pred[j][1]
64
+ if min_height < 0:
65
+ min_height = 0
66
+ heights.append(min_height)
67
+ if len(heights) == 0:
68
+ return None, None
69
+ max_scaled_height = max(heights) / get_scale_factor(dive_data)
70
+ return max_scaled_height, final_indices[np.argmax(heights)]
71
+
72
+ def distance_from_board_score(dive_data):
73
+ above_board_indices = [i for i in range(0, len(dive_data['distance_from_board'])) if dive_data['above_boards'][i]==1]
74
+ takeoff_indices = [i for i in range(0, len(dive_data['takeoff'])) if dive_data['takeoff'][i]==1]
75
+ final_indices = []
76
+ for i in range(len(above_board_indices)):
77
+ if above_board_indices[i] not in takeoff_indices:
78
+ final_indices.append(above_board_indices[i])
79
+ dists = np.array(dive_data['distance_from_board'])[final_indices]
80
+ for i in range(len(dists)):
81
+ if dists[i] is None:
82
+ dists[i] = float('inf')
83
+ # if np.min(dists) > 75:
84
+ # print(dive_data)
85
+ min_scaled_dist = np.min(dists) / get_scale_factor(dive_data)
86
+ too_close_threshold = 0.25
87
+ # if ground_truth[dive_data][0][:2] == '52':
88
+ # too_far_threshold = 1.1
89
+ # too_far_threshold is 75%tile
90
+ if 'diveNum' in dive_data:
91
+ if dive_data['diveNum'][0] == '4':
92
+ too_far_threshold = 1.1
93
+ if dive_data['diveNum'][0] == '1':
94
+ too_far_threshold = 1.6
95
+ if dive_data['diveNum'][0] == '2':
96
+ too_far_threshold = 1.8
97
+ if dive_data['diveNum'][0] == '3':
98
+ too_far_threshold = 1.6
99
+ if dive_data['diveNum'][0] == '5':
100
+ too_far_threshold = 1.5
101
+ if dive_data['diveNum'][0] == '6':
102
+ too_far_threshold = 1.1
103
+ else:
104
+ too_far_threshold = 1.8
105
+ # good distance
106
+ if min_scaled_dist < too_far_threshold and min_scaled_dist > too_close_threshold:
107
+ return 0, min_scaled_dist, final_indices[np.argmin(dists)]
108
+ # too far
109
+ if min_scaled_dist >= too_far_threshold:
110
+ return 1, min_scaled_dist, final_indices[np.argmin(dists)]
111
+ # too close
112
+ if min_scaled_dist <= too_close_threshold:
113
+ return -1, min_scaled_dist, final_indices[np.argmin(dists)]
114
+ return min_scaled_dist
115
+
116
+ def knee_bend_score(dive_data):
117
+ if find_position(dive_data) == 'tuck':
118
+ return None, None
119
+ knee_bends = []
120
+ for i in range(len(dive_data['pose_pred'])):
121
+ if dive_data['som'][i] == 0:
122
+ continue
123
+ pose_pred = dive_data['pose_pred'][i]
124
+ if pose_pred is None:
125
+ continue
126
+ pose_pred = pose_pred[0]
127
+ knee_to_ankle = [pose_pred[1][0] - pose_pred[0][0], 0-(pose_pred[1][1]-pose_pred[0][1])]
128
+ knee_to_hip = [pose_pred[1][0] - pose_pred[2][0], 0-(pose_pred[1][1]-pose_pred[2][1])]
129
+ knee_bend = find_angle(knee_to_ankle, knee_to_hip)
130
+ knee_bends.append(knee_bend)
131
+ if len(knee_bends) == 0:
132
+ return None, None
133
+ som_indices = [i for i in range(0, len(dive_data['som'])) if dive_data['som'][i]==1]
134
+ som_avg_knee_bend = np.mean(knee_bends)
135
+ return 180 - som_avg_knee_bend, som_indices
136
+
137
+ def position_tightness_score(dive_data):
138
+ som_indices = [i for i in range(0, len(dive_data['som'])) if dive_data['som'][i]==1]
139
+ twist_indices = [i for i in range(0, len(dive_data['som'])) if dive_data['twist'][i]==1]
140
+ som_tightness = np.array(dive_data['position_tightness'])[som_indices]
141
+ twist_tightness = 180 - np.array(dive_data['position_tightness'])[twist_indices]
142
+
143
+ # plt.plot(range(len(som_tightness)), som_tightness)
144
+ # plt.plot(range(len(twist_tightness)), twist_tightness)
145
+ # Compute the area using the composite trapezoidal rule.
146
+ som_tightness = np.array(list(filter(lambda item: item is not None and item < 90, som_tightness)))
147
+ twist_tightness = np.array(list(filter(lambda item: item is not None and item < 90, twist_tightness)))
148
+ if len(som_indices) == 0:
149
+ som_avg = None
150
+ else:
151
+ # som_area = np.trapz(som_tightness, dx=5) / len(som_tightness)
152
+ som_avg = np.mean(som_tightness)
153
+ # print("som area =", som_area)
154
+ if len(twist_indices)==0:
155
+ return som_avg, None, som_indices, twist_indices
156
+ # twist_area = np.trapz(twist_tightness, dx=5) / len(twist_tightness)
157
+ twist_avg = np.mean(twist_tightness)
158
+ if som_avg is not None:
159
+ som_avg -= 15
160
+ # print("twist area =",twist_area)
161
+ return som_avg, twist_avg, som_indices, twist_indices
162
+
163
+ def is_rotating_clockwise(dive_data):
164
+ directions = []
165
+ for i in range(1, len(dive_data['pose_pred'])):
166
+ if dive_data['pose_pred'][i] is None or dive_data['pose_pred'][i-1] is None:
167
+ continue
168
+ if dive_data['on_boards'][i] == 0:
169
+ prev_pose_pred_hip = dive_data['pose_pred'][i-1][0][3]
170
+ curr_pose_pred_hip = dive_data['pose_pred'][i][0][3]
171
+ prev_pose_pred_knee = dive_data['pose_pred'][i-1][0][4]
172
+ curr_pose_pred_knee = dive_data['pose_pred'][i][0][4]
173
+ prev_hip_knee = [prev_pose_pred_knee[0] - prev_pose_pred_hip[0], 0-(prev_pose_pred_knee[1] - prev_pose_pred_hip[1])]
174
+ curr_hip_knee = [curr_pose_pred_knee[0] - curr_pose_pred_hip[0], 0-(curr_pose_pred_knee[1] - curr_pose_pred_hip[1])]
175
+ direction = rotation_direction(prev_hip_knee, curr_hip_knee, threshold=0)
176
+ directions.append(direction)
177
+ return np.sum(directions) < 0
178
+
179
+ def over_under_rotation_score(dive_data):
180
+ entry_indices = [i for i in range(0, len(dive_data['entry'])) if dive_data['entry'][i]==1]
181
+ over_under_rotation_error = np.array(dive_data['over_under_rotation'])[entry_indices]
182
+ splashes = np.array(dive_data['splash'])[entry_indices]
183
+ for i in range(len(over_under_rotation_error) - 1, -1, -1):
184
+ if over_under_rotation_error[i] is None:
185
+ continue
186
+ else:
187
+ # gets the second to last pose (assuming the last pose has incorrect pose estimation)
188
+ # print(over_under_rotation_error[i-1]-90)
189
+ index = i-2
190
+ if index < 0:
191
+ index = 0
192
+ total_index = entry_indices[index]
193
+ if splashes[index] is None and over_under_rotation_error[index] is not None:
194
+ # print(entry_indices)
195
+ # print(entry_indices[i-3])
196
+ # return np.cos(math.radians(over_under_rotation_error[i-1]-90+10))
197
+ # avg_leg_torso = over_under_rotation_error[i-1]-90 +10 - straightness_during_entry_score(dive_data)
198
+ pose_pred = dive_data['pose_pred'][total_index][0]
199
+ thorax_pelvis_vector = [pose_pred[1][0] - pose_pred[7][0], 0-(pose_pred[1][1]-pose_pred[7][1])]
200
+ prev_pose_pred = dive_data['pose_pred'][total_index - 1]
201
+ if prev_pose_pred is not None:
202
+ # print(dive_data)
203
+ prev_pose_pred = prev_pose_pred[0]
204
+ prev_thorax_pelvis_vector = [prev_pose_pred[1][0] - prev_pose_pred[7][0], 0-(prev_pose_pred[1][1]-prev_pose_pred[7][1])]
205
+ rotation_speed = find_angle(thorax_pelvis_vector, prev_thorax_pelvis_vector)
206
+ else:
207
+ rotation_speed = 10
208
+ # print(rotation_speed)
209
+ vector2 = [0, 1]
210
+ # print(find_angle(thorax_pelvis_vector, vector2))
211
+ # print(thorax_pelvis_vector, prev_thorax_pelvis_vector)
212
+ if is_rotating_clockwise(dive_data):
213
+ # if under-rotated
214
+ if thorax_pelvis_vector[0] < 0:
215
+ avg_leg_torso = find_angle(thorax_pelvis_vector, vector2) - rotation_speed
216
+
217
+ else:
218
+ avg_leg_torso = find_angle(thorax_pelvis_vector, vector2) + rotation_speed
219
+ else:
220
+ # if over-rotated
221
+ if thorax_pelvis_vector[0] < 0:
222
+ avg_leg_torso = find_angle(thorax_pelvis_vector, vector2) + rotation_speed
223
+ else:
224
+ avg_leg_torso = find_angle(thorax_pelvis_vector, vector2) - rotation_speed
225
+ # avg_leg_torso = over_under_rotation_error[i-1]-90 +10 - np.array(dive_data['position_tightness'])[entry_indices][i-1]
226
+ return np.abs(avg_leg_torso), entry_indices[index]
227
+ break
228
+
229
+ def straightness_during_entry_score(dive_data):
230
+ entry_indices = [i for i in range(0, len(dive_data['entry'])) if dive_data['entry'][i]==1]
231
+ straightness_during_entry = np.array(dive_data['position_tightness'])[entry_indices]
232
+ over_under_rotation = over_under_rotation_score(dive_data)
233
+ if over_under_rotation is not None:
234
+ frame = over_under_rotation[1]
235
+ index = entry_indices.index(frame) - 1
236
+ if index < 0:
237
+ index = 0
238
+ return 180-straightness_during_entry[index], [frame-1, frame, frame + 1]
239
+ splashes = np.array(dive_data['splash'])[entry_indices]
240
+ for i in range(len(straightness_during_entry) - 1, -1, -1):
241
+ if i > 0 and (straightness_during_entry[i] is None or splashes[i] is not None):
242
+ continue
243
+ else:
244
+ # gets the second to last pose (assuming the last pose has incorrect pose estimation)
245
+ if straightness_during_entry[i] is not None:
246
+ if 180-straightness_during_entry[i] > 130:
247
+ continue
248
+ return 180-straightness_during_entry[i], entry_indices[i-1:i+2]
249
+ break
250
+
251
+ def splash_score(dive_data):
252
+ entry_indices = [i for i in range(0, len(dive_data['entry'])) if dive_data['entry'][i]==1]
253
+ if len(entry_indices) == 0:
254
+ return None
255
+ splash_indices=[i for i in range(0, len(dive_data['splash'])) if dive_data['splash'][i] is not None]
256
+ splashes = np.array(dive_data['splash'])[entry_indices]
257
+ for i in range(len(splashes)):
258
+ if splashes[i] is None:
259
+ splashes[i] = 0
260
+ splashes = splashes / get_scale_factor(dive_data)**2
261
+
262
+ # area under curve
263
+ # plt.plot(range(len(splashes)), splashes)
264
+ area = np.trapz(splashes, dx=5)
265
+ # print("area =", area)
266
+
267
+ # if area < 0.002:
268
+ # print(dive_data)
269
+ return area, entry_indices[np.argmax(splashes)], splash_indices
270
+
271
+ # feet apart
272
+ def feet_apart_score(dive_data):
273
+ takeoff_indices = [i for i in range(0, len(dive_data['takeoff'])) if dive_data['takeoff'][i]==1]
274
+ non_takeoff_indices = [i for i in range(len(dive_data['takeoff'])) if (i not in takeoff_indices and dive_data['splash'][i] is None)]
275
+ feet_apart_error = np.array(dive_data['feet_apart'])[non_takeoff_indices]
276
+ # plt.plot(range(len(feet_apart_error)), feet_apart_error)
277
+ for i in range(len(feet_apart_error)):
278
+ if feet_apart_error[i] is None or math.isnan(feet_apart_error[i]):
279
+ feet_apart_error[i] = 0
280
+ peaks, _ = find_peaks(feet_apart_error, height=5)
281
+ if len(peaks) >= 1:
282
+ peak_indices = np.array(non_takeoff_indices)[peaks]
283
+ # elif len(peaks) == 1:
284
+ # peak_indices = non_takeoff_indices[peaks[0]]
285
+ else:
286
+ peak_indices = []
287
+ # print(len(peaks))
288
+ # return peaks
289
+ # area = np.trapz(feet_apart_error, dx=5) /len(non_takeoff_indices)
290
+ area = np.mean(feet_apart_error)
291
+
292
+ # print(area)
293
+ return area, peak_indices
294
+
295
+ def find_position(dive_data):
296
+ angles = []
297
+ three_in_a_row = 0
298
+ for i in range(1, len(dive_data['pose_pred'])):
299
+ pose_pred = dive_data['pose_pred'][i]
300
+ if pose_pred is None or dive_data['som'][i]==0:
301
+ continue
302
+ pose_pred = pose_pred[0]
303
+ l_knee = pose_pred[4]
304
+ l_ankle = pose_pred[5]
305
+ l_hip = pose_pred[3]
306
+ l_knee_ankle = [l_ankle[0] - l_knee[0], 0-(l_ankle[1] - l_knee[1])]
307
+ l_knee_hip = [l_hip[0] - l_knee[0], 0-(l_hip[1] - l_knee[1])]
308
+ angle = find_angle(l_knee_ankle, l_knee_hip)
309
+ angles.append(angle)
310
+ # print(angle)
311
+ if angle < 70:
312
+ three_in_a_row += 1
313
+ if three_in_a_row >=3:
314
+ return 'tuck'
315
+ else:
316
+ three_in_a_row =0
317
+ # if np.mean(angles) < 100:
318
+ # return 'tuck'
319
+ # print(som_counter(dive_data))
320
+ # print(twist_counter(dive_data))
321
+ # if twist_counter_full_dive(dive_data) > 0 and som_counter_full_dive(dive_data)[0] < 5:
322
+ # return 'free'
323
+ return 'pike'
324
+
325
+ def get_position_from_diveNum(dive_data):
326
+ diveNum = dive_data['diveNum']
327
+ position_code = diveNum[-1]
328
+ if position_code == 'a':
329
+ return "straight"
330
+ elif position_code == 'b':
331
+ return "pike"
332
+ elif position_code == 'c':
333
+ return "tuck"
334
+ elif position_code == 'd':
335
+ return "free"
336
+ else:
337
+ return None
338
+
339
+ def get_all_report_scores(dive_data):
340
+ # with open('all_distributions.npy', 'rb') as f:
341
+ # feet_apart_scores = np.load(f)
342
+ # distance_from_board_scores = np.load(f)
343
+ # som_position_tightness_scores = np.load(f)
344
+ # twist_position_tightness_scores = np.load(f)
345
+ # over_under_rotation_scores = np.load(f)
346
+ # straightness_during_entry_scores = np.load(f)
347
+ # splash_scores = np.load(f)
348
+ with open('distribution_data.pkl', 'rb') as f:
349
+ distribution_data = pickle.load(f)
350
+ ## handstand and som_count##
351
+ expected_som, handstand = som_counter_full_dive(dive_data)
352
+ ## twist_count
353
+ expected_twists = twist_counter_full_dive(dive_data)
354
+ ## direction: front, back, reverse, inward
355
+ expected_direction = get_direction(dive_data)
356
+ dive_data['is_handstand'] = handstand
357
+ dive_data['direction'] = expected_direction
358
+
359
+ intermediate_scores = {}
360
+ all_percentiles = []
361
+ entry_indices = [i for i in range(0, len(dive_data['entry'])) if dive_data['entry'][i]==1]
362
+
363
+ ### height off board ###
364
+ if dive_data['is_handstand']:
365
+ error_scores = distribution_data['armstand_height_off_board_scores']
366
+ elif expected_twists >0:
367
+ error_scores = distribution_data['twist_height_off_board_scores']
368
+ elif dive_data['direction']=='front':
369
+ error_scores = distribution_data['front_height_off_board_scores']
370
+ elif dive_data['direction']=='back':
371
+ error_scores = distribution_data['back_height_off_board_scores']
372
+ elif dive_data['direction']=='reverse':
373
+ error_scores = distribution_data['reverse_height_off_board_scores']
374
+ elif dive_data['direction']=='inward':
375
+ error_scores = distribution_data['inward_height_off_board_scores']
376
+ error_scores = list(filter(lambda item: item is not None, error_scores))
377
+ intermediate_scores['height_off_board'] = {}
378
+ if dive_data['is_handstand']:
379
+ intermediate_scores['height_off_board']['raw_score'] = None
380
+ intermediate_scores['height_off_board']['frame_index'] = None
381
+ else:
382
+ intermediate_scores['height_off_board']['raw_score'] = height_off_board_score(dive_data)[0]
383
+ intermediate_scores['height_off_board']['frame_index'] = height_off_board_score(dive_data)[1]
384
+ err = intermediate_scores['height_off_board']['raw_score']
385
+ if err is not None:
386
+ temp = error_scores
387
+ temp.append(err)
388
+ temp.sort()
389
+ intermediate_scores['height_off_board']['percentile'] = temp.index(err)/len(temp)
390
+ all_percentiles.append(temp.index(err)/len(temp))
391
+ else:
392
+ intermediate_scores['height_off_board']['percentile'] = None
393
+
394
+ ## distance from board ####
395
+ error_scores = distribution_data['distance_from_board_scores']
396
+ error_scores = list(filter(lambda item: item is not None, error_scores))
397
+ intermediate_scores['distance_from_board'] = {}
398
+ intermediate_scores['distance_from_board']['raw_score'] = distance_from_board_score(dive_data)[1]
399
+ intermediate_scores['distance_from_board']['frame_index'] = distance_from_board_score(dive_data)[2]
400
+ err = distance_from_board_score(dive_data)[0]
401
+ if err is not None:
402
+ if err == 1:
403
+ intermediate_scores['distance_from_board']['percentile'] = "safe, but too far from"
404
+ intermediate_scores['distance_from_board']['score'] = 0.5
405
+
406
+ elif err == 0:
407
+ intermediate_scores['distance_from_board']['percentile'] = "a good distance from"
408
+ intermediate_scores['distance_from_board']['score'] = 1
409
+ else:
410
+ intermediate_scores['distance_from_board']['percentile'] = "too close to"
411
+ intermediate_scores['distance_from_board']['score'] = 0
412
+ all_percentiles.append(intermediate_scores['distance_from_board']['score'])
413
+ else:
414
+ intermediate_scores['distance_from_board']['percentile'] = None
415
+ intermediate_scores['distance_from_board']['score'] = None
416
+
417
+ ### feet_apart_scores ###
418
+ error_scores = distribution_data['feet_apart_scores']
419
+ error_scores = list(filter(lambda item: item is not None, error_scores))
420
+ intermediate_scores['feet_apart'] = {}
421
+ intermediate_scores['feet_apart']['raw_score'] = feet_apart_score(dive_data)[0]
422
+ intermediate_scores['feet_apart']['peaks'] = feet_apart_score(dive_data)[1]
423
+ err = intermediate_scores['feet_apart']['raw_score']
424
+ if err is not None:
425
+ temp = error_scores
426
+ temp.append(err)
427
+ temp.sort()
428
+ intermediate_scores['feet_apart']['percentile'] = 1-temp.index(err)/len(temp)
429
+ all_percentiles.append(1-temp.index(err)/len(temp))
430
+ else:
431
+ intermediate_scores['feet_apart']['percentile'] = None
432
+
433
+ ### knee_bend_scores ###
434
+ error_scores = distribution_data['knee_bend_scores']
435
+ error_scores = list(filter(lambda item: item is not None, error_scores))
436
+ intermediate_scores['knee_bend'] = {}
437
+ intermediate_scores['knee_bend']['raw_score'] = knee_bend_score(dive_data)[0]
438
+ intermediate_scores['knee_bend']['frame_indices'] = knee_bend_score(dive_data)[1]
439
+ err = intermediate_scores['knee_bend']['raw_score']
440
+ if err is not None:
441
+ temp = error_scores
442
+ temp.append(err)
443
+ temp.sort()
444
+ intermediate_scores['knee_bend']['percentile'] = 1-temp.index(err)/len(temp)
445
+ all_percentiles.append(1-temp.index(err)/len(temp))
446
+ else:
447
+ intermediate_scores['knee_bend']['percentile'] = None
448
+
449
+
450
+ ### som_position_tightness_scores ###
451
+ error_scores = distribution_data['som_position_tightness_scores']
452
+ error_scores = list(filter(lambda item: item is not None, error_scores))
453
+ intermediate_scores['som_position_tightness'] = {}
454
+ position = find_position(dive_data)
455
+ if position == 'tuck':
456
+ intermediate_scores['som_position_tightness']['position'] = 'tuck'
457
+ else:
458
+ intermediate_scores['som_position_tightness']['position'] = 'pike'
459
+ intermediate_scores['som_position_tightness']['raw_score'] = position_tightness_score(dive_data)[0]
460
+ intermediate_scores['som_position_tightness']['frame_indices'] = position_tightness_score(dive_data)[2]
461
+ err = intermediate_scores['som_position_tightness']['raw_score']
462
+ if err is not None:
463
+ temp = error_scores
464
+ temp.append(err)
465
+ temp.sort()
466
+ intermediate_scores['som_position_tightness']['percentile'] = 1-temp.index(err)/len(temp)
467
+ all_percentiles.append(1-temp.index(err)/len(temp))
468
+ else:
469
+ intermediate_scores['som_position_tightness']['percentile'] = None
470
+
471
+ ### twist_position_tightness_scores ###
472
+ error_scores = distribution_data['twist_position_tightness_scores']
473
+ error_scores = list(filter(lambda item: item is not None, error_scores))
474
+ intermediate_scores['twist_position_tightness'] = {}
475
+ intermediate_scores['twist_position_tightness']['raw_score'] = position_tightness_score(dive_data)[1]
476
+ intermediate_scores['twist_position_tightness']['frame_indices'] = position_tightness_score(dive_data)[3]
477
+ err = intermediate_scores['twist_position_tightness']['raw_score']
478
+ if err is not None:
479
+ temp = error_scores
480
+ temp.append(err)
481
+ temp.sort()
482
+ intermediate_scores['twist_position_tightness']['percentile'] = 1-temp.index(err)/len(temp)
483
+ all_percentiles.append(1-temp.index(err)/len(temp))
484
+ else:
485
+ intermediate_scores['twist_position_tightness']['percentile'] = None
486
+
487
+ ### over_under_rotation_scores ###
488
+ error_scores = distribution_data['over_under_rotation_scores']
489
+ error_scores = list(filter(lambda item: item is not None, error_scores))
490
+ intermediate_scores['over_under_rotation'] = {}
491
+ if over_under_rotation_score(dive_data) is not None:
492
+ intermediate_scores['over_under_rotation']['raw_score'] = over_under_rotation_score(dive_data)[0]
493
+ intermediate_scores['over_under_rotation']['frame_index'] = over_under_rotation_score(dive_data)[1]
494
+ else:
495
+ intermediate_scores['over_under_rotation']['raw_score'] = None
496
+ intermediate_scores['over_under_rotation']['frame_index'] = None
497
+ err = intermediate_scores['over_under_rotation']['raw_score']
498
+ if err is not None:
499
+ temp = error_scores
500
+ temp.append(err)
501
+ temp.sort()
502
+ intermediate_scores['over_under_rotation']['percentile'] = 1-temp.index(err)/len(temp)
503
+ all_percentiles.append(1-temp.index(err)/len(temp))
504
+
505
+ else:
506
+ intermediate_scores['over_under_rotation']['percentile'] = None
507
+
508
+ ### splash_scores ###
509
+ error_scores = distribution_data['splash_scores']
510
+ error_scores = list(filter(lambda item: item is not None, error_scores))
511
+ intermediate_scores['splash'] = {}
512
+ intermediate_scores['splash']['raw_score'] = splash_score(dive_data)[0]
513
+ intermediate_scores['splash']['maximum_index'] = splash_score(dive_data)[1]
514
+ intermediate_scores['splash']['frame_indices'] = splash_score(dive_data)[2]
515
+
516
+ err = intermediate_scores['splash']['raw_score']
517
+ if err is not None:
518
+ temp = error_scores
519
+ temp.append(err)
520
+ temp.sort()
521
+ intermediate_scores['splash']['percentile'] = 1-temp.index(err)/len(temp)
522
+ all_percentiles.append(1-temp.index(err)/len(temp))
523
+
524
+ else:
525
+ intermediate_scores['splash']['percentile'] = None
526
+
527
+ ### straightness_during_entry_scores ###
528
+ error_scores = distribution_data['straightness_during_entry_scores']
529
+ error_scores = list(filter(lambda item: item is not None, error_scores))
530
+ intermediate_scores['straightness_during_entry'] = {}
531
+ if straightness_during_entry_score(dive_data) is not None:
532
+ intermediate_scores['straightness_during_entry']['raw_score'] = straightness_during_entry_score(dive_data)[0]
533
+ intermediate_scores['straightness_during_entry']['frame_indices'] = straightness_during_entry_score(dive_data)[1]
534
+ else:
535
+ intermediate_scores['straightness_during_entry']['raw_score'] = None
536
+ intermediate_scores['straightness_during_entry']['frame_index'] = None
537
+
538
+ err = intermediate_scores['straightness_during_entry']['raw_score']
539
+ if err is not None:
540
+ temp = error_scores
541
+ temp.append(err)
542
+ temp.sort()
543
+ intermediate_scores['straightness_during_entry']['percentile'] = 1-temp.index(err)/len(temp)
544
+ all_percentiles.append(1-temp.index(err)/len(temp))
545
+
546
+ else:
547
+ intermediate_scores['straightness_during_entry']['percentile'] = None
548
+
549
+ ## overall score ###
550
+ # Excellent: 10
551
+ # Very Good: 8.5-9.5
552
+ # Good: 7.0-8.0
553
+ # Satisfactory: 5.0-6.5
554
+ # Deficient: 2.5-4.5
555
+ # Unsatisfactory: 0.5-2.0
556
+ # Completely failed: 0
557
+ overall_score = np.mean(all_percentiles) * 10
558
+ intermediate_scores['overall_score'] = {}
559
+ intermediate_scores['overall_score']['raw_score'] = overall_score
560
+ if overall_score == 10:
561
+ intermediate_scores['overall_score']['description'] = 'excellent'
562
+ elif overall_score >=8.5 and overall_score <10:
563
+ intermediate_scores['overall_score']['description'] = 'very good'
564
+ elif overall_score >=7 and overall_score <8.5:
565
+ intermediate_scores['overall_score']['description'] = 'good'
566
+ elif overall_score >=5 and overall_score <7:
567
+ intermediate_scores['overall_score']['description'] = 'satisfactory'
568
+ elif overall_score >=2.5 and overall_score <5:
569
+ intermediate_scores['overall_score']['description'] = 'deficient'
570
+ elif overall_score >0 and overall_score <2.5:
571
+ intermediate_scores['overall_score']['description'] = 'unsatisfactory'
572
+ else:
573
+ intermediate_scores['overall_score']['description'] = 'completely failed'
574
+
575
+ return intermediate_scores
576
+
577
+
578
+
579
+
splash.png ADDED
tempSegAndAllErrorsForAllFrames.py ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from microprograms.temporal_segmentation.entry import entry_microprogram_one_frame
2
+ from microprograms.temporal_segmentation.somersault import somersault_microprogram_one_frame
3
+ from microprograms.temporal_segmentation.twist import twist_microprogram_one_frame
4
+ from microprograms.temporal_segmentation.start_takeoff import takeoff_microprogram_one_frame
5
+ from microprograms.errors.distance_from_springboard_micro_program import board_end
6
+ from microprograms.errors.splash_micro_program import get_splash_from_one_frame
7
+ from microprograms.errors.distance_from_springboard_micro_program import calculate_distance_from_springboard_for_one_frame
8
+ from microprograms.errors.distance_from_springboard_micro_program import calculate_distance_from_platform_for_one_frame
9
+ from microprograms.errors.angles_micro_programs import applyFeetApartError
10
+ from microprograms.errors.angles_micro_programs import applyPositionTightnessError
11
+ from models.detectron2.platform_detector_setup import get_platform_detector
12
+ from models.pose_estimator.pose_estimator_model_setup import get_pose_estimation
13
+ from models.detectron2.diver_detector_setup import get_diver_detector
14
+ from models.pose_estimator.pose_estimator_model_setup import get_pose_model
15
+ from models.detectron2.splash_detector_setup import get_splash_detector
16
+ from somersault_counter import som_counter, twist_counter
17
+ from microprograms.errors.over_rotation import over_rotation
18
+ from temporal_segmentation import detect_on_board
19
+ import pickle
20
+ import os
21
+ import math
22
+ import numpy as np
23
+ import cv2
24
+ with open('segmentation_error_data.pkl', 'rb') as f:
25
+ data = pickle.load(f)
26
+
27
+ def getDiveInfo_from_diveNum(diveNum):
28
+ handstand = (diveNum[0] == '6')
29
+ expected_som = int(diveNum[2])
30
+ if len(diveNum) == 5:
31
+ expected_twists = int(diveNum[3])
32
+ else:
33
+ expected_twists = 0
34
+ if diveNum[0] == '1' or diveNum[0] == '3' or diveNum[:2] == '51' or diveNum[:2] == '53' or diveNum[:2] == '61' or diveNum[:2] == '63':
35
+ back_facing = False
36
+ else:
37
+ back_facing = True
38
+ if diveNum[0] == '1' or diveNum[:2] == '51' or diveNum[:2] == '61':
39
+ expected_direction = 'front'
40
+ elif diveNum[0] == '2' or diveNum[:2] == '52' or diveNum[:2] == '62':
41
+ expected_direction = 'back'
42
+ elif diveNum[0] == '3' or diveNum[:2] == '53' or diveNum[:2] == '63':
43
+ expected_direction = 'reverse'
44
+ elif diveNum[0] == '4':
45
+ expected_direction = 'inward'
46
+ if diveNum[-1] == 'b':
47
+ position = 'pike'
48
+ elif diveNum[-1] == 'c':
49
+ position = 'tuck'
50
+ else:
51
+ position = 'free'
52
+ return handstand, expected_som, expected_twists, back_facing, expected_direction, position
53
+
54
+ def getAllErrorsAndSegmentation(first_folder, second_folder, diveNum, board_side=None, platform_detector=None, splash_detector=None, diver_detector=None, pose_model=None):
55
+ handstand, expected_som, expected_twists, back_facing, expected_direction, position = getDiveInfo_from_diveNum(diveNum)
56
+ # first_folder = input("what is the first folder? Ex: 01, FINAWorldChampionships2019_Women10m_final_r1, etc. ")
57
+ # second_folder = input("what is the second folder? (dive within the first folder)")
58
+ dive_data = {}
59
+ takeoff = []
60
+ twist = []
61
+ som = []
62
+ entry = []
63
+ distance_from_board = []
64
+ position_tightness = []
65
+ feet_apart = []
66
+ over_under_rotation = []
67
+ splash = []
68
+ pose_preds = []
69
+ diver_boxes = []
70
+ above_boards = []
71
+ on_boards = []
72
+ som_counts = []
73
+ twist_counts = []
74
+ board_end_coords = []
75
+ plat_outputs = []
76
+ splash_pred_masks = []
77
+ above_board = True
78
+ on_board = True
79
+ if platform_detector is None:
80
+ platform_detector = get_platform_detector()
81
+ if splash_detector is None:
82
+ splash_detector = get_splash_detector()
83
+ if diver_detector is None:
84
+ diver_detector = get_diver_detector()
85
+ if pose_model is None:
86
+ pose_model = get_pose_model()
87
+ key = (first_folder, int(second_folder))
88
+ dive_folder_num = "{}_{}".format(first_folder, second_folder)
89
+ directory = './FineDiving/datasets/FINADiving_MTL_256s/{}/{}/'.format(first_folder, second_folder)
90
+ file_names = os.listdir(directory)
91
+ # with open('./output/joint_plots/{}/pose_preds.pkl'.format(dive_folder_num), 'rb') as pickle_file:
92
+ # pose_preds = pickle.load(pickle_file)
93
+ j = 0
94
+ prev_pred = None
95
+ som_prev_pred = None
96
+ half_som_count=0
97
+ petal_count = 0
98
+ in_petal = False
99
+ for i in range(len(file_names)):
100
+ # pose_pred = None
101
+ filepath = directory + file_names[i]
102
+ # print("filepath:", filepath)
103
+ if file_names[i][-4:] != ".jpg":
104
+ continue
105
+ diver_box, pose_pred = get_pose_estimation(filepath, diver_detector=diver_detector, pose_model=pose_model)
106
+ # pose_pred = data[key]['pose_pred'][i]
107
+ diver_boxes.append(diver_box)
108
+ pose_preds.append(pose_pred)
109
+ # if j < len(pose_preds):
110
+ # print("filepath has pose_pred:", filepath)
111
+ # pose_pred = pose_preds[j]
112
+ # j += 1
113
+ calculated_half_som_count, skip = som_counter(pose_pred, prev_pose_pred=som_prev_pred, half_som_count=half_som_count, handstand=handstand)
114
+ if not skip:
115
+ som_prev_pred = pose_pred
116
+ calculated_petal_count, calculated_in_petal = twist_counter(pose_pred, prev_pose_pred=prev_pred, in_petal=in_petal, petal_count=petal_count)
117
+ im = cv2.imread(filepath)
118
+ plat_output = platform_detector(im)
119
+ plat_outputs.append(plat_output)
120
+ board_end_coord = board_end(plat_output, board_side=board_side)
121
+ board_end_coords.append(board_end_coord)
122
+ # if board_end_coord is None:
123
+ # print("NO BOARD NONE CRYING")
124
+ if above_board and not on_board and board_end_coord is not None and pose_pred is not None and np.array(pose_pred)[0][2][1] > int(board_end_coord[1]):
125
+ above_board=False
126
+ if on_board and detect_on_board(board_end_coord, board_side, pose_pred, handstand) is not None and not detect_on_board(board_end_coord, board_side, pose_pred, handstand):
127
+ on_board = False
128
+ if above_board:
129
+ above_boards.append(1)
130
+ else:
131
+ above_boards.append(0)
132
+ if on_board:
133
+ on_boards.append(1)
134
+ else:
135
+ on_boards.append(0)
136
+ calculated_takeoff = takeoff_microprogram_one_frame(filepath, above_board=above_board, on_board=on_board, pose_pred=pose_pred)
137
+ calculated_twist = twist_microprogram_one_frame(filepath, on_board=on_board, pose_pred=pose_pred, expected_twists=expected_twists, petal_count=petal_count, expected_som=expected_som, half_som_count=half_som_count, diver_detector=diver_detector, pose_model=pose_model)
138
+ calculated_som = somersault_microprogram_one_frame(filepath, pose_pred=pose_pred, on_board=on_board, expected_som=expected_som, half_som_count=half_som_count, expected_twists=expected_twists, petal_count=petal_count, diver_detector=diver_detector, pose_model=pose_model)
139
+ calculated_entry = entry_microprogram_one_frame(filepath, above_board=above_board, on_board=on_board, pose_pred=pose_pred, expected_twists=expected_twists, petal_count=petal_count, expected_som=expected_som, half_som_count=half_som_count, splash_detector=splash_detector, visualize=False, dive_folder_num=dive_folder_num)
140
+ if calculated_som == 1:
141
+ half_som_count = calculated_half_som_count
142
+ elif calculated_twist == 1:
143
+ half_som_count = calculated_half_som_count
144
+ petal_count = calculated_petal_count
145
+ in_petal = calculated_in_petal
146
+ # distance from board
147
+ dist = calculate_distance_from_platform_for_one_frame(filepath, visualize=False, pose_pred=pose_pred, diver_detector=diver_detector, pose_model=pose_model, board_end_coord=board_end_coord, platform_detector=platform_detector) # saves photo to ./output/data/distance_from_board/
148
+ distance_from_board.append(dist)
149
+ position_tightness.append(applyPositionTightnessError(filepath, pose_pred=pose_pred, diver_detector=diver_detector, pose_model=pose_model))
150
+ feet_apart.append(applyFeetApartError(filepath, pose_pred=pose_pred, diver_detector=diver_detector, pose_model=pose_model))
151
+ over_under_rotation.append(over_rotation(filepath, pose_pred=pose_pred, diver_detector=diver_detector, pose_model=pose_model))
152
+ splash_area, splash_pred_mask = get_splash_from_one_frame(filepath, predictor=splash_detector, visualize=False)
153
+ splash.append(splash_area)
154
+ splash_pred_masks.append(splash_pred_mask)
155
+ takeoff.append(calculated_takeoff)
156
+ twist.append(calculated_twist)
157
+ som.append(calculated_som)
158
+ entry.append(calculated_entry)
159
+ som_counts.append(half_som_count)
160
+ twist_counts.append(petal_count)
161
+ prev_pred = pose_pred
162
+
163
+ dive_data['pose_pred'] = pose_preds
164
+ dive_data['takeoff'] = takeoff
165
+ dive_data['twist'] = twist
166
+ dive_data['som'] = som
167
+ dive_data['entry'] = entry
168
+ dive_data['distance_from_board'] = distance_from_board
169
+ dive_data['position_tightness'] = position_tightness
170
+ dive_data['feet_apart'] = feet_apart
171
+ dive_data['over_under_rotation'] = over_under_rotation
172
+ dive_data['splash'] = splash
173
+ dive_data['above_boards'] = above_boards
174
+ dive_data['on_boards'] = on_boards
175
+ dive_data['som_counts'] = som_counts
176
+ dive_data['twist_counts'] = twist_counts
177
+ dive_data['board_end_coords'] = board_end_coords
178
+ dive_data['diver_boxes'] = diver_boxes
179
+ dive_data['splash_pred_masks'] = splash_pred_masks
180
+ dive_data['plat_outputs'] = plat_outputs
181
+ dive_data['board_side'] = board_side
182
+ dive_data['is_handstand'] = handstand
183
+ dive_data['direction'] = expected_direction
184
+
185
+ print("takeoff", takeoff)
186
+ print("twist", twist)
187
+ print("som", som)
188
+ print("entry", entry)
189
+ print("distance_from_board", distance_from_board)
190
+ print("position_tightness", position_tightness)
191
+ print("feet_apart", feet_apart)
192
+ print("over_under_rotation", over_under_rotation)
193
+ print("splash", splash)
194
+ print("above_boards", above_boards)
195
+ print("on_boards", on_boards)
196
+ print("som_counts", som_counts)
197
+ print("twist_counts", twist_counts)
198
+ print("board_end_coords", board_end_coords)
199
+ print("diver_boxes", diver_boxes)
200
+ return dive_data
201
+
tempSegAndAllErrorsForAllFrames_newVids.py ADDED
@@ -0,0 +1,312 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from microprograms.temporal_segmentation.entry import entry_microprogram_one_frame
2
+ from microprograms.temporal_segmentation.somersault import somersault_microprogram_one_frame
3
+ from microprograms.temporal_segmentation.twist import twist_microprogram_one_frame
4
+ from microprograms.temporal_segmentation.start_takeoff import takeoff_microprogram_one_frame
5
+ from microprograms.errors.distance_from_springboard_micro_program import board_end
6
+ from microprograms.errors.splash_micro_program import *
7
+ from microprograms.errors.distance_from_springboard_micro_program import calculate_distance_from_springboard_for_one_frame
8
+ from microprograms.errors.distance_from_springboard_micro_program import calculate_distance_from_platform_for_one_frame
9
+ from microprograms.errors.distance_from_springboard_micro_program import find_which_side_board_on
10
+ from microprograms.errors.angles_micro_programs import applyFeetApartError
11
+ from microprograms.errors.angles_micro_programs import applyPositionTightnessError
12
+ from models.detectron2.platform_detector_setup import get_platform_detector
13
+ from models.pose_estimator.pose_estimator_model_setup import get_pose_estimation
14
+ from models.detectron2.diver_detector_setup import get_diver_detector
15
+ from models.pose_estimator.pose_estimator_model_setup import get_pose_model
16
+ from models.detectron2.splash_detector_setup import get_splash_detector
17
+ from somersault_counter import som_counter, twist_counter
18
+ from microprograms.errors.over_rotation import over_rotation
19
+ from temporal_segmentation import detect_on_board
20
+ from dive_recognition_functions import *
21
+ from scoring_functions import get_scale_factor
22
+ import gradio as gr
23
+ import pickle
24
+ import os
25
+ import math
26
+ import numpy as np
27
+ import cv2
28
+
29
+ with open('segmentation_error_data.pkl', 'rb') as f:
30
+ data = pickle.load(f)
31
+
32
+ def getDiveInfo_from_diveNum(diveNum):
33
+ handstand = (diveNum[0] == '6')
34
+ expected_som = int(diveNum[2])
35
+ if len(diveNum) == 5:
36
+ expected_twists = int(diveNum[3])
37
+ else:
38
+ expected_twists = 0
39
+ if diveNum[0] == '1' or diveNum[0] == '3' or diveNum[:2] == '51' or diveNum[:2] == '53' or diveNum[:2] == '61' or diveNum[:2] == '63':
40
+ back_facing = False
41
+ else:
42
+ back_facing = True
43
+ if diveNum[0] == '1' or diveNum[:2] == '51' or diveNum[:2] == '61':
44
+ expected_direction = 'front'
45
+ elif diveNum[0] == '2' or diveNum[:2] == '52' or diveNum[:2] == '62':
46
+ expected_direction = 'back'
47
+ elif diveNum[0] == '3' or diveNum[:2] == '53' or diveNum[:2] == '63':
48
+ expected_direction = 'reverse'
49
+ elif diveNum[0] == '4':
50
+ expected_direction = 'inward'
51
+ if diveNum[-1] == 'b':
52
+ position = 'pike'
53
+ elif diveNum[-1] == 'c':
54
+ position = 'tuck'
55
+ else:
56
+ position = 'free'
57
+ return handstand, expected_som, expected_twists, back_facing, expected_direction, position
58
+
59
+ def getDiveInfo_from_symbols(frames, dive_data=None, platform_detector=None, splash_detector=None, diver_detector=None, pose_model=None):
60
+ print("Getting dive info from symbols...")
61
+ if dive_data is None:
62
+ print("somethings not getting passed in properly")
63
+ dive_data = abstractSymbols(frames, platform_detector=platform_detector, splash_detector=splash_detector, diver_detector=diver_detector, pose_model=pose_model)
64
+
65
+ # get above_boards, on_boards, and position_tightness
66
+ above_board = True
67
+ on_board = True
68
+ above_boards = []
69
+ on_boards = []
70
+ position_tightness = []
71
+ distances = []
72
+ prev_board_coord = None
73
+ for i in range(len(dive_data['pose_pred'])):
74
+ pose_pred = dive_data['pose_pred'][i]
75
+ board_end_coord = dive_data['board_end_coords'][i]
76
+ if board_end_coord is not None and prev_board_coord is not None:
77
+ distances.append(math.dist(board_end_coord, prev_board_coord))
78
+ if math.dist(board_end_coord, prev_board_coord) > 150:
79
+ position_tightness.append(applyPositionTightnessError(filepath="", pose_pred=pose_pred, diver_detector=diver_detector, pose_model=pose_model))
80
+ if above_board:
81
+ above_boards.append(1)
82
+ else:
83
+ above_boards.append(0)
84
+ if on_board:
85
+ on_boards.append(1)
86
+ else:
87
+ on_boards.append(0)
88
+ continue
89
+ if above_board and not on_board and board_end_coord is not None and pose_pred is not None and np.array(pose_pred)[0][2][1] > int(board_end_coord[1]):
90
+ above_board=False
91
+ if on_board:
92
+ handstand = is_handstand(dive_data)
93
+ calculate_on_board = detect_on_board(board_end_coord, dive_data['board_side'], pose_pred, handstand)
94
+ if calculate_on_board is not None and not calculate_on_board:
95
+ on_board = False
96
+ if above_board:
97
+ above_boards.append(1)
98
+ else:
99
+ above_boards.append(0)
100
+ if on_board:
101
+ on_boards.append(1)
102
+ else:
103
+ on_boards.append(0)
104
+ prev_board_coord = board_end_coord
105
+ position_tightness.append(applyPositionTightnessError(filepath="", pose_pred=pose_pred, diver_detector=diver_detector, pose_model=pose_model))
106
+ dive_data['on_boards'] = on_boards
107
+ dive_data['above_boards'] = above_boards
108
+ dive_data['position_tightness'] = position_tightness
109
+
110
+ ## handstand and som_count##
111
+ expected_som, handstand = som_counter_full_dive(dive_data)
112
+
113
+ ## twist_count
114
+ expected_twists = twist_counter_full_dive(dive_data)
115
+
116
+ ## direction: front, back, reverse, inward
117
+ expected_direction = get_direction(dive_data)
118
+
119
+ return handstand, expected_som, expected_twists, expected_direction, dive_data
120
+
121
+
122
+ def abstractSymbols(frames, progress=gr.Progress(), platform_detector=None, splash_detector=None, diver_detector=None, pose_model=None):
123
+ print("Abstracting symbols...")
124
+ splashes = []
125
+ pose_preds = []
126
+ board_sides = []
127
+ plat_outputs = []
128
+ diver_boxes = []
129
+ splash_pred_masks = []
130
+ if platform_detector is None:
131
+ platform_detector = get_platform_detector()
132
+ if splash_detector is None:
133
+ splash_detector = get_splash_detector()
134
+ if diver_detector is None:
135
+ diver_detector = get_diver_detector()
136
+ if pose_model is None:
137
+ pose_model = get_pose_model()
138
+ num_frames = len(frames)
139
+ i = 0
140
+ for frame in frames:
141
+ progress(i/num_frames, desc="Abstracting Symbols")
142
+ plat_output = platform_detector(frame)
143
+ plat_outputs.append(plat_output)
144
+ board_side = find_which_side_board_on(plat_output)
145
+ if board_side is not None:
146
+ board_sides.append(board_side)
147
+ diver_box, pose_pred = get_pose_estimation(filepath="", image_bgr=frame, diver_detector=diver_detector, pose_model=pose_model)
148
+ pose_preds.append(pose_pred)
149
+ diver_boxes.append(diver_box)
150
+ splash_area, splash_pred_mask = get_splash_from_one_frame(filepath="", im=frame, predictor=splash_detector, visualize=False)
151
+ splash_pred_masks.append(splash_pred_mask)
152
+ splashes.append(splash_area)
153
+ i+=1
154
+ dive_data = {}
155
+ dive_data['plat_outputs'] = plat_outputs
156
+ dive_data['pose_pred'] = pose_preds
157
+ dive_data['splash'] = splashes
158
+ dive_data['splash_pred_masks'] = splash_pred_masks
159
+ dive_data['board_sides'] = board_sides
160
+ board_sides.sort()
161
+ board_side = board_sides[len(board_sides)//2]
162
+ dive_data['board_side'] = board_side
163
+ dive_data['diver_boxes'] = diver_boxes
164
+
165
+ # get board_end_coords
166
+ board_end_coords = []
167
+ for plat_output in dive_data['plat_outputs']:
168
+ board_end_coord = board_end(plat_output, board_side=dive_data['board_side'])
169
+ board_end_coords.append(board_end_coord)
170
+ dive_data['board_end_coords'] = board_end_coords
171
+
172
+ return dive_data
173
+
174
+ def getAllErrorsAndSegmentation_newVids(frames, dive_data, progress=gr.Progress(), diveNum="", board_side=None, platform_detector=None, splash_detector=None, diver_detector=None, pose_model=None):
175
+ print("in getAllErrorsAndSegmentation function...")
176
+ if len(frames) != len(dive_data['pose_pred']):
177
+ raise gr.Error("Abstract Symbols first!")
178
+ if diveNum != "":
179
+ dive_num_given = True
180
+ handstand, expected_som, expected_twists, back_facing, expected_direction, position = getDiveInfo_from_diveNum(diveNum)
181
+ else:
182
+ dive_num_given = False
183
+ handstand, expected_som, expected_twists, expected_direction, dive_data = getDiveInfo_from_symbols(frames, dive_data=dive_data, platform_detector=platform_detector, splash_detector=splash_detector, diver_detector=diver_detector, pose_model=pose_model)
184
+
185
+ if not dive_num_given:
186
+ above_boards = dive_data['above_boards']
187
+ on_boards = dive_data['on_boards']
188
+ position_tightness = dive_data['position_tightness']
189
+ board_end_coords = dive_data['board_end_coords']
190
+ else:
191
+ above_board = True
192
+ on_board = True
193
+ above_boards = []
194
+ on_boards = []
195
+ board_end_coords = []
196
+ position_tightness = []
197
+ splash = dive_data['splash']
198
+ diver_boxes = dive_data['diver_boxes']
199
+ board_side = dive_data['board_side']
200
+ pose_preds = dive_data['pose_pred']
201
+ takeoff = []
202
+ twist = []
203
+ som = []
204
+ entry = []
205
+ distance_from_board = []
206
+ feet_apart = []
207
+ over_under_rotation = []
208
+ som_counts = []
209
+ twist_counts = []
210
+
211
+ if platform_detector is None:
212
+ platform_detector = get_platform_detector()
213
+ if splash_detector is None:
214
+ splash_detector = get_splash_detector()
215
+ if diver_detector is None:
216
+ diver_detector = get_diver_detector()
217
+ if pose_model is None:
218
+ pose_model = get_pose_model()
219
+ j = 0
220
+ prev_pred = None
221
+ som_prev_pred = None
222
+ half_som_count=0
223
+ petal_count = 0
224
+ in_petal = False
225
+ num_frames = len(frames)
226
+ for i in range(num_frames):
227
+ progress(i/num_frames, desc="Calculating Dive Errors")
228
+ pose_pred = pose_preds[i]
229
+ calculated_half_som_count, skip = som_counter(pose_pred, prev_pose_pred=som_prev_pred, half_som_count=half_som_count, handstand=handstand)
230
+ if not skip:
231
+ som_prev_pred = pose_pred
232
+ calculated_petal_count, calculated_in_petal = twist_counter(pose_pred, prev_pose_pred=prev_pred, in_petal=in_petal, petal_count=petal_count)
233
+ if dive_num_given:
234
+ outputs = platform_detector(frames[i])
235
+ board_end_coord = board_end(outputs, board_side=board_side)
236
+ board_end_coords.append(board_end_coord)
237
+ if above_board and not on_board and board_end_coord is not None and pose_pred is not None and np.array(pose_pred)[0][2][1] > int(board_end_coord[1]):
238
+ above_board=False
239
+ if on_board and detect_on_board(board_end_coord, board_side, pose_pred, handstand) is not None and not detect_on_board(board_end_coord, board_side, pose_pred, handstand):
240
+ on_board = False
241
+ if above_board:
242
+ above_boards.append(1)
243
+ else:
244
+ above_boards.append(0)
245
+ if on_board:
246
+ on_boards.append(1)
247
+ else:
248
+ on_boards.append(0)
249
+ else:
250
+ board_end_coord = board_end_coords[i]
251
+ above_board = (above_boards[i] == 1)
252
+ on_board = (on_boards[i] == 1)
253
+ calculated_takeoff = takeoff_microprogram_one_frame(filepath="", above_board=above_board, on_board=on_board, pose_pred=pose_pred)
254
+ calculated_twist = twist_microprogram_one_frame(filepath="", on_board=on_board, pose_pred=pose_pred, expected_twists=expected_twists, petal_count=petal_count, expected_som=expected_som, half_som_count=half_som_count, diver_detector=diver_detector, pose_model=pose_model)
255
+ calculated_som = somersault_microprogram_one_frame(filepath="", pose_pred=pose_pred, on_board=on_board, expected_som=expected_som, half_som_count=half_som_count, expected_twists=expected_twists, petal_count=petal_count, diver_detector=diver_detector, pose_model=pose_model)
256
+ calculated_entry = entry_microprogram_one_frame(filepath="", frame=frames[i], above_board=above_board, on_board=on_board, pose_pred=pose_pred, expected_twists=expected_twists, petal_count=petal_count, expected_som=expected_som, half_som_count=half_som_count, splash_detector=splash_detector, visualize=False)
257
+ if calculated_som == 1:
258
+ half_som_count = calculated_half_som_count
259
+ elif calculated_twist == 1:
260
+ half_som_count = calculated_half_som_count
261
+ petal_count = calculated_petal_count
262
+ in_petal = calculated_in_petal
263
+ # distance from board
264
+ dist = calculate_distance_from_platform_for_one_frame(filepath="", im=frames[i], visualize=False, pose_pred=pose_pred, diver_detector=diver_detector, pose_model=pose_model, board_end_coord=board_end_coord, platform_detector=platform_detector) # saves photo to ./output/data/distance_from_board/
265
+ distance_from_board.append(dist)
266
+ if dive_num_given:
267
+ position_tightness.append(applyPositionTightnessError(filepath="", pose_pred=pose_pred, diver_detector=diver_detector, pose_model=pose_model))
268
+ # splash.append(get_splash_from_one_frame(filepath="", im=frames[i], predictor=splash_detector, visualize=False))
269
+ feet_apart.append(applyFeetApartError(filepath="", pose_pred=pose_pred, diver_detector=diver_detector, pose_model=pose_model))
270
+ over_under_rotation.append(over_rotation(filepath="", pose_pred=pose_pred, diver_detector=diver_detector, pose_model=pose_model))
271
+ takeoff.append(calculated_takeoff)
272
+ twist.append(calculated_twist)
273
+ som.append(calculated_som)
274
+ entry.append(calculated_entry)
275
+ som_counts.append(half_som_count)
276
+ twist_counts.append(petal_count)
277
+ prev_pred = pose_pred
278
+ print("takeoff", takeoff)
279
+ print("twist", twist)
280
+ print("som", som)
281
+ print("entry", entry)
282
+ print("distance_from_board", distance_from_board)
283
+ print("position_tightness", position_tightness)
284
+ print("feet_apart", feet_apart)
285
+ print("over_under_rotation", over_under_rotation)
286
+ print("splash", splash)
287
+ print("above_boards", above_boards)
288
+ print("on_boards", on_boards)
289
+ print("som_counts", som_counts)
290
+ print("twist_counts", twist_counts)
291
+ print("board_end_coords", board_end_coords)
292
+ print("diver_boxes", diver_boxes)
293
+
294
+ print("saving data into dive_data dictionary...")
295
+ dive_data['takeoff'] = takeoff
296
+ dive_data['twist'] = twist
297
+ dive_data['som'] = som
298
+ dive_data['entry'] = entry
299
+ dive_data['distance_from_board'] = distance_from_board
300
+ dive_data['position_tightness'] = position_tightness
301
+ dive_data['feet_apart'] = feet_apart
302
+ dive_data['over_under_rotation'] = over_under_rotation
303
+ dive_data['above_boards'] = above_boards
304
+ dive_data['on_boards'] = on_boards
305
+ dive_data['som_counts'] = som_counts
306
+ dive_data['twist_counts'] = twist_counts
307
+ dive_data['board_end_coords'] = board_end_coords
308
+ dive_data['is_handstand'] = handstand
309
+ dive_data['direction'] = expected_direction
310
+ return dive_data
311
+
312
+