few changes to the conversion to c3d
This commit is contained in:
parent
46652a8eaa
commit
db8014c3f5
1
.gitignore
vendored
1
.gitignore
vendored
@ -8,6 +8,7 @@ dist/
|
||||
# **/*.mp4
|
||||
**/*.trc
|
||||
**/*.sto
|
||||
**/*.c3d
|
||||
|
||||
**/Calib_qualisys.toml
|
||||
**/pose-3d/
|
||||
|
@ -164,6 +164,7 @@ make_c3d = false # also save triangulated data in c3d format
|
||||
## Only works on BODY_25 and BODY_25B models
|
||||
participant_height = 1.72 # m # float if single person, list of float if multi-person (same order as the Static trials)
|
||||
participant_mass = 70.0 # kg
|
||||
make_c3d = false # save triangulated data in c3d format in addition to trc
|
||||
|
||||
|
||||
[opensim]
|
||||
|
@ -163,10 +163,11 @@
|
||||
## Only works on BODY_25 and BODY_25B models
|
||||
# participant_height = 1.72 # m # float if single person, list of float if multi-person (same order as the Static trials)
|
||||
# participant_mass = 70.0 # kg
|
||||
# make_c3d = false # save triangulated data in c3d format in addition to trc
|
||||
|
||||
|
||||
# [opensim]
|
||||
# static_trial = ['S00_P00_Participant/S00_P00_T00_StaticTrial']
|
||||
# static_trial = [# static_trial = ['S00_P00_Participant/S00_P00_T00_StaticTrial']
|
||||
# # If this Config.toml file is at the Trial level, set to true or false (lowercase);
|
||||
# # At the Participant level, specify the name of the static trial folder name, e.g. ['S00_P00_T00_StaticTrial'];
|
||||
# # At the Session level, add participant subdirectory, e.g. ['S00_P00_Participant/S00_P00_T00_StaticTrial', 'S00_P01_Participant/S00_P00_T00_StaticTrial']
|
||||
|
@ -163,10 +163,11 @@
|
||||
## Only works on BODY_25 and BODY_25B models
|
||||
# participant_height = 1.72 # m # float if single person, list of float if multi-person (same order as the Static trials)
|
||||
# participant_mass = 70.0 # kg
|
||||
# make_c3d = false # save triangulated data in c3d format in addition to trc
|
||||
|
||||
|
||||
# [opensim]
|
||||
# static_trial = ['S00_P00_Participant/S00_P00_T00_StaticTrial']
|
||||
# static_trial = [# static_trial = ['S00_P00_Participant/S00_P00_T00_StaticTrial']
|
||||
# # If this Config.toml file is at the Trial level, set to true or false (lowercase);
|
||||
# # At the Participant level, specify the name of the static trial folder name, e.g. ['S00_P00_T00_StaticTrial'];
|
||||
# # At the Session level, add participant subdirectory, e.g. ['S00_P00_Participant/S00_P00_T00_StaticTrial', 'S00_P01_Participant/S00_P00_T00_StaticTrial']
|
||||
|
@ -163,10 +163,11 @@ display_figures = false # true or false (lowercase)
|
||||
## Only works on BODY_25 and BODY_25B models
|
||||
# participant_height = 1.72 # m # float if single person, list of float if multi-person (same order as the Static trials)
|
||||
# participant_mass = 70.0 # kg
|
||||
# make_c3d = false # save triangulated data in c3d format in addition to trc
|
||||
|
||||
|
||||
# [opensim]
|
||||
# static_trial = ['S00_P00_Participant/S00_P00_T00_StaticTrial']
|
||||
# static_trial = [# static_trial = ['S00_P00_Participant/S00_P00_T00_StaticTrial']
|
||||
# # If this Config.toml file is at the Trial level, set to true or false (lowercase);
|
||||
# # At the Participant level, specify the name of the static trial folder name, e.g. ['S00_P00_T00_StaticTrial'];
|
||||
# # At the Session level, add participant subdirectory, e.g. ['S00_P00_Participant/S00_P00_T00_StaticTrial', 'S00_P01_Participant/S00_P00_T00_StaticTrial']
|
||||
|
@ -163,10 +163,12 @@
|
||||
## Only works on BODY_25 and BODY_25B models
|
||||
# participant_height = 1.72 # m # float if single person, list of float if multi-person (same order as the Static trials)
|
||||
# participant_mass = 70.0 # kg
|
||||
# make_c3d = false # save triangulated data in c3d format in addition to trc
|
||||
# make_c3d = false # save triangulated data in c3d format in addition to trc
|
||||
|
||||
|
||||
# [opensim]
|
||||
# static_trial = ['S00_P00_Participant/S00_P00_T00_StaticTrial']
|
||||
# static_trial = [# static_trial = ['S00_P00_Participant/S00_P00_T00_StaticTrial']
|
||||
# # If this Config.toml file is at the Trial level, set to true or false (lowercase);
|
||||
# # At the Participant level, specify the name of the static trial folder name, e.g. ['S00_P00_T00_StaticTrial'];
|
||||
# # At the Session level, add participant subdirectory, e.g. ['S00_P00_Participant/S00_P00_T00_StaticTrial', 'S00_P01_Participant/S00_P00_T00_StaticTrial']
|
||||
|
@ -163,10 +163,11 @@
|
||||
## Only works on BODY_25 and BODY_25B models
|
||||
participant_height = 1.21 # m # float if single person, list of float if multi-person (same order as the Static trials)
|
||||
participant_mass = 25.0 # kg
|
||||
# make_c3d = false # save triangulated data in c3d format in addition to trc
|
||||
|
||||
|
||||
# [opensim]
|
||||
# static_trial = ['S00_P00_Participant/S00_P00_T00_StaticTrial']
|
||||
# static_trial = [# static_trial = ['S00_P00_Participant/S00_P00_T00_StaticTrial']
|
||||
# # If this Config.toml file is at the Trial level, set to true or false (lowercase);
|
||||
# # At the Participant level, specify the name of the static trial folder name, e.g. ['S00_P00_T00_StaticTrial'];
|
||||
# # At the Session level, add participant subdirectory, e.g. ['S00_P00_Participant/S00_P00_T00_StaticTrial', 'S00_P01_Participant/S00_P00_T00_StaticTrial']
|
||||
|
@ -162,10 +162,11 @@
|
||||
## Only works on BODY_25 and BODY_25B models
|
||||
participant_height = 1.72 # m # float if single person, list of float if multi-person (same order as the Static trials)
|
||||
participant_mass = 70.0 # kg
|
||||
# make_c3d = false # save triangulated data in c3d format in addition to trc
|
||||
|
||||
|
||||
# [opensim]
|
||||
# static_trial = ['S00_P00_Participant/S00_P00_T00_StaticTrial']
|
||||
# static_trial = [# static_trial = ['S00_P00_Participant/S00_P00_T00_StaticTrial']
|
||||
# # If this Config.toml file is at the Trial level, set to true or false (lowercase);
|
||||
# # At the Participant level, specify the name of the static trial folder name, e.g. ['S00_P00_T00_StaticTrial'];
|
||||
# # At the Session level, add participant subdirectory, e.g. ['S00_P00_Participant/S00_P00_T00_StaticTrial', 'S00_P01_Participant/S00_P00_T00_StaticTrial']
|
||||
|
@ -129,13 +129,13 @@ reorder_trc = true # only checked if multi_person analysis
|
||||
# show_interp_indices = true # true or false (lowercase). For each keypoint, return the frames that need to be interpolated
|
||||
# handle_LR_swap = false # Better if few cameras (eg less than 4) with risk of limb swapping (eg camera facing sagittal plane), otherwise slightly less accurate and slower
|
||||
# undistort_points = false # Better if distorted image (parallel lines curvy on the edge or at least one param > 10^-2), but unnecessary (and slightly slower) if distortions are low
|
||||
# make_c3d = false # save triangulated data in c3d format in addition to trc
|
||||
make_c3d = true # save triangulated data in c3d format in addition to trc
|
||||
|
||||
|
||||
# [filtering]
|
||||
[filtering]
|
||||
# type = 'butterworth' # butterworth, kalman, gaussian, LOESS, median, butterworth_on_speed
|
||||
# display_figures = false # true or false (lowercase)
|
||||
# make_c3d = false # save triangulated data in c3d format in addition to trc
|
||||
make_c3d = true # save triangulated data in c3d format in addition to trc
|
||||
|
||||
# [filtering.butterworth]
|
||||
# order = 4
|
||||
@ -159,10 +159,11 @@ reorder_trc = true # only checked if multi_person analysis
|
||||
## Only works on BODY_25 and BODY_25B models
|
||||
participant_height = [1.21, 1.72] # m # float if single person, list of float if multi-person (same order as the Static trials)
|
||||
participant_mass = [25.0, 70.0] # kg
|
||||
make_c3d = true # save triangulated data in c3d format in addition to trc
|
||||
|
||||
|
||||
# [opensim]
|
||||
# static_trial = ['S00_P00_Participant/S00_P00_T00_StaticTrial']
|
||||
# static_trial = [# static_trial = ['S00_P00_Participant/S00_P00_T00_StaticTrial']
|
||||
# # If this Config.toml file is at the Trial level, set to true or false (lowercase);
|
||||
# # At the Participant level, specify the name of the static trial folder name, e.g. ['S00_P00_T00_StaticTrial'];
|
||||
# # At the Session level, add participant subdirectory, e.g. ['S00_P00_Participant/S00_P00_T00_StaticTrial', 'S00_P01_Participant/S00_P00_T00_StaticTrial']
|
||||
|
@ -164,6 +164,7 @@ make_c3d = false # save triangulated data in c3d format in addition to trc
|
||||
## Only works on BODY_25 and BODY_25B models
|
||||
participant_height = 1.72 # m # float if single person, list of float if multi-person (same order as the Static trials)
|
||||
participant_mass = 70.0 # kg
|
||||
make_c3d = false # save triangulated data in c3d format in addition to trc
|
||||
|
||||
|
||||
[opensim]
|
||||
|
@ -10,8 +10,6 @@
|
||||
Converts c3d files to trc files.
|
||||
Beware that it only allows you to retrieve 3D points, you won't get analog data nor computed data such as angles or powers with this code.
|
||||
|
||||
N.B.: First install c3d: `pip install c3d`
|
||||
|
||||
Usage:
|
||||
from Pose2Sim.Utilities import c3d_to_trc; c3d_to_trc.c3d_to_trc_func(r'<input_c3d_file>')
|
||||
python -m c3d_to_trc -i input_c3d_file
|
||||
|
@ -1,73 +1,126 @@
|
||||
"""
|
||||
Extracts marker data from a TRC file and creates a corresponding C3D file.
|
||||
#! /usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
Usage:
|
||||
python trc_to_c3d.py --trc_path <path_to_trc_file> --f <frame_rate>
|
||||
|
||||
--trc_path: Path to the TRC file.
|
||||
--f: Frame rate of the 3D data.
|
||||
c3d file will be saved in the same directory as the TRC file with the same name.
|
||||
'''
|
||||
##################################################
|
||||
## Convert trc files to c3d ##
|
||||
##################################################
|
||||
|
||||
Converts trc files to c3d files.
|
||||
|
||||
Usage:
|
||||
from Pose2Sim.Utilities import trc_to_c3d; trc_to_c3d.trc_to_c3d_func(r'<input_trc_file>')
|
||||
python -m trc_to_c3d -t <path_to_trc_path>
|
||||
python -m trc_to_c3d --trc_path <path_to_trc_path> --c3d_path <output_c3d_file>
|
||||
'''
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
## INIT
|
||||
import argparse
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import c3d
|
||||
|
||||
def extract_marker_data(trc_file):
|
||||
with open(trc_file, 'r') as file:
|
||||
|
||||
## AUTHORSHIP INFORMATION
|
||||
__author__ = "HunMin Kim, David Pagnon"
|
||||
__copyright__ = "Copyright 2021, Pose2Sim"
|
||||
__credits__ = ["HuMin Kim, David Pagnon"]
|
||||
__license__ = "BSD 3-Clause License"
|
||||
__version__ = '0.8'
|
||||
__maintainer__ = "David Pagnon"
|
||||
__email__ = "contact@david-pagnon.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
## FUNCTIONS
|
||||
def extract_marker_data(trc_path):
|
||||
'''
|
||||
Extract marker names and coordinates from a trc file.
|
||||
|
||||
INPUTS:
|
||||
- trc_path: Path to the trc file
|
||||
|
||||
OUTPUTS:
|
||||
- marker_names: List of marker names
|
||||
- marker_coords: Array of marker coordinates (n_frames, t+3*n_markers)
|
||||
'''
|
||||
|
||||
# marker names
|
||||
with open(trc_path, 'r') as file:
|
||||
lines = file.readlines()
|
||||
marker_names_line = lines[3]
|
||||
marker_names = marker_names_line.strip().split('\t')[2::3]
|
||||
|
||||
trc_data = pd.read_csv(trc_file, sep='\t', skiprows=5)
|
||||
marker_coords = trc_data.iloc[:, 2:].to_numpy().reshape(-1, len(marker_names), 3)
|
||||
# marker_coords = np.nan_to_num(marker_coords, nan=0.0)
|
||||
marker_coords *= 1000 # Convert from meters to millimeters
|
||||
# time and marker coordinates
|
||||
trc_data_np = np.genfromtxt(trc_path, skip_header=5, delimiter = '\t')[:,1:]
|
||||
|
||||
return marker_names, marker_coords
|
||||
return marker_names, trc_data_np
|
||||
|
||||
def create_c3d_file(trc_file, marker_names, marker_coords, frame_rate):
|
||||
|
||||
def create_c3d_file(c3d_path, marker_names, trc_data_np):
|
||||
'''
|
||||
Create a c3d file from the data extracted from a trc file.
|
||||
|
||||
INPUTS:
|
||||
- c3d_path: Path to the c3d file
|
||||
- marker_names: List of marker names
|
||||
- trc_data_np: Array of marker coordinates (n_frames, t+3*n_markers)
|
||||
|
||||
OUTPUTS:
|
||||
- c3d file
|
||||
'''
|
||||
|
||||
# retrieve frame rate
|
||||
times = trc_data_np[:,0]
|
||||
frame_rate = round((len(times)-1) / (times[-1] - times[0]))
|
||||
|
||||
# write c3d file
|
||||
writer = c3d.Writer(point_rate=frame_rate, analog_rate=0, point_scale=1.0, point_units='mm', gen_scale=-1.0)
|
||||
writer.set_point_labels(marker_names)
|
||||
|
||||
markers_group = writer.point_group
|
||||
|
||||
for frame in marker_coords:
|
||||
residuals = np.full((frame.shape[0], 1), 0.0)
|
||||
cameras = np.zeros((frame.shape[0], 1))
|
||||
points = np.hstack((frame, residuals, cameras))
|
||||
for frame in trc_data_np:
|
||||
residuals = np.full((len(marker_names), 1), 0.0)
|
||||
cameras = np.zeros((len(marker_names), 1))
|
||||
coords = frame[1:].reshape(-1,3)*1000
|
||||
points = np.hstack((coords, residuals, cameras))
|
||||
writer.add_frames([(points, np.array([]))])
|
||||
|
||||
writer.set_start_frame(1)
|
||||
writer._set_last_frame(len(marker_coords))
|
||||
writer.set_start_frame(0)
|
||||
writer._set_last_frame(len(trc_data_np)-1)
|
||||
|
||||
c3d_file_path = trc_file.replace('.trc', '.c3d')
|
||||
with open(c3d_file_path, 'wb') as handle:
|
||||
with open(c3d_path, 'wb') as handle:
|
||||
writer.write(handle)
|
||||
print(f"Successfully created c3d file.")
|
||||
|
||||
def trc_to_c3d(trc_file, frame_rate):
|
||||
marker_names, marker_coords = extract_marker_data(trc_file)
|
||||
create_c3d_file(trc_file, marker_names, marker_coords, frame_rate)
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Convert TRC files to C3D files.')
|
||||
parser.add_argument('--trc_path', type=str, required=True, help='Path to the TRC file')
|
||||
parser.add_argument('--f', type=int, required=True, help='Frame rate')
|
||||
def trc_to_c3d_func(*args):
|
||||
'''
|
||||
Converts trc files to c3d files.
|
||||
|
||||
Usage:
|
||||
from Pose2Sim.Utilities import trc_to_c3d; trc_to_c3d.trc_to_c3d_func(r'<input_trc_file>')
|
||||
python -m trc_to_c3d -t <path_to_trc_path>
|
||||
python -m trc_to_c3d --trc_path <path_to_trc_path> --c3d_path <output_c3d_file>
|
||||
'''
|
||||
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
trc_path = args[0]['trc_path'] # invoked with argparse
|
||||
if args[0]['c3d_path'] == None:
|
||||
c3d_path = trc_path.replace('.trc', '.c3d')
|
||||
else:
|
||||
c3d_path = args[0]['c3d_path']
|
||||
except:
|
||||
trc_path = args[0] # invoked as a function
|
||||
c3d_path = trc_path.replace('.trc', '.c3d')
|
||||
|
||||
trc_file = args.trc_path
|
||||
frame_rate = args.f
|
||||
marker_names, trc_data_np = extract_marker_data(trc_path)
|
||||
create_c3d_file(c3d_path, marker_names, trc_data_np)
|
||||
|
||||
if not os.path.isfile(trc_file):
|
||||
print(f"Error: {trc_file} does not exist.")
|
||||
return
|
||||
|
||||
trc_to_c3d(trc_file, frame_rate)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
parser = argparse.ArgumentParser(description='Convert TRC files to C3D files.')
|
||||
parser.add_argument('-t', '--trc_path', type=str, required=True, help='trc input file path')
|
||||
parser.add_argument('-c', '--c3d_path', type=str, required=False, help='c3d output file path')
|
||||
args = vars(parser.parse_args())
|
||||
|
||||
trc_to_c3d_func(args)
|
||||
|
@ -16,10 +16,8 @@ import json
|
||||
import numpy as np
|
||||
import re
|
||||
import cv2
|
||||
import os
|
||||
import pandas as pd
|
||||
import c3d
|
||||
import glob
|
||||
import sys
|
||||
|
||||
import matplotlib as mpl
|
||||
mpl.use('qt5agg')
|
||||
@ -27,7 +25,8 @@ mpl.rc('figure', max_open_warning=0)
|
||||
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
||||
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
|
||||
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QTabWidget, QVBoxLayout
|
||||
import sys
|
||||
import warnings
|
||||
warnings.filterwarnings("ignore", category=UserWarning, module="c3d")
|
||||
|
||||
|
||||
## AUTHORSHIP INFORMATION
|
||||
@ -385,6 +384,83 @@ def zup2yup(Q):
|
||||
return Q
|
||||
|
||||
|
||||
def extract_trc_data(trc_path):
|
||||
'''
|
||||
Extract marker names and coordinates from a trc file.
|
||||
|
||||
INPUTS:
|
||||
- trc_path: Path to the trc file
|
||||
|
||||
OUTPUTS:
|
||||
- marker_names: List of marker names
|
||||
- marker_coords: Array of marker coordinates (n_frames, t+3*n_markers)
|
||||
'''
|
||||
|
||||
# marker names
|
||||
with open(trc_path, 'r') as file:
|
||||
lines = file.readlines()
|
||||
marker_names_line = lines[3]
|
||||
marker_names = marker_names_line.strip().split('\t')[2::3]
|
||||
|
||||
# time and marker coordinates
|
||||
trc_data_np = np.genfromtxt(trc_path, skip_header=5, delimiter = '\t')[:,1:]
|
||||
|
||||
return marker_names, trc_data_np
|
||||
|
||||
|
||||
def create_c3d_file(c3d_path, marker_names, trc_data_np):
|
||||
'''
|
||||
Create a c3d file from the data extracted from a trc file.
|
||||
|
||||
INPUTS:
|
||||
- c3d_path: Path to the c3d file
|
||||
- marker_names: List of marker names
|
||||
- trc_data_np: Array of marker coordinates (n_frames, t+3*n_markers)
|
||||
|
||||
OUTPUTS:
|
||||
- c3d file
|
||||
'''
|
||||
|
||||
# retrieve frame rate
|
||||
times = trc_data_np[:,0]
|
||||
frame_rate = round((len(times)-1) / (times[-1] - times[0]))
|
||||
|
||||
# write c3d file
|
||||
writer = c3d.Writer(point_rate=frame_rate, analog_rate=0, point_scale=1.0, point_units='mm', gen_scale=-1.0)
|
||||
writer.set_point_labels(marker_names)
|
||||
|
||||
for frame in trc_data_np:
|
||||
residuals = np.full((len(marker_names), 1), 0.0)
|
||||
cameras = np.zeros((len(marker_names), 1))
|
||||
coords = frame[1:].reshape(-1,3)*1000
|
||||
points = np.hstack((coords, residuals, cameras))
|
||||
writer.add_frames([(points, np.array([]))])
|
||||
|
||||
writer.set_start_frame(0)
|
||||
writer._set_last_frame(len(trc_data_np)-1)
|
||||
|
||||
with open(c3d_path, 'wb') as handle:
|
||||
writer.write(handle)
|
||||
|
||||
|
||||
def convert_to_c3d(trc_path):
|
||||
'''
|
||||
Make Visual3D compatible c3d files from a trc path
|
||||
|
||||
INPUT:
|
||||
- trc_path: string, trc file to convert
|
||||
|
||||
OUTPUT:
|
||||
- c3d file
|
||||
'''
|
||||
|
||||
c3d_path = trc_path.replace('.trc', '.c3d')
|
||||
marker_names, trc_data_np = extract_trc_data(trc_path)
|
||||
create_c3d_file(c3d_path, marker_names, trc_data_np)
|
||||
|
||||
return c3d_path
|
||||
|
||||
|
||||
## CLASSES
|
||||
class plotWindow():
|
||||
'''
|
||||
@ -436,85 +512,3 @@ class plotWindow():
|
||||
|
||||
def show(self):
|
||||
self.app.exec_()
|
||||
|
||||
# Save c3d
|
||||
def trc_to_c3d(project_dir, frame_rate, called_from):
|
||||
'''
|
||||
Converts.trc files to.c3d files
|
||||
INPUT:
|
||||
- project_dir: path to project folder
|
||||
- frame_rate: frame rate of the video
|
||||
- called_from: string that determines which.trc files to convert.
|
||||
'triangulation' for.trc files from triangulation step
|
||||
'filtering' for.trc files from filtering step
|
||||
|
||||
'''
|
||||
# Determine the 3D pose folder
|
||||
pose3d_dir = os.path.join(project_dir, 'pose-3d')
|
||||
|
||||
# Determine the .trc file name to read
|
||||
trc_files = []
|
||||
if called_from == 'triangulation':
|
||||
trc_pattern = "*.trc"
|
||||
trc_files = [os.path.basename(f) for f in glob.glob(os.path.join(pose3d_dir, trc_pattern)) if 'filt' not in f]
|
||||
elif called_from == 'filtering':
|
||||
trc_pattern = "*_filt_*.trc"
|
||||
trc_files = [os.path.basename(f) for f in glob.glob(os.path.join(pose3d_dir, trc_pattern))]
|
||||
else:
|
||||
print("Invalid called_from value.")
|
||||
|
||||
for trc_file in trc_files:
|
||||
# Extract marker names from the 4th row of the TRC file
|
||||
with open(os.path.join(pose3d_dir, trc_file), 'r') as file:
|
||||
lines = file.readlines()
|
||||
marker_names_line = lines[3]
|
||||
marker_names = marker_names_line.strip().split('\t')[2::3]
|
||||
|
||||
# Read the data frame (skiprows=5)
|
||||
trc_data = pd.read_csv(os.path.join(pose3d_dir, trc_file), sep='\t', skiprows=5)
|
||||
|
||||
# Extract marker coordinates
|
||||
marker_coords = trc_data.iloc[:, 2:].to_numpy().reshape(-1, len(marker_names), 3)
|
||||
# marker_coords = np.nan_to_num(marker_coords, nan=0.0)
|
||||
|
||||
scale_factor = 1000
|
||||
marker_coords = marker_coords * scale_factor
|
||||
|
||||
# Create a C3D writer
|
||||
writer = c3d.Writer(point_rate=frame_rate, analog_rate=0, point_scale=1.0, point_units='mm', gen_scale=-1.0)
|
||||
|
||||
# Add marker parameters
|
||||
writer.set_point_labels(marker_names)
|
||||
|
||||
# # Add marker descriptions (optional)
|
||||
# marker_descriptions = [''] * len(marker_names)
|
||||
# writer.point_group.add_param('DESCRIPTIONS', desc='Marker descriptions',
|
||||
# bytes_per_element=-1, dimensions=[len(marker_names)],
|
||||
# bytes=np.array(marker_descriptions, dtype=object))
|
||||
|
||||
# # Set the data start parameter
|
||||
# data_start = writer.header.data_block
|
||||
# writer.point_group.add_param('DATA_START', desc='Data start parameter',
|
||||
# bytes_per_element=2, dimensions=[], bytes=struct.pack('<H', data_start))
|
||||
|
||||
# Create a C3D group for markers
|
||||
markers_group = writer.point_group
|
||||
|
||||
# Add frame data
|
||||
for frame in marker_coords:
|
||||
# Add residual and camera columns
|
||||
residuals = np.full((frame.shape[0], 1), 0.0) # Set residuals to 0.0
|
||||
cameras = np.zeros((frame.shape[0], 1)) # Set cameras to 0
|
||||
points = np.hstack((frame, residuals, cameras))
|
||||
writer.add_frames([(points, np.array([]))])
|
||||
|
||||
# Set the trial start and end frames
|
||||
writer.set_start_frame(1)
|
||||
writer._set_last_frame(len(marker_coords))
|
||||
|
||||
# Write the C3D file
|
||||
c3d_file_path = trc_file.replace('.trc', '.c3d')
|
||||
with open(os.path.join(pose3d_dir, c3d_file_path), 'wb') as handle:
|
||||
writer.write(handle)
|
||||
|
||||
print(f"-->c3d file saved: {c3d_file_path}")
|
@ -37,7 +37,7 @@ from filterpy.kalman import KalmanFilter, rts_smoother
|
||||
from filterpy.common import Q_discrete_white_noise
|
||||
|
||||
from Pose2Sim.common import plotWindow
|
||||
from Pose2Sim.common import trc_to_c3d
|
||||
from Pose2Sim.common import convert_to_c3d
|
||||
|
||||
## AUTHORSHIP INFORMATION
|
||||
__author__ = "David Pagnon"
|
||||
@ -416,6 +416,7 @@ def recap_filter3d(config, trc_path):
|
||||
gaussian_filter_sigma_kernel = int(config.get('filtering').get('gaussian').get('sigma_kernel'))
|
||||
loess_filter_nb_values = config.get('filtering').get('LOESS').get('nb_values_used')
|
||||
median_filter_kernel_size = config.get('filtering').get('median').get('kernel_size')
|
||||
make_c3d = config.get('filtering').get('make_c3d')
|
||||
|
||||
# Recap
|
||||
filter_mapping_recap = {
|
||||
@ -428,6 +429,8 @@ def recap_filter3d(config, trc_path):
|
||||
}
|
||||
logging.info(filter_mapping_recap[filter_type])
|
||||
logging.info(f'Filtered 3D coordinates are stored at {trc_path}.\n')
|
||||
if make_c3d:
|
||||
logging.info('All filtered trc files have been converted to c3d.')
|
||||
|
||||
|
||||
def filter_all(config):
|
||||
@ -497,10 +500,11 @@ def filter_all(config):
|
||||
# Q_filt = Q_filt.fillna(' ')
|
||||
Q_filt.to_csv(trc_o, sep='\t', index=False, header=None, lineterminator='\n')
|
||||
|
||||
# Save c3d
|
||||
if make_c3d:
|
||||
convert_to_c3d(t_out)
|
||||
|
||||
# Recap
|
||||
recap_filter3d(config, t_out)
|
||||
|
||||
# Save c3d
|
||||
if make_c3d == True:
|
||||
trc_to_c3d(project_dir, frame_rate, called_from='filtering')
|
||||
|
||||
|
@ -23,14 +23,15 @@ OUTPUT:
|
||||
## INIT
|
||||
import os
|
||||
import numpy as np
|
||||
from Pose2Sim.MarkerAugmenter import utilsDataman
|
||||
import copy
|
||||
import tensorflow as tf
|
||||
from Pose2Sim.MarkerAugmenter.utils import TRC2numpy
|
||||
import json
|
||||
import glob
|
||||
import logging
|
||||
|
||||
from Pose2Sim.MarkerAugmenter import utilsDataman
|
||||
from Pose2Sim.MarkerAugmenter.utils import TRC2numpy
|
||||
from Pose2Sim.common import convert_to_c3d
|
||||
|
||||
|
||||
## AUTHORSHIP INFORMATION
|
||||
__author__ = "Antoine Falisse, adapted by HunMin Kim"
|
||||
@ -65,7 +66,6 @@ def augmentTRC(config_dict):
|
||||
project_dir = config_dict.get('project').get('project_dir')
|
||||
pathInputTRCFile = os.path.realpath(os.path.join(project_dir, 'pose-3d'))
|
||||
pathOutputTRCFile = os.path.realpath(os.path.join(project_dir, 'pose-3d'))
|
||||
pose_model = config_dict.get('pose').get('pose_model')
|
||||
subject_height = config_dict.get('markerAugmentation').get('participant_height')
|
||||
if subject_height is None or subject_height == 0 or subject_height==0:
|
||||
raise ValueError("Subject height is not set or invalid in the config file.")
|
||||
@ -73,6 +73,7 @@ def augmentTRC(config_dict):
|
||||
if not type(subject_height) == list:
|
||||
subject_height = [subject_height]
|
||||
subject_mass = [subject_mass]
|
||||
make_c3d = config_dict.get('markerAugmentation').get('make_c3d')
|
||||
augmenterDir = os.path.dirname(utilsDataman.__file__)
|
||||
augmenterModelName = 'LSTM'
|
||||
augmenter_model = 'v0.3'
|
||||
@ -151,8 +152,6 @@ def augmentTRC(config_dict):
|
||||
trc_data_data = trc_data[:,1:]
|
||||
|
||||
# Step 2: Normalize with reference marker position.
|
||||
with open(os.path.join(augmenterModelDir, "metadata.json"), 'r') as f:
|
||||
metadata = json.load(f)
|
||||
referenceMarker_data = midhip_data # instead of trc_file.marker(referenceMarker) # change by HunMin
|
||||
norm_trc_data_data = np.zeros((trc_data_data.shape[0],
|
||||
trc_data_data.shape[1]))
|
||||
@ -245,7 +244,15 @@ def augmentTRC(config_dict):
|
||||
# %% Return augmented .trc file
|
||||
trc_file.write(pathOutputTRCFile)
|
||||
|
||||
logging.info(f'Augmented marker coordinates are stored at {pathOutputTRCFile}.\n')
|
||||
logging.info(f'Augmented marker coordinates are stored at {pathOutputTRCFile}.')
|
||||
|
||||
# Save c3d
|
||||
if make_c3d:
|
||||
print(pathOutputTRCFile)
|
||||
convert_to_c3d(pathOutputTRCFile)
|
||||
logging.info(f'Augmented trc files have been converted to c3d.')
|
||||
|
||||
logging.info('\n')
|
||||
|
||||
return min_y_pos
|
||||
|
||||
|
@ -50,8 +50,7 @@ from anytree.importer import DictImporter
|
||||
import logging
|
||||
|
||||
from Pose2Sim.common import retrieve_calib_params, computeP, weighted_triangulation, \
|
||||
reprojection, euclidean_distance, sort_stringlist_by_last_number, zup2yup
|
||||
from Pose2Sim.common import trc_to_c3d
|
||||
reprojection, euclidean_distance, sort_stringlist_by_last_number, zup2yup, convert_to_c3d
|
||||
from Pose2Sim.skeletons import *
|
||||
|
||||
|
||||
@ -312,7 +311,7 @@ def recap_triangulate(config, error, nb_cams_excluded, keypoints_names, cam_excl
|
||||
# if batch
|
||||
session_dir = os.path.realpath(os.path.join(project_dir, '..', '..'))
|
||||
# if single trial
|
||||
session_dir = os.getcwd() if not 'Config.toml' in session_dir else session_dir
|
||||
session_dir = os.getcwd() if not 'Config.toml' in os.listdir(session_dir) else session_dir
|
||||
calib_dir = [os.path.join(session_dir, c) for c in os.listdir(session_dir) if 'calib' in c.lower()][0]
|
||||
calib_file = glob.glob(os.path.join(calib_dir, '*.toml'))[0] # lastly created calibration file
|
||||
calib = toml.load(calib_file)
|
||||
@ -322,6 +321,7 @@ def recap_triangulate(config, error, nb_cams_excluded, keypoints_names, cam_excl
|
||||
likelihood_threshold = config.get('triangulation').get('likelihood_threshold_triangulation')
|
||||
show_interp_indices = config.get('triangulation').get('show_interp_indices')
|
||||
interpolation_kind = config.get('triangulation').get('interpolation')
|
||||
make_c3d = config.get('triangulation').get('make_c3d')
|
||||
handle_LR_swap = config.get('triangulation').get('handle_LR_swap')
|
||||
undistort_points = config.get('triangulation').get('undistort_points')
|
||||
|
||||
@ -374,8 +374,11 @@ def recap_triangulate(config, error, nb_cams_excluded, keypoints_names, cam_excl
|
||||
str_cam_excluded_count += f'Camera {k}: {int(np.round(v*100))}%, '
|
||||
logging.info(str_cam_excluded_count)
|
||||
logging.info(f'\n3D coordinates are stored at {trc_path[n]}.')
|
||||
|
||||
logging.info(f'\n\nLimb swapping was {"handled" if handle_LR_swap else "not handled"}.')
|
||||
|
||||
logging.info('\n\n')
|
||||
if make_c3d:
|
||||
logging.info('All trc files have been converted to c3d.')
|
||||
logging.info(f'Limb swapping was {"handled" if handle_LR_swap else "not handled"}.')
|
||||
logging.info(f'Lens distortions were {"taken into account" if undistort_points else "not taken into account"}.')
|
||||
|
||||
|
||||
@ -693,7 +696,7 @@ def triangulate_all(config):
|
||||
# if batch
|
||||
session_dir = os.path.realpath(os.path.join(project_dir, '..', '..'))
|
||||
# if single trial
|
||||
session_dir = os.getcwd() if not 'Config.toml' in session_dir else session_dir
|
||||
session_dir = os.getcwd() if not 'Config.toml' in os.listdir(session_dir) else session_dir
|
||||
multi_person = config.get('project').get('multi_person')
|
||||
pose_model = config.get('pose').get('pose_model')
|
||||
frame_range = config.get('project').get('frame_range')
|
||||
@ -705,7 +708,7 @@ def triangulate_all(config):
|
||||
undistort_points = config.get('triangulation').get('undistort_points')
|
||||
make_c3d = config.get('triangulation').get('make_c3d')
|
||||
frame_rate = config.get('project').get('frame_rate')
|
||||
|
||||
|
||||
calib_dir = [os.path.join(session_dir, c) for c in os.listdir(session_dir) if 'calib' in c.lower()][0]
|
||||
try:
|
||||
calib_file = glob.glob(os.path.join(calib_dir, '*.toml'))[0] # lastly created calibration file
|
||||
@ -909,23 +912,25 @@ def triangulate_all(config):
|
||||
|
||||
# Create TRC file
|
||||
trc_paths = [make_trc(config, Q_tot[n], keypoints_names, f_range, id_person=n) for n in range(len(Q_tot))]
|
||||
|
||||
if make_c3d:
|
||||
c3d_paths = [convert_to_c3d(t) for t in trc_paths]
|
||||
|
||||
# Reorder TRC files
|
||||
if multi_person and reorder_trc and len(trc_paths)>1:
|
||||
trc_id = retrieve_right_trc_order(trc_paths)
|
||||
[os.rename(t, t+'.old') for t in trc_paths]
|
||||
[os.rename(t+'.old', trc_paths[i]) for i, t in zip(trc_id,trc_paths)]
|
||||
if make_c3d:
|
||||
[os.rename(c, c+'.old') for c in c3d_paths]
|
||||
[os.rename(c+'.old', c3d_paths[i]) for i, c in zip(trc_id,c3d_paths)]
|
||||
error_tot = [error_tot[i] for i in trc_id]
|
||||
nb_cams_excluded_tot = [nb_cams_excluded_tot[i] for i in trc_id]
|
||||
cam_excluded_count = [cam_excluded_count[i] for i in trc_id]
|
||||
interp_frames = [interp_frames[i] for i in trc_id]
|
||||
non_interp_frames = [non_interp_frames[i] for i in trc_id]
|
||||
|
||||
logging.info('\nThe trc files have been renamed to match the order of the static sequences.')
|
||||
|
||||
logging.info('\nThe trc and c3d files have been renamed to match the order of the static sequences.')
|
||||
|
||||
|
||||
# Recap message
|
||||
recap_triangulate(config, error_tot, nb_cams_excluded_tot, keypoints_names, cam_excluded_count, interp_frames, non_interp_frames, trc_paths)
|
||||
|
||||
# Save c3d
|
||||
if make_c3d == True:
|
||||
trc_to_c3d(project_dir, frame_rate, called_from='triangulation')
|
||||
|
Loading…
Reference in New Issue
Block a user