can run with config dict rather than file

This commit is contained in:
davidpagnon 2023-09-20 14:39:40 +02:00
parent 7423833365
commit faec842d9e
4 changed files with 162 additions and 13 deletions

View File

@ -38,6 +38,10 @@ calibration_type = 'convert' # 'convert' or 'calculate'
convert_from = 'qualisys' # 'qualisys', 'optitrack', or 'vicon'
[calibration.convert.qualisys]
binning_factor = 1 # Usually 1, except when filming in 540p where it usually is 2
[calibration.convert.optitrack] # See readme for instructions
[calibration.convert.vicon] # No parameters needed
[calibration.convert.opencap] # No parameters needed
[calibration.convert.biocv] # No parameters needed
[calibration.calculate]

View File

@ -88,11 +88,19 @@ def base_params(config_dict):
def poseEstimation(config=os.path.join('User', 'Config.toml')):
'''
Estimate pose using BlazePose, OpenPose, AlphaPose, or DeepLabCut
Estimate pose using BlazePose, OpenPose, AlphaPose, or DeepLabCut.
config can either be a path or a dictionary (for batch processing)
'''
raise NotImplementedError('This has not been integrated yet. \nPlease read README.md for further explanation')
# TODO
from Pose2Sim.poseEstimation import pose_estimation_all
if type(config)==dict:
config_dict = config
else:
config_dict = read_config_file(config)
project_dir, seq_name, frames = base_params(config_dict)
@ -111,10 +119,15 @@ def poseEstimation(config=os.path.join('User', 'Config.toml')):
def calibration(config=os.path.join('User', 'Config.toml')):
'''
Cameras calibration from checkerboards or from qualisys files.
config can either be a path or a dictionary (for batch processing)
'''
from Pose2Sim.calibration import calibrate_cams_all
if type(config)==dict:
config_dict = config
else:
config_dict = read_config_file(config)
project_dir, seq_name, frames = base_params(config_dict)
@ -132,11 +145,19 @@ def calibration(config=os.path.join('User', 'Config.toml')):
def synchronization(config=os.path.join('User', 'Config.toml')):
'''
Synchronize cameras if needed
Synchronize cameras if needed.
config can either be a path or a dictionary (for batch processing)
'''
raise NotImplementedError('This has not been integrated yet. \nPlease read README.md for further explanation')
#TODO
from Pose2Sim.synchronization import synchronize_cams_all
if type(config)==dict:
config_dict = config
else:
config_dict = read_config_file(config)
project_dir, seq_name, frames = base_params(config_dict)
@ -156,10 +177,15 @@ def personAssociation(config=os.path.join('User', 'Config.toml')):
'''
Tracking of the person of interest in case of multiple persons detection.
Needs a calibration file.
config can either be a path or a dictionary (for batch processing)
'''
from Pose2Sim.personAssociation import track_2d_all
if type(config)==dict:
config_dict = config
else:
config_dict = read_config_file(config)
project_dir, seq_name, frames = base_params(config_dict)
@ -178,10 +204,15 @@ def personAssociation(config=os.path.join('User', 'Config.toml')):
def triangulation(config=os.path.join('User', 'Config.toml')):
'''
Robust triangulation of 2D points coordinates.
config can either be a path or a dictionary (for batch processing)
'''
from Pose2Sim.triangulation import triangulate_all
if type(config)==dict:
config_dict = config
else:
config_dict = read_config_file(config)
project_dir, seq_name, frames = base_params(config_dict)
@ -200,10 +231,15 @@ def triangulation(config=os.path.join('User', 'Config.toml')):
def filtering(config=os.path.join('User', 'Config.toml')):
'''
Filter trc 3D coordinates.
config can either be a path or a dictionary (for batch processing)
'''
from Pose2Sim.filtering import filter_all
if type(config)==dict:
config_dict = config
else:
config_dict = read_config_file(config)
project_dir, seq_name, frames = base_params(config_dict)
@ -213,3 +249,63 @@ def filtering(config=os.path.join('User', 'Config.toml')):
logging.info(f"\nProject directory: {project_dir}")
filter_all(config_dict)
def scalingModel(config=os.path.join('User', 'Config.toml')):
'''
Uses OpenSim to scale a model based on a static 3D pose.
config can either be a path or a dictionary (for batch processing)
'''
raise NotImplementedError('This has not been integrated yet. \nPlease read README.md for further explanation')
# TODO
from Pose2Sim.scalingModel import scale_model_all
if type(config)==dict:
config_dict = config
else:
config_dict = read_config_file(config)
project_dir, seq_name, frames = base_params(config_dict)
logging.info("\n\n---------------------------------------------------------------------")
logging.info("Scaling model")
logging.info("---------------------------------------------------------------------")
logging.info(f"\nProject directory: {project_dir}")
start = time.time()
scale_model_all(config_dict)
end = time.time()
logging.info(f'Model scaling took {end-start:.2f} s.')
def inverseKinematics(config=os.path.join('User', 'Config.toml')):
'''
Uses OpenSim to perform inverse kinematics.
config can either be a path or a dictionary (for batch processing)
'''
raise NotImplementedError('This has not been integrated yet. \nPlease read README.md for further explanation')
# TODO
from Pose2Sim.inverseKinematics import inverse_kinematics_all
if type(config)==dict:
config_dict = config
else:
config_dict = read_config_file(config)
project_dir, seq_name, frames = base_params(config_dict)
logging.info("\n\n---------------------------------------------------------------------")
logging.info("Inverse kinematics")
logging.info("---------------------------------------------------------------------")
logging.info(f"\nProject directory: {project_dir}")
start = time.time()
inverse_kinematics_all(config_dict)
end = time.time()
logging.info(f'Inverse kinematics took {end-start:.2f} s.')

View File

@ -449,7 +449,7 @@ def filter_all(config):
pose_folder_name = config.get('project').get('pose_folder_name')
try:
pose_tracked_dir = os.path.join(project_dir, pose_tracked_folder_name)
os.path.isdir(pose_tracked_dir)
os.listdir(pose_tracked_dir)
pose_dir = pose_tracked_dir
except:
pose_dir = os.path.join(project_dir, pose_folder_name)
@ -469,7 +469,7 @@ def filter_all(config):
# Trc paths
trc_f_in = f'{seq_name}_{f_range[0]}-{f_range[1]}.trc'
trc_f_out = f'{seq_name}_filt_{f_range[0]}-{f_range[1]}.trc'
trc_f_out = f'{seq_name}_filt_{filter_type}_{f_range[0]}-{f_range[1]}.trc'
trc_path_in = os.path.join(pose3d_dir, trc_f_in)
trc_path_out = os.path.join(pose3d_dir, trc_f_out)

View File

@ -52,6 +52,7 @@ If you can only use one single camera and don't mind losing some accuracy, pleas
1. [OpenSim Scaling](#opensim-scaling)
2. [OpenSim Inverse kinematics](#opensim-inverse-kinematics)
3. [Command Line](#command-line)
7. [Batch processing](#batch-processing)
3. [Utilities](#utilities)
4. [How to cite and how to contribute](#how-to-cite-and-how-to-contribute)
1. [How to cite](#how-to-cite)
@ -659,6 +660,38 @@ Make sure to replace `38` in `py38np120` with your Python version (3.8 in this c
</pre>
</details>
## Batch processing
If you need to batch process multiple data or with multiple different parameters, you can run any Pose2Sim function with a `config` dictionary instead of a file. For example:
```
from Pose2Sim import Pose2Sim
import toml
config_dict = toml.load('User/Config.toml')
config_dict['project']['pose_folder_name'] = new_project_path
Pose2Sim.triangulate(config_dict)
```
Or into a loop:
```
from Pose2Sim import Pose2Sim
import toml
config_dict = toml.load('User/Config.toml')
# Change project_path
for new_project_path in new_project_paths:
config_dict['project']['project_dir'] = new_project_path
config_dict['filtering']['display_figures'] = False
# Run any Pose2Sim function with config_dict instead of a path
Pose2Sim.triangulation(config_dict)
# Now change filtering type
for new_filter in ['butterworth', 'kalman', 'gaussian']:
config_dict['filtering']['type'] = new_filter
Pose2Sim.filtering(config_dict)
```
# Utilities
A list of standalone tools (see [Utilities](https://github.com/perfanalytics/pose2sim/tree/main/Pose2Sim/Utilities)), which can be either run as scripts, or imported as functions. Check usage in the docstrings of each Python file. The figure below shows how some of these toolscan be used to further extend Pose2Sim usage.
@ -793,7 +826,6 @@ If you want to contribute to Pose2Sim, please follow [this guide](https://docs.g
> - [x] **Pose:** Support [BlazePose](https://developers.google.com/mediapipe/solutions/vision/pose_landmarker) for faster inference (on mobile device).
> - [x] **Pose:** Support [DeepLabCut](http://www.mackenziemathislab.org/deeplabcut) for training on custom datasets.
> - [x] **Pose:** Support [AlphaPose](https://github.com/MVIG-SJTU/AlphaPose) as an alternative to OpenPose.
> - [ ] **Pose:** Support [MediaPipe holistic](https://github.com/google/mediapipe/blob/master/docs/solutions/holistic.md) for pronation/supination (converter, skeleton.py, OpenSim model and setup files).
> - [ ] **Pose:** Support [MMPose](https://github.com/open-mmlab/mmpose), [SLEAP](https://sleap.ai/), etc.
</br>
@ -870,3 +902,20 @@ If you want to contribute to Pose2Sim, please follow [this guide](https://docs.g
> - [ ] **** Run pose estimation and OpenSim from within Pose2Sim
> - [ ] **Run from command line via click or typer**
> - [ ] **Utilities**: Export other data from c3d files into .mot or .sto files (angles, powers, forces, moments, GRF, EMG...)
</br>
> - [ ] **Bug:** common.py, class plotWindow(). Python crashes after a few runs of `Pose2Sim.filtering()` when `display_figures=true`. See [there](https://github.com/superjax/plotWindow/issues/7).
> - [ ] **Bug:** calibration.py. FFMPEG error message when calibration files are images. See [there](https://github.com/perfanalytics/pose2sim/issues/33#:~:text=In%20order%20to%20check,filter%20this%20message%20yet.).
</br>
**Pose2Sim releases:**
> - v0.1: Published online
> - v0.2: Published associated paper
> - v0.3: Supported other pose estimation algorithms
> - v0.4: New calibration tool
<!-- - v0.5: Supports multi-person analysis
- v0.6: New synchronization tool
- v0.7: Graphical User Interface
- v1.0: -->