sports2d 0.8.22__tar.gz → 0.8.24__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.
Files changed (37) hide show
  1. {sports2d-0.8.22 → sports2d-0.8.24}/PKG-INFO +4 -17
  2. {sports2d-0.8.22 → sports2d-0.8.24}/README.md +3 -1
  3. {sports2d-0.8.22 → sports2d-0.8.24}/Sports2D/Demo/Config_demo.toml +4 -2
  4. {sports2d-0.8.22 → sports2d-0.8.24}/Sports2D/Sports2D.py +1 -1
  5. {sports2d-0.8.22 → sports2d-0.8.24}/Sports2D/process.py +76 -51
  6. {sports2d-0.8.22 → sports2d-0.8.24}/pyproject.toml +0 -15
  7. {sports2d-0.8.22 → sports2d-0.8.24}/sports2d.egg-info/PKG-INFO +4 -17
  8. sports2d-0.8.24/sports2d.egg-info/requires.txt +2 -0
  9. sports2d-0.8.22/sports2d.egg-info/requires.txt +0 -17
  10. {sports2d-0.8.22 → sports2d-0.8.24}/.github/workflows/continuous-integration.yml +0 -0
  11. {sports2d-0.8.22 → sports2d-0.8.24}/.github/workflows/joss_pdf.yml +0 -0
  12. {sports2d-0.8.22 → sports2d-0.8.24}/.github/workflows/publish-on-release.yml +0 -0
  13. {sports2d-0.8.22 → sports2d-0.8.24}/.gitignore +0 -0
  14. {sports2d-0.8.22 → sports2d-0.8.24}/CITATION.cff +0 -0
  15. {sports2d-0.8.22 → sports2d-0.8.24}/Content/Demo_plots.png +0 -0
  16. {sports2d-0.8.22 → sports2d-0.8.24}/Content/Demo_results.png +0 -0
  17. {sports2d-0.8.22 → sports2d-0.8.24}/Content/Demo_terminal.png +0 -0
  18. {sports2d-0.8.22 → sports2d-0.8.24}/Content/Person_selection.png +0 -0
  19. {sports2d-0.8.22 → sports2d-0.8.24}/Content/Video_tuto_Sports2D_Colab.png +0 -0
  20. {sports2d-0.8.22 → sports2d-0.8.24}/Content/joint_convention.png +0 -0
  21. {sports2d-0.8.22 → sports2d-0.8.24}/Content/paper.bib +0 -0
  22. {sports2d-0.8.22 → sports2d-0.8.24}/Content/paper.md +0 -0
  23. {sports2d-0.8.22 → sports2d-0.8.24}/Content/sports2d_blender.gif +0 -0
  24. {sports2d-0.8.22 → sports2d-0.8.24}/Content/sports2d_opensim.gif +0 -0
  25. {sports2d-0.8.22 → sports2d-0.8.24}/LICENSE +0 -0
  26. {sports2d-0.8.22 → sports2d-0.8.24}/Sports2D/Demo/Calib_demo.toml +0 -0
  27. {sports2d-0.8.22 → sports2d-0.8.24}/Sports2D/Demo/demo.mp4 +0 -0
  28. {sports2d-0.8.22 → sports2d-0.8.24}/Sports2D/Sports2D.ipynb +0 -0
  29. {sports2d-0.8.22 → sports2d-0.8.24}/Sports2D/Utilities/__init__.py +0 -0
  30. {sports2d-0.8.22 → sports2d-0.8.24}/Sports2D/Utilities/common.py +0 -0
  31. {sports2d-0.8.22 → sports2d-0.8.24}/Sports2D/Utilities/tests.py +0 -0
  32. {sports2d-0.8.22 → sports2d-0.8.24}/Sports2D/__init__.py +0 -0
  33. {sports2d-0.8.22 → sports2d-0.8.24}/setup.cfg +0 -0
  34. {sports2d-0.8.22 → sports2d-0.8.24}/sports2d.egg-info/SOURCES.txt +0 -0
  35. {sports2d-0.8.22 → sports2d-0.8.24}/sports2d.egg-info/dependency_links.txt +0 -0
  36. {sports2d-0.8.22 → sports2d-0.8.24}/sports2d.egg-info/entry_points.txt +0 -0
  37. {sports2d-0.8.22 → sports2d-0.8.24}/sports2d.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sports2d
3
- Version: 0.8.22
3
+ Version: 0.8.24
4
4
  Summary: Compute 2D human pose and angles from a video or a webcam.
5
5
  Author-email: David Pagnon <contact@david-pagnon.com>
6
6
  Maintainer-email: David Pagnon <contact@david-pagnon.com>
@@ -22,22 +22,7 @@ Classifier: Topic :: Multimedia :: Graphics :: 3D Modeling
22
22
  Requires-Python: >=3.9
23
23
  Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
- Requires-Dist: toml
26
- Requires-Dist: numpy>=1.19
27
- Requires-Dist: matplotlib
28
- Requires-Dist: PyQt5
29
- Requires-Dist: tqdm
30
- Requires-Dist: anytree
31
- Requires-Dist: pandas>=1.5
32
- Requires-Dist: scipy
33
- Requires-Dist: statsmodels
34
- Requires-Dist: ipython
35
- Requires-Dist: c3d
36
- Requires-Dist: rtmlib
37
- Requires-Dist: openvino
38
- Requires-Dist: opencv-python<4.12
39
25
  Requires-Dist: imageio_ffmpeg
40
- Requires-Dist: deep-sort-realtime
41
26
  Requires-Dist: Pose2Sim>=0.10.38
42
27
  Dynamic: license-file
43
28
 
@@ -88,7 +73,9 @@ Works on any smartphone!**\
88
73
  </br>
89
74
 
90
75
 
91
- https://github.com/user-attachments/assets/6a444474-4df1-4134-af0c-e9746fa433ad
76
+ https://github.com/user-attachments/assets/2ce62012-f28c-4e23-b3b8-f68931bacb77
77
+
78
+ <!-- https://github.com/user-attachments/assets/6a444474-4df1-4134-af0c-e9746fa433ad -->
92
79
 
93
80
  <!-- https://github.com/user-attachments/assets/1c6e2d6b-d0cf-4165-864e-d9f01c0b8a0e -->
94
81
 
@@ -45,7 +45,9 @@ Works on any smartphone!**\
45
45
  </br>
46
46
 
47
47
 
48
- https://github.com/user-attachments/assets/6a444474-4df1-4134-af0c-e9746fa433ad
48
+ https://github.com/user-attachments/assets/2ce62012-f28c-4e23-b3b8-f68931bacb77
49
+
50
+ <!-- https://github.com/user-attachments/assets/6a444474-4df1-4134-af0c-e9746fa433ad -->
49
51
 
50
52
  <!-- https://github.com/user-attachments/assets/1c6e2d6b-d0cf-4165-864e-d9f01c0b8a0e -->
51
53
 
@@ -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 = false
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': False
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 == '': calib_file = None
1480
- else: calib_file = Path(calib_file).resolve()
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
- else:
2116
- # Compute calibration parameters
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
  #%% ==================================================
@@ -33,22 +33,7 @@ classifiers = [
33
33
  ]
34
34
  urls = {Homepage = "https://github.com/davidpagnon/Sports2D", "Bug Tracker" = "https://github.com/davidpagnon/Sports2D/issues"}
35
35
  dependencies = [
36
- "toml",
37
- "numpy>=1.19",
38
- "matplotlib",
39
- "PyQt5",
40
- "tqdm",
41
- "anytree",
42
- "pandas>=1.5",
43
- "scipy",
44
- "statsmodels",
45
- "ipython",
46
- "c3d",
47
- "rtmlib",
48
- "openvino",
49
- "opencv-python<4.12", # otherwise forces numpy>=2.0, which is incompatible with some opensim/python combinations
50
36
  "imageio_ffmpeg",
51
- "deep-sort-realtime",
52
37
  "Pose2Sim>=0.10.38"
53
38
  ]
54
39
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sports2d
3
- Version: 0.8.22
3
+ Version: 0.8.24
4
4
  Summary: Compute 2D human pose and angles from a video or a webcam.
5
5
  Author-email: David Pagnon <contact@david-pagnon.com>
6
6
  Maintainer-email: David Pagnon <contact@david-pagnon.com>
@@ -22,22 +22,7 @@ Classifier: Topic :: Multimedia :: Graphics :: 3D Modeling
22
22
  Requires-Python: >=3.9
23
23
  Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
- Requires-Dist: toml
26
- Requires-Dist: numpy>=1.19
27
- Requires-Dist: matplotlib
28
- Requires-Dist: PyQt5
29
- Requires-Dist: tqdm
30
- Requires-Dist: anytree
31
- Requires-Dist: pandas>=1.5
32
- Requires-Dist: scipy
33
- Requires-Dist: statsmodels
34
- Requires-Dist: ipython
35
- Requires-Dist: c3d
36
- Requires-Dist: rtmlib
37
- Requires-Dist: openvino
38
- Requires-Dist: opencv-python<4.12
39
25
  Requires-Dist: imageio_ffmpeg
40
- Requires-Dist: deep-sort-realtime
41
26
  Requires-Dist: Pose2Sim>=0.10.38
42
27
  Dynamic: license-file
43
28
 
@@ -88,7 +73,9 @@ Works on any smartphone!**\
88
73
  </br>
89
74
 
90
75
 
91
- https://github.com/user-attachments/assets/6a444474-4df1-4134-af0c-e9746fa433ad
76
+ https://github.com/user-attachments/assets/2ce62012-f28c-4e23-b3b8-f68931bacb77
77
+
78
+ <!-- https://github.com/user-attachments/assets/6a444474-4df1-4134-af0c-e9746fa433ad -->
92
79
 
93
80
  <!-- https://github.com/user-attachments/assets/1c6e2d6b-d0cf-4165-864e-d9f01c0b8a0e -->
94
81
 
@@ -0,0 +1,2 @@
1
+ imageio_ffmpeg
2
+ Pose2Sim>=0.10.38
@@ -1,17 +0,0 @@
1
- toml
2
- numpy>=1.19
3
- matplotlib
4
- PyQt5
5
- tqdm
6
- anytree
7
- pandas>=1.5
8
- scipy
9
- statsmodels
10
- ipython
11
- c3d
12
- rtmlib
13
- openvino
14
- opencv-python<4.12
15
- imageio_ffmpeg
16
- deep-sort-realtime
17
- Pose2Sim>=0.10.38
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes