-
Notifications
You must be signed in to change notification settings - Fork 56
/
Copy pathc3d_to_trc.py
131 lines (106 loc) · 4.99 KB
/
c3d_to_trc.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#! /usr/bin/env python
# -*- coding: utf-8 -*-
'''
##################################################
## Convert c3d files to trc ##
##################################################
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.
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
python -m c3d_to_trc -i input_c3d_file -o output_c3d_file
'''
## INIT
import c3d
import numpy as np
import argparse
## AUTHORSHIP INFORMATION
__author__ = "David Pagnon"
__copyright__ = "Copyright 2021, Pose2Sim"
__credits__ = ["David Pagnon"]
__license__ = "BSD 3-Clause License"
__version__ = "0.9.4"
__maintainer__ = "David Pagnon"
__email__ = "contact@david-pagnon.com"
__status__ = "Development"
## FUNCTIONS
def c3d_to_trc_func(*args):
'''
Convert c3d to trc
/!\ Only point data are retrieved. Analog data (force plates, emg) and
computed data (angles, powers, etc) will be lost.
Usage:
import c3d_to_trc; c3d_to_trc.c3d_to_trc_func(r'<input_c3d_file>')
c3d_to_trc -i input_c3d_file
c3d_to_trc -i input_c3d_file -o output_c3d_file
'''
try:
c3d_path = args[0]['input'] # invoked with argparse
if args[0]['output'] == None:
trc_path = c3d_path.replace('.c3d', '.trc')
else:
trc_path = args[0]['output']
except:
c3d_path = args[0] # invoked as a function
try:
trc_path = args[1]
except:
trc_path = c3d_path.replace('.c3d', '.trc')
# c3d header
reader = c3d.Reader(open(c3d_path, 'rb'))
items_header = str(reader.header).split('\n')
items_header_list = [item.strip().split(': ') for item in items_header]
label_item = [item[0] for item in items_header_list]
value_item = [item[1] for item in items_header_list]
header_c3d = dict(zip(label_item, value_item))
# unit
for k1 in reader.group_items():
if k1[0]=='POINT':
for k2 in k1[1].param_items():
if k2[0]=='UNITS':
if 'mm' in k2[1].bytes[:].decode('utf-8'):
unit = 'mm'
unit_scale= 0.001
else:
unit = 'm'
unit_scale= 1 # mm
# c3d data: reads 3D points (no analog data) and takes off computed data
labels = reader.point_labels
index_labels_markers = [i for i, s in enumerate(labels) if 'Angle' not in s and 'Power' not in s and 'Force' not in s and 'Moment' not in s and 'GRF' not in s]
labels_markers = [labels[ind] for ind in index_labels_markers]
# trc header
header0_str = 'PathFileType\t4\t(X/Y/Z)\t' + trc_path
header1 = {}
header1['DataRate'] = str(int(float(header_c3d['frame_rate'])))
header1['CameraRate'] = header1['DataRate']
header1['NumFrames'] = str(int(header_c3d['last_frame']) - int(header_c3d['first_frame']) + 1)
header1['NumMarkers'] = str(len(labels_markers))
header1['Units'] = unit
header1['OrigDataRate'] = header1['DataRate']
header1['OrigDataStartFrame'] = header_c3d['first_frame']
header1['OrigNumFrames'] = header1['NumFrames']
header1_str1 = '\t'.join(header1.keys())
header1_str2 = '\t'.join(header1.values())
header2_str1 = 'Frame#\tTime\t' + '\t\t\t'.join([item.strip() for item in labels_markers]) + '\t\t'
header2_str2 = '\t\t'+'\t'.join(['X{i}\tY{i}\tZ{i}'.format(i=i+1) for i in range(int(header1['NumMarkers']))])
header_trc = '\n'.join([header0_str, header1_str1, header1_str2, header2_str1, header2_str2])
with open(trc_path, 'w') as trc_o:
trc_o.write(header_trc+'\n')
# trc data
index_data_markers = np.sort(np.concatenate([np.array(index_labels_markers)*3, np.array(index_labels_markers)*3+1, np.array(index_labels_markers)*3+2]))
t0 = int(float(header_c3d['first_frame'])) / int(float(header_c3d['frame_rate']))
tf = int(float(header_c3d['last_frame'])) / int(float(header_c3d['frame_rate']))
trc_time = np.linspace(t0, tf, num=(int(header_c3d['last_frame']) - int(header_c3d['first_frame']) + 1))
for n, (i, points, _) in enumerate(list(reader.read_frames())):
c3d_line = np.concatenate([item[:3] for item in points])*unit_scale
c3d_line_markers = c3d_line[index_data_markers]
trc_line = '{i}\t{t}\t'.format(i=i, t=trc_time[n]) + '\t'.join(map(str,c3d_line_markers))
trc_o.write(trc_line+'\n')
print(f'Converted c3d file to {trc_path}')
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-i', '--input', required = True, help='c3d input file name')
parser.add_argument('-o', '--output', required=False, help='trc output file name')
args = vars(parser.parse_args())
c3d_to_trc_func(args)