can run with config dict rather than file
This commit is contained in:
parent
7423833365
commit
faec842d9e
@ -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]
|
||||
|
@ -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.')
|
@ -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)
|
||||
|
||||
|
51
README.md
51
README.md
@ -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: -->
|
||||
|
Loading…
Reference in New Issue
Block a user