sports2d 0.8.22__tar.gz → 0.8.23__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sports2d-0.8.22 → sports2d-0.8.23}/PKG-INFO +1 -1
- {sports2d-0.8.22 → sports2d-0.8.23}/Sports2D/Demo/Config_demo.toml +4 -2
- {sports2d-0.8.22 → sports2d-0.8.23}/Sports2D/Sports2D.py +1 -1
- {sports2d-0.8.22 → sports2d-0.8.23}/Sports2D/process.py +76 -51
- {sports2d-0.8.22 → sports2d-0.8.23}/sports2d.egg-info/PKG-INFO +1 -1
- {sports2d-0.8.22 → sports2d-0.8.23}/.github/workflows/continuous-integration.yml +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/.github/workflows/joss_pdf.yml +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/.github/workflows/publish-on-release.yml +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/.gitignore +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/CITATION.cff +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/Content/Demo_plots.png +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/Content/Demo_results.png +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/Content/Demo_terminal.png +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/Content/Person_selection.png +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/Content/Video_tuto_Sports2D_Colab.png +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/Content/joint_convention.png +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/Content/paper.bib +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/Content/paper.md +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/Content/sports2d_blender.gif +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/Content/sports2d_opensim.gif +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/LICENSE +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/README.md +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/Sports2D/Demo/Calib_demo.toml +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/Sports2D/Demo/demo.mp4 +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/Sports2D/Sports2D.ipynb +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/Sports2D/Utilities/__init__.py +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/Sports2D/Utilities/common.py +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/Sports2D/Utilities/tests.py +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/Sports2D/__init__.py +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/pyproject.toml +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/setup.cfg +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/sports2d.egg-info/SOURCES.txt +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/sports2d.egg-info/dependency_links.txt +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/sports2d.egg-info/entry_points.txt +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/sports2d.egg-info/requires.txt +0 -0
- {sports2d-0.8.22 → sports2d-0.8.23}/sports2d.egg-info/top_level.txt +0 -0
|
@@ -103,7 +103,7 @@ max_distance = 100 # in px or None # If a person is detected further than max_d
|
|
|
103
103
|
# Pixel to meters conversion
|
|
104
104
|
to_meters = true
|
|
105
105
|
make_c3d = true
|
|
106
|
-
save_calib =
|
|
106
|
+
save_calib = true
|
|
107
107
|
|
|
108
108
|
# If conversion from first_person_height
|
|
109
109
|
floor_angle = 'auto' # 'auto' or a value in degrees, eg 2.3. If 'auto', estimated from the line formed by the toes when they are on the ground (where speed = 0)
|
|
@@ -111,7 +111,9 @@ xy_origin = ['auto'] # ['auto'] or [px_x,px_y]. N.B.: px_y points downwards.
|
|
|
111
111
|
|
|
112
112
|
# If conversion from a calibration file
|
|
113
113
|
calib_file = '' # Calibration in the Pose2Sim format. 'calib_demo.toml', or '' if not available
|
|
114
|
-
|
|
114
|
+
# subject_distance
|
|
115
|
+
# focal_distance
|
|
116
|
+
# recalculate_extrinsics
|
|
115
117
|
|
|
116
118
|
[angles]
|
|
117
119
|
display_angle_values_on = ['body', 'list'] # 'body', 'list', ['body', 'list'], 'none'. Display angle values on the body, as a list in the upper left of the image, both, or do not display them.
|
|
@@ -197,7 +197,7 @@ DEFAULT_CONFIG = {'base': {'video_input': ['demo.mp4'],
|
|
|
197
197
|
'calib_file': '',
|
|
198
198
|
'floor_angle': 'auto',
|
|
199
199
|
'xy_origin': ['auto'],
|
|
200
|
-
'save_calib':
|
|
200
|
+
'save_calib': True
|
|
201
201
|
},
|
|
202
202
|
'angles': {'display_angle_values_on': ['body', 'list'],
|
|
203
203
|
'fontSize': 0.3,
|
|
@@ -78,11 +78,11 @@ from matplotlib import patheffects
|
|
|
78
78
|
|
|
79
79
|
from rtmlib import PoseTracker, BodyWithFeet, Wholebody, Body, Hand, Custom
|
|
80
80
|
from rtmlib.tools.object_detection.post_processings import nms
|
|
81
|
-
from deep_sort_realtime.deepsort_tracker import DeepSort
|
|
82
81
|
|
|
83
82
|
from Sports2D.Utilities.common import *
|
|
84
83
|
from Pose2Sim.common import *
|
|
85
84
|
from Pose2Sim.skeletons import *
|
|
85
|
+
from Pose2Sim.calibration import toml_write
|
|
86
86
|
from Pose2Sim.triangulation import indices_of_first_last_non_nan_chunks
|
|
87
87
|
from Pose2Sim.personAssociation import *
|
|
88
88
|
from Pose2Sim.filtering import *
|
|
@@ -1458,6 +1458,7 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir):
|
|
|
1458
1458
|
tracking_mode = config_dict.get('pose').get('tracking_mode')
|
|
1459
1459
|
max_distance = config_dict.get('pose').get('max_distance', None)
|
|
1460
1460
|
if tracking_mode == 'deepsort':
|
|
1461
|
+
from deep_sort_realtime.deepsort_tracker import DeepSort
|
|
1461
1462
|
deepsort_params = config_dict.get('pose').get('deepsort_params')
|
|
1462
1463
|
try:
|
|
1463
1464
|
deepsort_params = ast.literal_eval(deepsort_params)
|
|
@@ -1476,8 +1477,12 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir):
|
|
|
1476
1477
|
save_calib = config_dict.get('px_to_meters_conversion').get('save_calib')
|
|
1477
1478
|
# Calibration from file
|
|
1478
1479
|
calib_file = config_dict.get('px_to_meters_conversion').get('calib_file')
|
|
1479
|
-
if calib_file == '':
|
|
1480
|
-
|
|
1480
|
+
if calib_file == '':
|
|
1481
|
+
calib_file = None
|
|
1482
|
+
else:
|
|
1483
|
+
calib_file = video_dir / calib_file
|
|
1484
|
+
if not calib_file.is_file():
|
|
1485
|
+
raise FileNotFoundError(f'Error: Could not find calibration file {calib_file}. Check that the file exists.')
|
|
1481
1486
|
# Calibration from person height
|
|
1482
1487
|
floor_angle = config_dict.get('px_to_meters_conversion').get('floor_angle') # 'auto' or float
|
|
1483
1488
|
floor_angle = np.radians(float(floor_angle)) if floor_angle != 'auto' else floor_angle
|
|
@@ -2107,16 +2112,47 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir):
|
|
|
2107
2112
|
trc_data_m = []
|
|
2108
2113
|
if to_meters and save_pose:
|
|
2109
2114
|
logging.info('\nConverting pose to meters:')
|
|
2115
|
+
|
|
2116
|
+
# Compute height in px of the first person
|
|
2117
|
+
height_px = compute_height(trc_data[0].iloc[:,1:], new_keypoints_names,
|
|
2118
|
+
fastest_frames_to_remove_percent=fastest_frames_to_remove_percent, close_to_zero_speed=close_to_zero_speed_px, large_hip_knee_angles=large_hip_knee_angles, trimmed_extrema_percent=trimmed_extrema_percent)
|
|
2119
|
+
|
|
2120
|
+
if calib_file or save_calib:
|
|
2121
|
+
dist_to_cam = 10.0 # arbitrary distance between the camera and the person (m)
|
|
2122
|
+
R90z = np.array([[0.0, -1.0, 0.0],
|
|
2123
|
+
[1.0, 0.0, 0.0],
|
|
2124
|
+
[0.0, 0.0, 1.0]])
|
|
2125
|
+
R270x = np.array([[1.0, 0.0, 0.0],
|
|
2126
|
+
[0.0, 0.0, 1.0],
|
|
2127
|
+
[0.0, -1.0, 0.0]])
|
|
2128
|
+
|
|
2129
|
+
# Compute px to meter parameters from calibration file
|
|
2110
2130
|
if calib_file:
|
|
2111
|
-
logging.info(f'Using calibration file to convert coordinates in meters: {calib_file}.')
|
|
2112
2131
|
calib_params_dict = retrieve_calib_params(calib_file)
|
|
2113
|
-
# TODO
|
|
2114
2132
|
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
height_px = compute_height(trc_data[0].iloc[:,1:], new_keypoints_names,
|
|
2118
|
-
fastest_frames_to_remove_percent=fastest_frames_to_remove_percent, close_to_zero_speed=close_to_zero_speed_px, large_hip_knee_angles=large_hip_knee_angles, trimmed_extrema_percent=trimmed_extrema_percent)
|
|
2133
|
+
f = calib_params_dict['K'][0][0][0]
|
|
2134
|
+
first_person_height = height_px / f * dist_to_cam
|
|
2119
2135
|
|
|
2136
|
+
R_cam = cv2.Rodrigues(calib_params_dict['R'][0])[0]
|
|
2137
|
+
T_cam = np.array(calib_params_dict['T'][0])
|
|
2138
|
+
R_world, T_world = world_to_camera_persp(R_cam, T_cam)
|
|
2139
|
+
Rfloory = R90z.T @ R_world @ R270x.T
|
|
2140
|
+
T_world = R90z.T @ T_world
|
|
2141
|
+
floor_angle_estim = np.arctan2(Rfloory[0,2], Rfloory[0,0])
|
|
2142
|
+
|
|
2143
|
+
cu = calib_params_dict['K'][0][0][2]
|
|
2144
|
+
cv = calib_params_dict['K'][0][1][2]
|
|
2145
|
+
cx = 0.0
|
|
2146
|
+
cy = cv + T_world[2]*f/dist_to_cam
|
|
2147
|
+
xy_origin_estim = [cx, cy]
|
|
2148
|
+
|
|
2149
|
+
logging.info(f'Using calibration file to convert coordinates in meters: {calib_file}.\n'
|
|
2150
|
+
f'Floor angle: {np.degrees(floor_angle_estim):.2f}°, '
|
|
2151
|
+
f'xy_origin: [{cx:.2f}, {cy:.2f}] px.')
|
|
2152
|
+
|
|
2153
|
+
|
|
2154
|
+
# Compute px to meter parameters from scene
|
|
2155
|
+
else:
|
|
2120
2156
|
toe_speed_below = 1 # m/s (below which the foot is considered to be stationary)
|
|
2121
2157
|
px_per_m = height_px/first_person_height
|
|
2122
2158
|
toe_speed_below_px_frame = toe_speed_below * px_per_m / fps
|
|
@@ -2142,6 +2178,37 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir):
|
|
|
2142
2178
|
logging.info(f'Using height of person #0 ({first_person_height}m) to convert coordinates in meters.\n'
|
|
2143
2179
|
f'Floor angle: {np.degrees(floor_angle_estim) if not floor_angle=="auto" else f"auto (estimation: {round(np.degrees(floor_angle_estim),2)}°)"}, '
|
|
2144
2180
|
f'xy_origin: {xy_origin if not xy_origin=="auto" else f"auto (estimation: {[round(c) for c in xy_origin_estim]})"} px.')
|
|
2181
|
+
|
|
2182
|
+
# Save calibration file
|
|
2183
|
+
if save_calib:
|
|
2184
|
+
calib_file_path = output_dir / f'{video_file_stem}_Sports2D_calib.toml'
|
|
2185
|
+
|
|
2186
|
+
# name, size, distortions
|
|
2187
|
+
N = [video_file_stem]
|
|
2188
|
+
S = [[cam_width, cam_height]]
|
|
2189
|
+
D = [[0.0, 0.0, 0.0, 0.0]]
|
|
2190
|
+
|
|
2191
|
+
# Intrinsics
|
|
2192
|
+
f = height_px / first_person_height * dist_to_cam
|
|
2193
|
+
cu = cam_width/2
|
|
2194
|
+
cv = cam_height/2
|
|
2195
|
+
K = np.array([[[f, 0.0, cu], [0.0, f, cv], [0.0, 0.0, 1.0]]])
|
|
2196
|
+
|
|
2197
|
+
# Extrinsics
|
|
2198
|
+
Rfloory = np.array([[np.cos(floor_angle_estim), 0.0, np.sin(floor_angle_estim)],
|
|
2199
|
+
[0.0, 1.0, 0.0],
|
|
2200
|
+
[-np.sin(floor_angle_estim), 0.0, np.cos(floor_angle_estim)]])
|
|
2201
|
+
R_world = R90z @ Rfloory @ R270x
|
|
2202
|
+
T_world = R90z @ np.array([-(cx-cu)/f*dist_to_cam, -dist_to_cam, (cy-cv)/f*dist_to_cam])
|
|
2203
|
+
|
|
2204
|
+
R_cam, T_cam = world_to_camera_persp(R_world, T_world)
|
|
2205
|
+
Tvec_cam = T_cam.reshape(1,3).tolist()
|
|
2206
|
+
Rvec_cam = cv2.Rodrigues(R_cam)[0].reshape(1,3).tolist()
|
|
2207
|
+
|
|
2208
|
+
# Write calibration file
|
|
2209
|
+
toml_write(calib_file_path, N, S, D, K, Rvec_cam, Tvec_cam)
|
|
2210
|
+
logging.info(f'Calibration saved to {calib_file_path}.')
|
|
2211
|
+
|
|
2145
2212
|
|
|
2146
2213
|
# Coordinates in m
|
|
2147
2214
|
new_visible_side = []
|
|
@@ -2206,48 +2273,6 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir):
|
|
|
2206
2273
|
new_visible_side += [visible_side_i]
|
|
2207
2274
|
else:
|
|
2208
2275
|
new_visible_side = visible_side.copy()
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
# # plt.plot(trc_data_m.iloc[:,0], trc_data_m.iloc[:,1])
|
|
2216
|
-
# # plt.ylim([0,2])
|
|
2217
|
-
# # plt.show()
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
# z = 3.0 # distance between the camera and the person. Required in the calibration file but simplified in the equations
|
|
2222
|
-
# f = height_px / first_person_height * z
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
# # Name
|
|
2226
|
-
# N = [video_file]
|
|
2227
|
-
|
|
2228
|
-
# # Size
|
|
2229
|
-
# S = [[cam_width, cam_height]]
|
|
2230
|
-
|
|
2231
|
-
# # Distortions
|
|
2232
|
-
# D = [[0.0, 0.0, 0.0, 0.0]]
|
|
2233
|
-
|
|
2234
|
-
# # Camera matrix
|
|
2235
|
-
# K = [[[f, 0.0, cx], [0.0, f, cy], [0.0, 0.0, 1.0]]] # f and Z do not matter in 2D
|
|
2236
|
-
|
|
2237
|
-
# # Rot, Trans
|
|
2238
|
-
# R =
|
|
2239
|
-
# T =
|
|
2240
|
-
|
|
2241
|
-
# # Save calibration file
|
|
2242
|
-
|
|
2243
|
-
# # Convert to meters
|
|
2244
|
-
# trc_data =
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
2276
|
|
|
2252
2277
|
|
|
2253
2278
|
#%% ==================================================
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|