sports2d 0.8.11__tar.gz → 0.8.13__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 (36) hide show
  1. {sports2d-0.8.11 → sports2d-0.8.13}/PKG-INFO +1 -1
  2. {sports2d-0.8.11 → sports2d-0.8.13}/Sports2D/process.py +49 -24
  3. {sports2d-0.8.11 → sports2d-0.8.13}/sports2d.egg-info/PKG-INFO +1 -1
  4. {sports2d-0.8.11 → sports2d-0.8.13}/.github/workflows/continuous-integration.yml +0 -0
  5. {sports2d-0.8.11 → sports2d-0.8.13}/.github/workflows/joss_pdf.yml +0 -0
  6. {sports2d-0.8.11 → sports2d-0.8.13}/.github/workflows/publish-on-release.yml +0 -0
  7. {sports2d-0.8.11 → sports2d-0.8.13}/.gitignore +0 -0
  8. {sports2d-0.8.11 → sports2d-0.8.13}/CITATION.cff +0 -0
  9. {sports2d-0.8.11 → sports2d-0.8.13}/Content/Demo_plots.png +0 -0
  10. {sports2d-0.8.11 → sports2d-0.8.13}/Content/Demo_results.png +0 -0
  11. {sports2d-0.8.11 → sports2d-0.8.13}/Content/Demo_terminal.png +0 -0
  12. {sports2d-0.8.11 → sports2d-0.8.13}/Content/Person_selection.png +0 -0
  13. {sports2d-0.8.11 → sports2d-0.8.13}/Content/Video_tuto_Sports2D_Colab.png +0 -0
  14. {sports2d-0.8.11 → sports2d-0.8.13}/Content/joint_convention.png +0 -0
  15. {sports2d-0.8.11 → sports2d-0.8.13}/Content/paper.bib +0 -0
  16. {sports2d-0.8.11 → sports2d-0.8.13}/Content/paper.md +0 -0
  17. {sports2d-0.8.11 → sports2d-0.8.13}/Content/sports2d_blender.gif +0 -0
  18. {sports2d-0.8.11 → sports2d-0.8.13}/Content/sports2d_opensim.gif +0 -0
  19. {sports2d-0.8.11 → sports2d-0.8.13}/LICENSE +0 -0
  20. {sports2d-0.8.11 → sports2d-0.8.13}/README.md +0 -0
  21. {sports2d-0.8.11 → sports2d-0.8.13}/Sports2D/Demo/Config_demo.toml +0 -0
  22. {sports2d-0.8.11 → sports2d-0.8.13}/Sports2D/Demo/demo.mp4 +0 -0
  23. {sports2d-0.8.11 → sports2d-0.8.13}/Sports2D/Sports2D.ipynb +0 -0
  24. {sports2d-0.8.11 → sports2d-0.8.13}/Sports2D/Sports2D.py +0 -0
  25. {sports2d-0.8.11 → sports2d-0.8.13}/Sports2D/Utilities/__init__.py +0 -0
  26. {sports2d-0.8.11 → sports2d-0.8.13}/Sports2D/Utilities/common.py +0 -0
  27. {sports2d-0.8.11 → sports2d-0.8.13}/Sports2D/Utilities/filter.py +0 -0
  28. {sports2d-0.8.11 → sports2d-0.8.13}/Sports2D/Utilities/tests.py +0 -0
  29. {sports2d-0.8.11 → sports2d-0.8.13}/Sports2D/__init__.py +0 -0
  30. {sports2d-0.8.11 → sports2d-0.8.13}/pyproject.toml +0 -0
  31. {sports2d-0.8.11 → sports2d-0.8.13}/setup.cfg +0 -0
  32. {sports2d-0.8.11 → sports2d-0.8.13}/sports2d.egg-info/SOURCES.txt +0 -0
  33. {sports2d-0.8.11 → sports2d-0.8.13}/sports2d.egg-info/dependency_links.txt +0 -0
  34. {sports2d-0.8.11 → sports2d-0.8.13}/sports2d.egg-info/entry_points.txt +0 -0
  35. {sports2d-0.8.11 → sports2d-0.8.13}/sports2d.egg-info/requires.txt +0 -0
  36. {sports2d-0.8.11 → sports2d-0.8.13}/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.11
3
+ Version: 0.8.13
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>
@@ -83,6 +83,7 @@ from Sports2D.Utilities import filter
83
83
  from Sports2D.Utilities.common import *
84
84
  from Pose2Sim.common import *
85
85
  from Pose2Sim.skeletons import *
86
+ from Pose2Sim.triangulation import indices_of_first_last_non_nan_chunks
86
87
 
87
88
  DEFAULT_MASS = 70
88
89
  DEFAULT_HEIGHT = 1.7
@@ -495,24 +496,25 @@ def draw_angles(img, valid_X, valid_Y, valid_angles, valid_X_flipped, keypoints_
495
496
  right_angle = True if ang_params[2]==90 else False
496
497
 
497
498
  # Draw angle
498
- if len(ang_coords) == 2: # segment angle
499
- app_point, vec = draw_segment_angle(img, ang_coords, flip)
500
- else: # joint angle
501
- app_point, vec1, vec2 = draw_joint_angle(img, ang_coords, flip, right_angle)
502
-
503
- # Write angle on body
504
- if 'body' in display_angle_values_on:
499
+ if not np.any(np.isnan(ang_coords)):
505
500
  if len(ang_coords) == 2: # segment angle
506
- write_angle_on_body(img, ang, app_point, vec, np.array([1,0]), dist=20, color=(255,255,255), fontSize=fontSize, thickness=thickness)
501
+ app_point, vec = draw_segment_angle(img, ang_coords, flip)
507
502
  else: # joint angle
508
- write_angle_on_body(img, ang, app_point, vec1, vec2, dist=40, color=(0,255,0), fontSize=fontSize, thickness=thickness)
509
-
510
- # Write angle as a list on image with progress bar
511
- if 'list' in display_angle_values_on:
512
- if len(ang_coords) == 2: # segment angle
513
- ang_label_line = write_angle_as_list(img, ang, ang_name, person_label_position, ang_label_line, color = (255,255,255), fontSize=fontSize, thickness=thickness)
514
- else:
515
- ang_label_line = write_angle_as_list(img, ang, ang_name, person_label_position, ang_label_line, color = (0,255,0), fontSize=fontSize, thickness=thickness)
503
+ app_point, vec1, vec2 = draw_joint_angle(img, ang_coords, flip, right_angle)
504
+
505
+ # Write angle on body
506
+ if 'body' in display_angle_values_on:
507
+ if len(ang_coords) == 2: # segment angle
508
+ write_angle_on_body(img, ang, app_point, vec, np.array([1,0]), dist=20, color=(255,255,255), fontSize=fontSize, thickness=thickness)
509
+ else: # joint angle
510
+ write_angle_on_body(img, ang, app_point, vec1, vec2, dist=40, color=(0,255,0), fontSize=fontSize, thickness=thickness)
511
+
512
+ # Write angle as a list on image with progress bar
513
+ if 'list' in display_angle_values_on:
514
+ if len(ang_coords) == 2: # segment angle
515
+ ang_label_line = write_angle_as_list(img, ang, ang_name, person_label_position, ang_label_line, color = (255,255,255), fontSize=fontSize, thickness=thickness)
516
+ else:
517
+ ang_label_line = write_angle_as_list(img, ang, ang_name, person_label_position, ang_label_line, color = (0,255,0), fontSize=fontSize, thickness=thickness)
516
518
 
517
519
  return img
518
520
 
@@ -789,14 +791,15 @@ def pose_plots(trc_data_unfiltered, trc_data, person_id):
789
791
  OUTPUT:
790
792
  - matplotlib window with tabbed figures for each keypoint
791
793
  '''
792
- os_name = platform.system()
793
794
 
795
+ os_name = platform.system()
794
796
  if os_name == 'Windows':
795
797
  mpl.use('qt5agg') # windows
798
+
796
799
  mpl.rc('figure', max_open_warning=0)
797
800
 
798
801
  keypoints_names = trc_data.columns[1::3]
799
-
802
+
800
803
  pw = plotWindow()
801
804
  pw.MainWindow.setWindowTitle('Person'+ str(person_id) + ' coordinates') # Main title
802
805
 
@@ -838,16 +841,22 @@ def angle_plots(angle_data_unfiltered, angle_data, person_id):
838
841
  - matplotlib window with tabbed figures for each angle
839
842
  '''
840
843
 
841
- mpl.use('qt5agg')
844
+ os_name = platform.system()
845
+ if os_name == 'Windows':
846
+ mpl.use('qt5agg') # windows
842
847
  mpl.rc('figure', max_open_warning=0)
843
848
 
844
849
  angles_names = angle_data.columns[1:]
845
-
850
+
846
851
  pw = plotWindow()
847
852
  pw.MainWindow.setWindowTitle('Person'+ str(person_id) + ' angles') # Main title
848
853
 
849
854
  for id, angle in enumerate(angles_names):
850
855
  f = plt.figure()
856
+ if os_name == 'Windows':
857
+ f.canvas.manager.window.setWindowTitle(angle + ' Plot') # windows
858
+ elif os_name == 'Darwin': # macOS
859
+ f.canvas.manager.set_window_title(angle + ' Plot') # mac
851
860
 
852
861
  ax = plt.subplot(111)
853
862
  plt.plot(angle_data_unfiltered.iloc[:,0], angle_data_unfiltered.iloc[:,id+1], label='unfiltered')
@@ -1817,9 +1826,15 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir):
1817
1826
  logging.info(f'- Person {i}: Interpolating missing sequences if they are smaller than {interp_gap_smaller_than} frames. Large gaps filled with {fill_large_gaps_with}.')
1818
1827
  all_frames_X_person_interp = all_frames_X_person.apply(interpolate_zeros_nans, axis=0, args = [interp_gap_smaller_than, 'linear'])
1819
1828
  all_frames_Y_person_interp = all_frames_Y_person.apply(interpolate_zeros_nans, axis=0, args = [interp_gap_smaller_than, 'linear'])
1829
+
1820
1830
  if fill_large_gaps_with.lower() == 'last_value':
1821
- all_frames_X_person_interp = all_frames_X_person_interp.ffill(axis=0).bfill(axis=0)
1822
- all_frames_Y_person_interp = all_frames_Y_person_interp.ffill(axis=0).bfill(axis=0)
1831
+ for col in all_frames_X_person_interp.columns:
1832
+ first_run_start, last_run_end = indices_of_first_last_non_nan_chunks(all_frames_Y_person_interp[col])
1833
+ for coord_df in [all_frames_X_person_interp, all_frames_Y_person_interp, all_frames_Z_homog]:
1834
+ coord_df.loc[:first_run_start, col] = np.nan
1835
+ coord_df.loc[last_run_end:, col] = np.nan
1836
+ coord_df.loc[first_run_start:last_run_end, col] = coord_df.loc[first_run_start:last_run_end, col].ffill().bfill()
1837
+
1823
1838
  elif fill_large_gaps_with.lower() == 'zeros':
1824
1839
  all_frames_X_person_interp.replace(np.nan, 0, inplace=True)
1825
1840
  all_frames_Y_person_interp.replace(np.nan, 0, inplace=True)
@@ -1941,7 +1956,13 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir):
1941
1956
  # Convert to meters
1942
1957
  px_to_m_i = [convert_px_to_meters(trc_data[i][kpt_name], first_person_height, height_px, cx, cy, -floor_angle_estim, visible_side=visible_side_i) for kpt_name in new_keypoints_names]
1943
1958
  trc_data_m_i = pd.concat([all_frames_time.rename('time')]+px_to_m_i, axis=1)
1944
- trc_data_m_i = trc_data_m_i.ffill(axis=0).bfill(axis=0)
1959
+ for c in 3*np.arange(len(trc_data_m_i.columns[3::3]))+1: # only X coordinates
1960
+ first_run_start, last_run_end = indices_of_first_last_non_nan_chunks(trc_data_m_i.iloc[:,c])
1961
+ trc_data_m_i.iloc[:first_run_start,c+2] = np.nan
1962
+ trc_data_m_i.iloc[last_run_end:,c+2] = np.nan
1963
+ trc_data_m_i.iloc[first_run_start:last_run_end,c+2] = trc_data_m_i.iloc[first_run_start:last_run_end,c+2].ffill().bfill()
1964
+ first_trim, last_trim = trc_data_m_i.isnull().any(axis=1).idxmin(), trc_data_m_i[::-1].isnull().any(axis=1).idxmin()
1965
+ trc_data_m_i = trc_data_m_i.iloc[first_trim:last_trim+1,:]
1945
1966
  px_to_m_unfiltered_i = [convert_px_to_meters(trc_data_unfiltered[i][kpt_name], first_person_height, height_px, cx, cy, -floor_angle_estim) for kpt_name in new_keypoints_names]
1946
1967
  trc_data_unfiltered_m_i = pd.concat([all_frames_time.rename('time')]+px_to_m_unfiltered_i, axis=1)
1947
1968
 
@@ -2033,7 +2054,11 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir):
2033
2054
  logging.info(f'- Person {i}: Interpolating missing sequences if they are smaller than {interp_gap_smaller_than} frames. Large gaps filled with {fill_large_gaps_with}.')
2034
2055
  all_frames_angles_person_interp = all_frames_angles_person.apply(interpolate_zeros_nans, axis=0, args = [interp_gap_smaller_than, 'linear'])
2035
2056
  if fill_large_gaps_with == 'last_value':
2036
- all_frames_angles_person_interp = all_frames_angles_person_interp.ffill(axis=0).bfill(axis=0)
2057
+ for col in all_frames_angles_person_interp.columns:
2058
+ first_run_start, last_run_end = indices_of_first_last_non_nan_chunks(all_frames_angles_person_interp[col])
2059
+ all_frames_angles_person_interp.loc[:first_run_start, col] = np.nan
2060
+ all_frames_angles_person_interp.loc[last_run_end:, col] = np.nan
2061
+ all_frames_angles_person_interp.loc[first_run_start:last_run_end, col] = all_frames_angles_person_interp.loc[first_run_start:last_run_end, col].ffill().bfill()
2037
2062
  elif fill_large_gaps_with == 'zeros':
2038
2063
  all_frames_angles_person_interp.replace(np.nan, 0, inplace=True)
2039
2064
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sports2d
3
- Version: 0.8.11
3
+ Version: 0.8.13
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>
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes