biomechzoo 0.5.9__py3-none-any.whl
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.
- __init__.py +33 -0
- biomechzoo/__init__.py +0 -0
- biomechzoo/__main__.py +6 -0
- biomechzoo/biomech_ops/__init__.py +0 -0
- biomechzoo/biomech_ops/continuous_relative_phase_data.py +31 -0
- biomechzoo/biomech_ops/continuous_relative_phase_line.py +36 -0
- biomechzoo/biomech_ops/filter_data.py +58 -0
- biomechzoo/biomech_ops/filter_line.py +85 -0
- biomechzoo/biomech_ops/movement_onset.py +53 -0
- biomechzoo/biomech_ops/normalize_data.py +36 -0
- biomechzoo/biomech_ops/normalize_line.py +51 -0
- biomechzoo/biomech_ops/phase_angle_data.py +39 -0
- biomechzoo/biomech_ops/phase_angle_line.py +48 -0
- biomechzoo/biomechzoo.py +447 -0
- biomechzoo/conversion/__init__.py +0 -0
- biomechzoo/conversion/c3d2zoo_data.py +95 -0
- biomechzoo/conversion/mvnx2zoo_data.py +113 -0
- biomechzoo/conversion/opencap2zoo_data.py +23 -0
- biomechzoo/conversion/table2zoo_data.py +114 -0
- biomechzoo/imu/__init__.py +0 -0
- biomechzoo/imu/kinematics.py +0 -0
- biomechzoo/imu/tilt_algorithm.py +112 -0
- biomechzoo/linear_algebra_ops/__init__.py +0 -0
- biomechzoo/linear_algebra_ops/compute_magnitude_data.py +43 -0
- biomechzoo/mvn/__init__.py +0 -0
- biomechzoo/mvn/load_mvnx.py +514 -0
- biomechzoo/mvn/main_mvnx.py +75 -0
- biomechzoo/mvn/mvn.py +232 -0
- biomechzoo/mvn/mvnx_file_accessor.py +464 -0
- biomechzoo/processing/__init__.py +0 -0
- biomechzoo/processing/addchannel_data.py +71 -0
- biomechzoo/processing/addevent_data.py +116 -0
- biomechzoo/processing/explodechannel_data.py +69 -0
- biomechzoo/processing/partition_data.py +46 -0
- biomechzoo/processing/removechannel_data.py +46 -0
- biomechzoo/processing/removeevent_data.py +57 -0
- biomechzoo/processing/renamechannel_data.py +79 -0
- biomechzoo/processing/renameevent_data.py +62 -0
- biomechzoo/processing/split_trial_data.py +40 -0
- biomechzoo/statistics/eventval.py +118 -0
- biomechzoo/utils/__init__.py +0 -0
- biomechzoo/utils/batchdisp.py +21 -0
- biomechzoo/utils/compute_sampling_rate_from_time.py +25 -0
- biomechzoo/utils/engine.py +88 -0
- biomechzoo/utils/findfield.py +11 -0
- biomechzoo/utils/get_split_events.py +33 -0
- biomechzoo/utils/peak_sign.py +24 -0
- biomechzoo/utils/set_zoosystem.py +66 -0
- biomechzoo/utils/version.py +5 -0
- biomechzoo/utils/zload.py +57 -0
- biomechzoo/utils/zplot.py +61 -0
- biomechzoo/utils/zsave.py +54 -0
- biomechzoo-0.5.9.dist-info/METADATA +46 -0
- biomechzoo-0.5.9.dist-info/RECORD +58 -0
- biomechzoo-0.5.9.dist-info/WHEEL +5 -0
- biomechzoo-0.5.9.dist-info/entry_points.txt +2 -0
- biomechzoo-0.5.9.dist-info/licenses/LICENSE +21 -0
- biomechzoo-0.5.9.dist-info/top_level.txt +2 -0
biomechzoo/mvn/mvn.py
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
FRAMES_ALL = -1
|
|
2
|
+
|
|
3
|
+
AXIS_ALL = -1
|
|
4
|
+
AXIS_X = 0
|
|
5
|
+
AXIS_Y = 1
|
|
6
|
+
AXIS_Z = 2
|
|
7
|
+
AXIS_W = 3 # The retrieval method will shift indices for w,x,y,z to 0,1,2,3
|
|
8
|
+
|
|
9
|
+
ANGLE_ALL = -1
|
|
10
|
+
|
|
11
|
+
ANGLE_ABDUCTION_ADDUCTION = 0
|
|
12
|
+
ANGLE_RADIAL_ULNAR_DEVIATION = 0
|
|
13
|
+
ANGLE_LATERAL_BENDING = 0
|
|
14
|
+
|
|
15
|
+
ANGLE_INTERNAL_EXTERNAL_ROTATION = 1
|
|
16
|
+
ANGLE_PRONATION_SUPINATION = 1
|
|
17
|
+
ANGLE_AXIAL_ROTATION = 1
|
|
18
|
+
|
|
19
|
+
ANGLE_FLEXION_EXTENSION = 2
|
|
20
|
+
ANGLE_DORSIFLEXION_PLANTARFLEXION = 2
|
|
21
|
+
|
|
22
|
+
SEGMENT_PELVIS = 0
|
|
23
|
+
SEGMENT_L5 = 1
|
|
24
|
+
SEGMENT_L3 = 2
|
|
25
|
+
SEGMENT_T12 = 3
|
|
26
|
+
SEGMENT_T8 = 4
|
|
27
|
+
SEGMENT_NECK = 5
|
|
28
|
+
SEGMENT_HEAD = 6
|
|
29
|
+
SEGMENT_RIGHT_SHOULDER = 7
|
|
30
|
+
SEGMENT_RIGHT_UPPER_ARM = 8
|
|
31
|
+
SEGMENT_RIGHT_FOREARM = 9
|
|
32
|
+
SEGMENT_RIGHT_HAND = 10
|
|
33
|
+
SEGMENT_LEFT_SHOULDER = 11
|
|
34
|
+
SEGMENT_LEFT_UPPER_ARM = 12
|
|
35
|
+
SEGMENT_LEFT_FOREARM = 13
|
|
36
|
+
SEGMENT_LEFT_HAND = 14
|
|
37
|
+
SEGMENT_RIGHT_UPPER_LEG = 15
|
|
38
|
+
SEGMENT_RIGHT_LOWER_LEG = 16
|
|
39
|
+
SEGMENT_RIGHT_FOOT = 17
|
|
40
|
+
SEGMENT_RIGHT_TOE = 18
|
|
41
|
+
SEGMENT_LEFT_UPPER_LEG = 19
|
|
42
|
+
SEGMENT_LEFT_LOWER_LEG = 20
|
|
43
|
+
SEGMENT_LEFT_FOOT = 21
|
|
44
|
+
SEGMENT_LEFT_TOE = 22
|
|
45
|
+
|
|
46
|
+
SEGMENT_CENTER_OF_MASS = 1000
|
|
47
|
+
|
|
48
|
+
SEGMENTS = {SEGMENT_PELVIS: 'Pelvis',
|
|
49
|
+
SEGMENT_L5: 'L5',
|
|
50
|
+
SEGMENT_L3: 'L3',
|
|
51
|
+
SEGMENT_T12: 'T12',
|
|
52
|
+
SEGMENT_T8: 'T8',
|
|
53
|
+
SEGMENT_NECK: 'Neck',
|
|
54
|
+
SEGMENT_HEAD: 'Head',
|
|
55
|
+
SEGMENT_RIGHT_SHOULDER: 'RightShoulder',
|
|
56
|
+
SEGMENT_RIGHT_UPPER_ARM: 'RightUpperArm',
|
|
57
|
+
SEGMENT_RIGHT_FOREARM: 'RightForeArm',
|
|
58
|
+
SEGMENT_RIGHT_HAND: 'RightHand',
|
|
59
|
+
SEGMENT_LEFT_SHOULDER: 'LeftShoulder',
|
|
60
|
+
SEGMENT_LEFT_UPPER_ARM: 'LeftUpperArm',
|
|
61
|
+
SEGMENT_LEFT_FOREARM: 'LeftForeArm',
|
|
62
|
+
SEGMENT_LEFT_HAND: 'LeftHand',
|
|
63
|
+
SEGMENT_RIGHT_UPPER_LEG: 'RightUpperLeg',
|
|
64
|
+
SEGMENT_RIGHT_LOWER_LEG: 'RightLowerLeg',
|
|
65
|
+
SEGMENT_RIGHT_FOOT: 'RightFoot',
|
|
66
|
+
SEGMENT_RIGHT_TOE: 'RightToe',
|
|
67
|
+
SEGMENT_LEFT_UPPER_LEG: 'LeftUpperLeg',
|
|
68
|
+
SEGMENT_LEFT_LOWER_LEG: 'LeftLowerLeg',
|
|
69
|
+
SEGMENT_LEFT_FOOT: 'LeftFoot',
|
|
70
|
+
SEGMENT_LEFT_TOE: 'LeftToe',
|
|
71
|
+
SEGMENT_CENTER_OF_MASS: 'CoM'}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# regular joints
|
|
75
|
+
|
|
76
|
+
JOINT_L5_S1 = 0
|
|
77
|
+
JOINT_L4_L3 = 1
|
|
78
|
+
JOINT_L1_T12 = 2
|
|
79
|
+
JOINT_T9_T8 = 3
|
|
80
|
+
JOINT_T1_C7 = 4
|
|
81
|
+
JOINT_C1_HEAD = 5
|
|
82
|
+
JOINT_RIGHT_T4_SHOULDER = 6
|
|
83
|
+
JOINT_RIGHT_SHOULDER = 7
|
|
84
|
+
JOINT_RIGHT_ELBOW = 8
|
|
85
|
+
JOINT_RIGHT_WRIST = 9
|
|
86
|
+
JOINT_LEFT_T4_SHOULDER = 10
|
|
87
|
+
JOINT_LEFT_SHOULDER = 11
|
|
88
|
+
JOINT_LEFT_ELBOW = 12
|
|
89
|
+
JOINT_LEFT_WRIST = 13
|
|
90
|
+
JOINT_RIGHT_HIP = 14
|
|
91
|
+
JOINT_RIGHT_KNEE = 15
|
|
92
|
+
JOINT_RIGHT_ANKLE = 16
|
|
93
|
+
JOINT_RIGHT_BALL_FOOT = 17
|
|
94
|
+
JOINT_LEFT_HIP = 18
|
|
95
|
+
JOINT_LEFT_KNEE = 19
|
|
96
|
+
JOINT_LEFT_ANKLE = 20
|
|
97
|
+
JOINT_LEFT_BALL_FOOT = 21
|
|
98
|
+
|
|
99
|
+
JOINTS = {JOINT_L5_S1: 'jL5S1',
|
|
100
|
+
JOINT_L4_L3: 'jL4L3',
|
|
101
|
+
JOINT_L1_T12: 'jL1T12',
|
|
102
|
+
JOINT_T9_T8: 'jT9T8',
|
|
103
|
+
JOINT_T1_C7: 'jT1C7',
|
|
104
|
+
JOINT_C1_HEAD: 'jC1Head',
|
|
105
|
+
JOINT_RIGHT_T4_SHOULDER: 'jRightT4Shoulder',
|
|
106
|
+
JOINT_RIGHT_SHOULDER: 'jRightShoulder',
|
|
107
|
+
JOINT_RIGHT_ELBOW: 'jRightElbow',
|
|
108
|
+
JOINT_RIGHT_WRIST: 'jRightWrist',
|
|
109
|
+
JOINT_LEFT_T4_SHOULDER: 'jLeftT4Shoulder',
|
|
110
|
+
JOINT_LEFT_SHOULDER: 'jLeftShoulder',
|
|
111
|
+
JOINT_LEFT_ELBOW: 'jLeftElbow',
|
|
112
|
+
JOINT_LEFT_WRIST: 'jLeftWrist',
|
|
113
|
+
JOINT_RIGHT_HIP: 'jRightHip',
|
|
114
|
+
JOINT_RIGHT_KNEE: 'jRightKnee',
|
|
115
|
+
JOINT_RIGHT_ANKLE: 'jRightAnkle',
|
|
116
|
+
JOINT_RIGHT_BALL_FOOT: 'jRightBallFoot',
|
|
117
|
+
JOINT_LEFT_HIP: 'jLeftHip',
|
|
118
|
+
JOINT_LEFT_KNEE: 'jLeftKnee',
|
|
119
|
+
JOINT_LEFT_ANKLE: 'jLeftAnkle',
|
|
120
|
+
JOINT_LEFT_BALL_FOOT: 'jLeftBallFoot'}
|
|
121
|
+
|
|
122
|
+
PARAMETER_JOINTS = {JOINT_L5_S1: 'j_l5_s1',
|
|
123
|
+
JOINT_L4_L3: 'j_l4_l3',
|
|
124
|
+
JOINT_L1_T12: 'j_l1_t12',
|
|
125
|
+
JOINT_T9_T8: 'j_t9_t8',
|
|
126
|
+
JOINT_T1_C7: 'j_t1_c7',
|
|
127
|
+
JOINT_C1_HEAD: 'j_c1_head',
|
|
128
|
+
JOINT_RIGHT_T4_SHOULDER: 'j_right_t4_shoulder',
|
|
129
|
+
JOINT_RIGHT_SHOULDER: 'j_right_shoulder',
|
|
130
|
+
JOINT_RIGHT_ELBOW: 'j_right_elbow',
|
|
131
|
+
JOINT_RIGHT_WRIST: 'j_right_wrist',
|
|
132
|
+
JOINT_LEFT_T4_SHOULDER: 'j_left_t4_shoulder',
|
|
133
|
+
JOINT_LEFT_SHOULDER: 'j_left_shoulder',
|
|
134
|
+
JOINT_LEFT_ELBOW: 'j_left_elbow',
|
|
135
|
+
JOINT_LEFT_WRIST: 'j_left_wrist',
|
|
136
|
+
JOINT_RIGHT_HIP: 'j_right_hip',
|
|
137
|
+
JOINT_RIGHT_KNEE: 'j_right_knee',
|
|
138
|
+
JOINT_RIGHT_ANKLE: 'j_right_ankle',
|
|
139
|
+
JOINT_RIGHT_BALL_FOOT: 'j_right_ball_foot',
|
|
140
|
+
JOINT_LEFT_HIP: 'j_left_hip',
|
|
141
|
+
JOINT_LEFT_KNEE: 'j_left_knee',
|
|
142
|
+
JOINT_LEFT_ANKLE: 'j_left_ankle',
|
|
143
|
+
JOINT_LEFT_BALL_FOOT: 'j_left_ball_foot'}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
# ergonomic joints
|
|
147
|
+
|
|
148
|
+
ERGO_JOINT_T8_HEAD = 0
|
|
149
|
+
ERGO_JOINT_T8_LEFT_UPPER_ARM = 1
|
|
150
|
+
ERGO_JOINT_T8_RIGHT_UPPER_ARM = 2
|
|
151
|
+
ERGO_JOINT_PELVIS_T8 = 3
|
|
152
|
+
ERGO_JOINT_VERTICAL_PELVIS = 4
|
|
153
|
+
ERGO_JOINT_VERTICAL_T8 = 5
|
|
154
|
+
|
|
155
|
+
ERGO_JOINT_INDICES = {ERGO_JOINT_T8_HEAD,
|
|
156
|
+
ERGO_JOINT_T8_LEFT_UPPER_ARM,
|
|
157
|
+
ERGO_JOINT_T8_RIGHT_UPPER_ARM,
|
|
158
|
+
ERGO_JOINT_PELVIS_T8,
|
|
159
|
+
ERGO_JOINT_VERTICAL_PELVIS,
|
|
160
|
+
ERGO_JOINT_VERTICAL_T8}
|
|
161
|
+
|
|
162
|
+
ERGO_JOINTS = {ERGO_JOINT_T8_HEAD: 'T8_Head',
|
|
163
|
+
ERGO_JOINT_T8_LEFT_UPPER_ARM: 'T8_LeftUpperArm',
|
|
164
|
+
ERGO_JOINT_T8_RIGHT_UPPER_ARM: 'T8_RightUpperArm',
|
|
165
|
+
ERGO_JOINT_PELVIS_T8: 'Pelvis_T8',
|
|
166
|
+
ERGO_JOINT_VERTICAL_PELVIS: 'Vertical_Pelvis',
|
|
167
|
+
ERGO_JOINT_VERTICAL_T8: 'Vertical_T8'}
|
|
168
|
+
|
|
169
|
+
ERGO_PARAMETER_JOINTS = {ERGO_JOINT_T8_HEAD: 't8_head',
|
|
170
|
+
ERGO_JOINT_T8_LEFT_UPPER_ARM: 't8_left_upper_arm',
|
|
171
|
+
ERGO_JOINT_T8_RIGHT_UPPER_ARM: 't8_right_upper_arm',
|
|
172
|
+
ERGO_JOINT_PELVIS_T8: 'pelvis_t8',
|
|
173
|
+
ERGO_JOINT_VERTICAL_PELVIS: 'vertical_p1elvis',
|
|
174
|
+
ERGO_JOINT_VERTICAL_T8: 'vertical_t8'}
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
# foot contacts
|
|
178
|
+
|
|
179
|
+
FOOT_CONTACT_LEFT_HEEL = 1
|
|
180
|
+
FOOT_CONTACT_LEFT_TOE = 2
|
|
181
|
+
FOOT_CONTACT_RIGHT_HEEL = 4
|
|
182
|
+
FOOT_CONTACT_RIGHT_TOE = 8
|
|
183
|
+
|
|
184
|
+
# some points
|
|
185
|
+
|
|
186
|
+
POINT_JOINT_ANKLE = 0
|
|
187
|
+
POINT_JOINT_BALL_FOOT = 1
|
|
188
|
+
POINT_HEEL_FOOT = 2
|
|
189
|
+
POINT_FIRST_METATARSAL = 3
|
|
190
|
+
POINT_FIFTH_METATARSAL = 4
|
|
191
|
+
POINT_PIVOT_FOOT = 5
|
|
192
|
+
POINT_HEEL_CENTER = 6
|
|
193
|
+
POINT_TOP_OF_FOOT = 7
|
|
194
|
+
|
|
195
|
+
POINTS_LEFT_FOOT = {
|
|
196
|
+
POINT_JOINT_ANKLE: 'jLeftAnkle',
|
|
197
|
+
POINT_JOINT_BALL_FOOT: 'jLeftBallFoot',
|
|
198
|
+
POINT_HEEL_FOOT: 'pLeftHeelFoot',
|
|
199
|
+
POINT_FIRST_METATARSAL: 'pLeftFirstMetatarsal',
|
|
200
|
+
POINT_FIFTH_METATARSAL: 'pLeftFifthMetatarsal',
|
|
201
|
+
POINT_PIVOT_FOOT: 'pLeftPivotFoot',
|
|
202
|
+
POINT_HEEL_CENTER: 'pLeftHeelCenter',
|
|
203
|
+
POINT_TOP_OF_FOOT: 'pLeftTopOfFoot',
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
POINTS_RIGHT_FOOT = {
|
|
207
|
+
POINT_JOINT_ANKLE: 'jRightAnkle',
|
|
208
|
+
POINT_JOINT_BALL_FOOT: 'jRightBallFoot',
|
|
209
|
+
POINT_HEEL_FOOT: 'pRightHeelFoot',
|
|
210
|
+
POINT_FIRST_METATARSAL: 'pRightFirstMetatarsal',
|
|
211
|
+
POINT_FIFTH_METATARSAL: 'pRightFifthMetatarsal',
|
|
212
|
+
POINT_PIVOT_FOOT: 'pRightPivotFoot',
|
|
213
|
+
POINT_HEEL_CENTER: 'pRightHeelCenter',
|
|
214
|
+
POINT_TOP_OF_FOOT: 'pRightTopOfFoot',
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
# Toe
|
|
218
|
+
# POINT_JOINT_BALL_FOOT = 0 # overlaps with foot segment
|
|
219
|
+
POINT_TOE = 1
|
|
220
|
+
POINT_JOINT_TOE = 2
|
|
221
|
+
|
|
222
|
+
POINTS_LEFT_TOE = {
|
|
223
|
+
# POINT_JOINT_BALL_FOOT: 'jLeftBallFoot',
|
|
224
|
+
POINT_TOE: 'pLeftToe',
|
|
225
|
+
POINT_JOINT_TOE: 'jLeftToe',
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
POINTS_RIGHT_TOE = {
|
|
229
|
+
# POINT_JOINT_BALL_FOOT: 'jRightBallFoot',
|
|
230
|
+
POINT_TOE: 'pRightToe',
|
|
231
|
+
POINT_JOINT_TOE: 'jRightToe',
|
|
232
|
+
}
|
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
from biomechzoo.mvn import mvn
|
|
2
|
+
import warnings
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class MvnxFileAccessor:
|
|
6
|
+
|
|
7
|
+
@property
|
|
8
|
+
def original_file_name(self):
|
|
9
|
+
return self.file_data['meta_data']['original_filename']
|
|
10
|
+
|
|
11
|
+
@property
|
|
12
|
+
def actor_name(self):
|
|
13
|
+
return self.file_data['meta_data']['name']
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def actor_color(self):
|
|
17
|
+
return self.file_data['meta_data']['color']
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def profile(self):
|
|
21
|
+
return self.file_data['meta_data']['scenario']
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def configuration(self):
|
|
25
|
+
return self.file_data['meta_data']['configuration']
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def comments(self):
|
|
29
|
+
return self.file_data['meta_data']['comments']
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def quality(self):
|
|
33
|
+
return self.file_data['meta_data']['quality']
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def frame_count(self):
|
|
37
|
+
return self._last_frame - self._first_frame
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def segment_count(self):
|
|
41
|
+
return self.file_data['frames']['segment_count']
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def joint_count(self):
|
|
45
|
+
return self.file_data['frames']['joint_count']
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def finger_joint_count(self):
|
|
49
|
+
return self.file_data['frames']['finger_joint_count']
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def ergo_joint_count(self):
|
|
53
|
+
ergo_joint_count = len(self.file_data['ergo_joints']) if self.file_data['ergo_joints'] is not None else None
|
|
54
|
+
return ergo_joint_count # 'ergoJointCount' non-existing in mvnx
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def sensor_count(self):
|
|
58
|
+
return self.file_data['frames']['sensor_count']
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def frame_rate(self) -> int:
|
|
62
|
+
if 'sample_rate' in self.file_data['meta_data']:
|
|
63
|
+
return int(self.file_data['meta_data']['sample_rate'])
|
|
64
|
+
else:
|
|
65
|
+
warnings.warn('Using default sample rate of 240')
|
|
66
|
+
return 240
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def recording_date(self) -> str:
|
|
70
|
+
return self.file_data['meta_data']['rec_date']
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def version(self):
|
|
74
|
+
return self.file_data['meta_data']['version']
|
|
75
|
+
|
|
76
|
+
def __init__(self):
|
|
77
|
+
self.file_data = {}
|
|
78
|
+
self._all_frames_slice = None
|
|
79
|
+
self._first_frame = 0
|
|
80
|
+
self._last_frame = 0
|
|
81
|
+
self._index_to_segment = {}
|
|
82
|
+
|
|
83
|
+
def create_index_to_segment_dict(self):
|
|
84
|
+
segment_index = 0
|
|
85
|
+
for _, segment in self.file_data['segments']['elements'].items():
|
|
86
|
+
if 'label' in segment:
|
|
87
|
+
self._index_to_segment[segment_index] = segment['label']
|
|
88
|
+
segment_index += 1
|
|
89
|
+
|
|
90
|
+
def set_frame_window(self, first_frame, last_frame):
|
|
91
|
+
self._first_frame = first_frame
|
|
92
|
+
self._last_frame = last_frame
|
|
93
|
+
self._all_frames_slice = slice(self._first_frame, self._last_frame)
|
|
94
|
+
|
|
95
|
+
def reset_frame_window(self):
|
|
96
|
+
self._first_frame = 0
|
|
97
|
+
self._last_frame = len(self.file_data['frames']['segment_data'])
|
|
98
|
+
self._all_frames_slice = slice(self._first_frame, self._last_frame)
|
|
99
|
+
|
|
100
|
+
def window_profile(self):
|
|
101
|
+
"""
|
|
102
|
+
This method determines the filter profile (aka scenario) for the currently selected window on the
|
|
103
|
+
data.
|
|
104
|
+
:return: The profile name (singleLevel, multiLevel, ...) or 'mixed' if different profiles
|
|
105
|
+
ere applied to the window.
|
|
106
|
+
"""
|
|
107
|
+
if 'profiles' not in self.file_data['meta_data']:
|
|
108
|
+
return self.profile
|
|
109
|
+
else:
|
|
110
|
+
profiles = set()
|
|
111
|
+
for profile_spec in self.file_data['meta_data']['profiles']:
|
|
112
|
+
if profile_spec[1] > self._first_frame and profile_spec[0] <= self._last_frame:
|
|
113
|
+
profiles.add(profile_spec[2])
|
|
114
|
+
|
|
115
|
+
if len(profiles) == 1:
|
|
116
|
+
return profiles.pop()
|
|
117
|
+
else:
|
|
118
|
+
return 'mixed'
|
|
119
|
+
|
|
120
|
+
def frame_to_mapped_slice(self, frame) -> (slice, bool):
|
|
121
|
+
# convert the frame parameter to a slice that is mapped to the current view on the file
|
|
122
|
+
single_frame = False
|
|
123
|
+
if not isinstance(frame, slice):
|
|
124
|
+
if frame == mvn.FRAMES_ALL:
|
|
125
|
+
# all frames slice already is mapped to the current view
|
|
126
|
+
self.reset_frame_window()
|
|
127
|
+
frame = self._all_frames_slice # use the prepared 'all frames' slice
|
|
128
|
+
else:
|
|
129
|
+
# for a single frame, map the frame to the current view on all data by adding the virtual first frame
|
|
130
|
+
frame = slice(self._first_frame + frame, self._first_frame + frame + 1) # create a single frame slice
|
|
131
|
+
single_frame = True
|
|
132
|
+
else:
|
|
133
|
+
# shift the slice to the current virtual 'view'
|
|
134
|
+
start = frame.start + self._first_frame
|
|
135
|
+
if frame.stop:
|
|
136
|
+
stop = frame.stop + self._first_frame
|
|
137
|
+
else: # a slice with end given as None implies end at last frame
|
|
138
|
+
stop = self._last_frame
|
|
139
|
+
step = frame.step
|
|
140
|
+
frame = slice(start, stop, step)
|
|
141
|
+
|
|
142
|
+
return frame, single_frame
|
|
143
|
+
|
|
144
|
+
def segment_name_from_index(self, segment_index):
|
|
145
|
+
return self._index_to_segment[segment_index]
|
|
146
|
+
|
|
147
|
+
def point_name_from_indices(self, segment_index, point_index):
|
|
148
|
+
segment_name = self.segment_name_from_index(segment_index)
|
|
149
|
+
segment = self.file_data['segments']['elements'][segment_name]
|
|
150
|
+
return segment['info']['point_label_from_index'][point_index]
|
|
151
|
+
|
|
152
|
+
""" Pose methods """
|
|
153
|
+
|
|
154
|
+
def identity_pose_is_valid(self):
|
|
155
|
+
return ('identity' in self.file_data) and \
|
|
156
|
+
(self.identity_pose()['segments_counts'] > 0)
|
|
157
|
+
|
|
158
|
+
def identity_pose_segment_pos(self, segment):
|
|
159
|
+
return self.identity_pose()['segments'][segment]['pos_g']
|
|
160
|
+
|
|
161
|
+
def identity_pose_segment_ori(self, segment):
|
|
162
|
+
return self.identity_pose()['segments'][segment]['q_gb']
|
|
163
|
+
|
|
164
|
+
def t_pose_is_valid(self):
|
|
165
|
+
return ('tpose' in self.file_data) and \
|
|
166
|
+
(self.t_pose()['segments_counts'] > 0)
|
|
167
|
+
|
|
168
|
+
def t_pose_segment_pos(self, segment):
|
|
169
|
+
return self.t_pose()['segments'][segment]['pos_g']
|
|
170
|
+
|
|
171
|
+
def t_pose_segment_ori(self, segment):
|
|
172
|
+
return self.t_pose()['segments'][segment]['q_gb']
|
|
173
|
+
|
|
174
|
+
def identity_pose(self):
|
|
175
|
+
return self.file_data['identity']
|
|
176
|
+
|
|
177
|
+
def t_pose(self):
|
|
178
|
+
return self.file_data['tpose']
|
|
179
|
+
|
|
180
|
+
""" Segment methods """
|
|
181
|
+
|
|
182
|
+
def get_segment_pos(self, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
|
|
183
|
+
"""
|
|
184
|
+
Get the position information for a segment
|
|
185
|
+
|
|
186
|
+
:param segment: The index of the segment to return the data for (Mvn.SEGMENT_.... )
|
|
187
|
+
:param frame: Can be the index of the frame to return, a slice to return a range of frames
|
|
188
|
+
or Mvn.FRAMES_ALL (default) to return all frames
|
|
189
|
+
:param axis: The frame number to return the data for (Mvn.AXIS_... ALL for all axes)
|
|
190
|
+
:return: A single value, list, or list of lists with position values
|
|
191
|
+
"""
|
|
192
|
+
|
|
193
|
+
return self.get_segment_data('pos', segment, frame, axis)
|
|
194
|
+
|
|
195
|
+
def get_segment_ori(self, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
|
|
196
|
+
"""
|
|
197
|
+
Get the orientation information for a segment
|
|
198
|
+
|
|
199
|
+
:param segment: The index of the segment to return the data for (Mvn.SEGMENT_.... )
|
|
200
|
+
:param frame: Can be the index of the frame to return, a slice to return a range of frames
|
|
201
|
+
or Mvn.FRAMES_ALL (default) to return all frames
|
|
202
|
+
:param axis: The frame number to return the data for (Mvn.AXIS_... ALL for all axes)
|
|
203
|
+
:return: A single value, list, or list of lists with orientation values
|
|
204
|
+
"""
|
|
205
|
+
|
|
206
|
+
# For orientation data, if all axes requested, return all. If specific axis requested, shift index so that w,
|
|
207
|
+
# x,y,z becomes 0,1,2,3
|
|
208
|
+
axis = (axis + 1) % 4 if axis != mvn.AXIS_ALL else axis
|
|
209
|
+
return self.get_segment_data('ori', segment, frame, axis)
|
|
210
|
+
|
|
211
|
+
def get_segment_point_pos(self, segment, point):
|
|
212
|
+
segment_name = mvn.SEGMENTS[segment]
|
|
213
|
+
segment_info = self.file_data['segments'][segment_name]
|
|
214
|
+
points = segment_info['info']['point_label_from_index']
|
|
215
|
+
point_name = points[point]
|
|
216
|
+
return segment_info['points_mvn'][point_name]
|
|
217
|
+
|
|
218
|
+
def get_point_pos(self, segment, point):
|
|
219
|
+
segment_name = mvn.SEGMENTS[segment]
|
|
220
|
+
|
|
221
|
+
if segment_name == 'LeftFoot':
|
|
222
|
+
point_name = mvn.POINTS_LEFT_FOOT[point]
|
|
223
|
+
elif segment_name == 'RightFoot':
|
|
224
|
+
point_name = mvn.POINTS_RIGHT_FOOT[point]
|
|
225
|
+
elif segment_name == 'LeftToe':
|
|
226
|
+
point_name = mvn.POINTS_LEFT_TOE[point]
|
|
227
|
+
elif segment_name == 'RightToe':
|
|
228
|
+
point_name = mvn.POINTS_RIGHT_TOE[point]
|
|
229
|
+
|
|
230
|
+
return self.file_data['segments'][segment_name]['points_mvn'][point_name]
|
|
231
|
+
|
|
232
|
+
def get_segment_vel(self, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
|
|
233
|
+
"""
|
|
234
|
+
Get the local velocity information for a segment
|
|
235
|
+
|
|
236
|
+
:param segment: The index of the segment to return the data for (Mvn.SEGMENT_.... )
|
|
237
|
+
:param frame: Can be the index of the frame to return, a slice to return a range of frames
|
|
238
|
+
or Mvn.FRAMES_ALL (default) to return all frames
|
|
239
|
+
:param axis: The frame number to return the data for (Mvn.AXIS_... ALL for all axes)
|
|
240
|
+
:return: A single value, list, or list of lists with velocity values
|
|
241
|
+
"""
|
|
242
|
+
|
|
243
|
+
return self.get_segment_data('vel', segment, frame, axis)
|
|
244
|
+
|
|
245
|
+
def get_segment_acc(self, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
|
|
246
|
+
"""
|
|
247
|
+
Get the acceleration information for a segment
|
|
248
|
+
|
|
249
|
+
:param segment: The index of the segment to return the data for (Mvn.SEGMENT_.... )
|
|
250
|
+
:param frame: Can be the index of the frame to return, a slice to return a range of frames
|
|
251
|
+
or Mvn.FRAMES_ALL (default) to return all frames
|
|
252
|
+
:param axis: The frame number to return the data for (Mvn.AXIS_... ALL for all axes)
|
|
253
|
+
:return: A single value, list, or list of lists with acceleration values
|
|
254
|
+
"""
|
|
255
|
+
|
|
256
|
+
return self.get_segment_data('acc', segment, frame, axis)
|
|
257
|
+
|
|
258
|
+
def get_segment_angular_vel(self, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
|
|
259
|
+
"""
|
|
260
|
+
Get the acceleration information for a segment
|
|
261
|
+
|
|
262
|
+
:param segment: The index of the segment to return the data for (Mvn.SEGMENT_.... )
|
|
263
|
+
:param frame: Can be the index of the frame to return, a slice to return a range of frames
|
|
264
|
+
or Mvn.FRAMES_ALL (default) to return all frames
|
|
265
|
+
:param axis: The frame number to return the data for (Mvn.AXIS_... ALL for all axes)
|
|
266
|
+
:return: A single value, list, or list of lists with angular velocity values
|
|
267
|
+
"""
|
|
268
|
+
|
|
269
|
+
return self.get_segment_data('ang_vel', segment, frame, axis)
|
|
270
|
+
|
|
271
|
+
def get_segment_angular_acc(self, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
|
|
272
|
+
"""
|
|
273
|
+
Get the acceleration information for a segment
|
|
274
|
+
|
|
275
|
+
:param segment: The index of the segment to return the data for (Mvn.SEGMENT_.... )
|
|
276
|
+
:param frame: Can be the index of the frame to return, a slice to return a range of frames
|
|
277
|
+
or Mvn.FRAMES_ALL (default) to return all frames
|
|
278
|
+
:param axis: The frame number to return the data for (Mvn.AXIS_... ALL for all axes)
|
|
279
|
+
:return: A single value, list, or list of lists with acceleration values
|
|
280
|
+
"""
|
|
281
|
+
|
|
282
|
+
return self.get_segment_data('ang_acc', segment, frame, axis)
|
|
283
|
+
|
|
284
|
+
def get_segment_data(self, data_field, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
|
|
285
|
+
return self.get_data('segment_data', data_field, segment, frame, axis)
|
|
286
|
+
|
|
287
|
+
""" Joint methods """
|
|
288
|
+
|
|
289
|
+
def get_joint_angle(self, joint, frame=mvn.FRAMES_ALL, angle=mvn.ANGLE_ALL):
|
|
290
|
+
joint_name = mvn.JOINTS[joint]
|
|
291
|
+
data_set = 'joint_data'
|
|
292
|
+
|
|
293
|
+
frame, is_single_frame = self.frame_to_mapped_slice(frame)
|
|
294
|
+
|
|
295
|
+
if angle == mvn.ANGLE_ALL:
|
|
296
|
+
return_values = [value[joint_name] for value in self.file_data['frames'][data_set][frame]]
|
|
297
|
+
else:
|
|
298
|
+
return_values = [value[joint_name][angle] for value in self.file_data['frames'][data_set][frame]]
|
|
299
|
+
|
|
300
|
+
return return_values[0] if is_single_frame else return_values
|
|
301
|
+
|
|
302
|
+
def get_joint_angle_xzy(self, joint, frame=mvn.FRAMES_ALL, angle=mvn.ANGLE_ALL):
|
|
303
|
+
joint_name = mvn.JOINTS[joint]
|
|
304
|
+
data_set = 'joint_data_xzy'
|
|
305
|
+
|
|
306
|
+
frame, is_single_frame = self.frame_to_mapped_slice(frame)
|
|
307
|
+
|
|
308
|
+
if angle == mvn.ANGLE_ALL:
|
|
309
|
+
return_values = [value[joint_name] for value in self.file_data['frames'][data_set][frame]]
|
|
310
|
+
else:
|
|
311
|
+
return_values = [value[joint_name][angle] for value in self.file_data['frames'][data_set][frame]]
|
|
312
|
+
|
|
313
|
+
return return_values[0] if is_single_frame else return_values
|
|
314
|
+
|
|
315
|
+
def get_ergo_joint_angle(self, joint, frame=mvn.FRAMES_ALL, angle=mvn.ANGLE_ALL):
|
|
316
|
+
joint_name = mvn.ERGO_JOINTS[joint]
|
|
317
|
+
data_set = 'ergo_joint_data'
|
|
318
|
+
|
|
319
|
+
frame, is_single_frame = self.frame_to_mapped_slice(frame)
|
|
320
|
+
|
|
321
|
+
if angle == mvn.ANGLE_ALL:
|
|
322
|
+
return_values = [value[joint_name] for value in self.file_data['frames'][data_set][frame]]
|
|
323
|
+
else:
|
|
324
|
+
return_values = [value[joint_name][angle] for value in self.file_data['frames'][data_set][frame]]
|
|
325
|
+
|
|
326
|
+
return return_values[0] if is_single_frame else return_values
|
|
327
|
+
|
|
328
|
+
""" Center of Mass methods """
|
|
329
|
+
|
|
330
|
+
def get_center_of_mass_pos(self, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
|
|
331
|
+
"""
|
|
332
|
+
Get the position information for center of mass
|
|
333
|
+
|
|
334
|
+
:param frame: Can be the index of the frame to return, a slice to return a range of frames
|
|
335
|
+
or Mvn.FRAMES_ALL (default) to return all frames
|
|
336
|
+
:param axis: The axis to return the data for (Mvn.AXIS_... ALL for all axes)
|
|
337
|
+
:return: A single value, list, or list of lists with position values
|
|
338
|
+
"""
|
|
339
|
+
|
|
340
|
+
return self.get_segment_data('pos', mvn.SEGMENT_CENTER_OF_MASS, frame, axis)
|
|
341
|
+
|
|
342
|
+
def get_center_of_mass_vel(self, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
|
|
343
|
+
"""
|
|
344
|
+
Get the velocity information for center of mass
|
|
345
|
+
|
|
346
|
+
:param frame: Can be the index of the frame to return, a slice to return a range of frames
|
|
347
|
+
or Mvn.FRAMES_ALL (default) to return all frames
|
|
348
|
+
:param axis: The axis to return the data for (Mvn.AXIS_... ALL for all axes)
|
|
349
|
+
:return: A single value, list, or list of lists with position values
|
|
350
|
+
"""
|
|
351
|
+
|
|
352
|
+
return self.get_segment_data('vel', mvn.SEGMENT_CENTER_OF_MASS, frame, axis)
|
|
353
|
+
|
|
354
|
+
def get_center_of_mass_acc(self, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
|
|
355
|
+
"""
|
|
356
|
+
Get the acceleration information for center of mass
|
|
357
|
+
|
|
358
|
+
:param frame: Can be the index of the frame to return, a slice to return a range of frames
|
|
359
|
+
or Mvn.FRAMES_ALL (default) to return all frames
|
|
360
|
+
:param axis: The axis to return the data for (Mvn.AXIS_... ALL for all axes)
|
|
361
|
+
:return: A single value, list, or list of lists with position values
|
|
362
|
+
"""
|
|
363
|
+
|
|
364
|
+
return self.get_segment_data('acc', mvn.SEGMENT_CENTER_OF_MASS, frame, axis)
|
|
365
|
+
|
|
366
|
+
""" Sensor methods """
|
|
367
|
+
|
|
368
|
+
def get_sensor_ori(self, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
|
|
369
|
+
"""
|
|
370
|
+
Get the orientation information for a sensor
|
|
371
|
+
|
|
372
|
+
:param segment: The index of the segment to return the sensor data for (Mvn.SEGMENT_.... )
|
|
373
|
+
:param frame: Can be the index of the frame to return, a slice to return a range of frames
|
|
374
|
+
or Mvn.FRAMES_ALL (default) to return all frames
|
|
375
|
+
:param axis: The frame number to return the data for (Mvn.AXIS_... ALL for all axes)
|
|
376
|
+
:return: A single value, list, or list of lists with orientation values
|
|
377
|
+
"""
|
|
378
|
+
|
|
379
|
+
# if all axes requested, return all. If specific axis requested, shift index so that w,x,y,z becomes 0,1,2,3
|
|
380
|
+
axis = (axis + 1) % 4 if axis != mvn.AXIS_ALL else axis
|
|
381
|
+
return self.get_sensor_data('ori', segment, frame, axis)
|
|
382
|
+
|
|
383
|
+
def get_sensor_free_acc(self, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
|
|
384
|
+
"""
|
|
385
|
+
Get the free acceleration information for a sensor
|
|
386
|
+
|
|
387
|
+
:param segment: The index of the segment to return the sensor data for (Mvn.SEGMENT_.... )
|
|
388
|
+
:param frame: Can be the index of the frame to return, a slice to return a range of frames
|
|
389
|
+
or Mvn.FRAMES_ALL (default) to return all frames
|
|
390
|
+
:param axis: The frame number to return the data for (Mvn.AXIS_... ALL for all axes)
|
|
391
|
+
:return: A single value, list, or list of lists with acceleration values
|
|
392
|
+
"""
|
|
393
|
+
|
|
394
|
+
return self.get_sensor_data('acc', segment, frame, axis)
|
|
395
|
+
|
|
396
|
+
def get_sensor_data(self, data_field, sensor_segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
|
|
397
|
+
return self.get_data('sensor_data', data_field, sensor_segment, frame, axis)
|
|
398
|
+
|
|
399
|
+
""" Contact methods """
|
|
400
|
+
|
|
401
|
+
def get_foot_contacts(self, frame):
|
|
402
|
+
"""
|
|
403
|
+
Get the contacts for a frame
|
|
404
|
+
:param frame: The frame, or a range of frames to retrieve the contacts for.
|
|
405
|
+
:return: The contacts
|
|
406
|
+
"""
|
|
407
|
+
frame, is_single_frame = self.frame_to_mapped_slice(frame)
|
|
408
|
+
return_values = self.file_data['frames']['contacts_data'][frame] #edited Phil Dixon
|
|
409
|
+
return return_values[0] if is_single_frame else return_values
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def has_foot_contact(self, frame, foot_contact_flags=0):
|
|
413
|
+
"""
|
|
414
|
+
Find out if the frame has a contact, optionally for a specific segment/point combo
|
|
415
|
+
|
|
416
|
+
:param frame: The frame (or range) to retrieve the contacts for.
|
|
417
|
+
:param foot_contact_flags: The specific contact to check for:
|
|
418
|
+
mvn.FOOT_CONTACT_LEFT_HEEL,
|
|
419
|
+
mvn.FOOT_CONTACT_LEFT_TOE,
|
|
420
|
+
mvn.FOOT_CONTACT_RIGHT_HEEL or
|
|
421
|
+
mvn.FOOT_CONTACT_RIGHT_TOE
|
|
422
|
+
|
|
423
|
+
It is possible to combine contacts by summing the values, eg:
|
|
424
|
+
mvn.FOOT_CONTACT_LEFT_HEEL + mvn.FOOT_CONTACT_LEFT_TOE
|
|
425
|
+
This will return a contact if either of the flags has a contact
|
|
426
|
+
|
|
427
|
+
Passing 0 (or nothing) will return True if there is any contact
|
|
428
|
+
|
|
429
|
+
:return: Per frame True if a contact was found, False otherwise.
|
|
430
|
+
"""
|
|
431
|
+
frame_contacts = self.get_foot_contacts(frame) # frame will be shifted in the called method
|
|
432
|
+
|
|
433
|
+
if isinstance(frame_contacts, int):
|
|
434
|
+
if foot_contact_flags == 0:
|
|
435
|
+
return frame_contacts > 0
|
|
436
|
+
else:
|
|
437
|
+
return True if (frame_contacts & foot_contact_flags) > 0 else False
|
|
438
|
+
else:
|
|
439
|
+
has_contacts = []
|
|
440
|
+
for contacts in frame_contacts:
|
|
441
|
+
if foot_contact_flags == 0:
|
|
442
|
+
has_contacts.append(frame_contacts > 0)
|
|
443
|
+
else:
|
|
444
|
+
has_contacts.append(True if (contacts & foot_contact_flags) > 0 else False)
|
|
445
|
+
return has_contacts
|
|
446
|
+
|
|
447
|
+
""" Generic methods """
|
|
448
|
+
|
|
449
|
+
def get_data(self, data_set, data_field, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
|
|
450
|
+
if segment == -1:
|
|
451
|
+
segment_name = 'com'
|
|
452
|
+
else:
|
|
453
|
+
segment_name = mvn.SEGMENTS[segment]
|
|
454
|
+
|
|
455
|
+
frame, is_single_frame = self.frame_to_mapped_slice(frame)
|
|
456
|
+
if data_set == 'joint_data':
|
|
457
|
+
return_values = [value[data_field] for value in self.file_data['frames'][data_set][frame]]
|
|
458
|
+
elif axis == mvn.AXIS_ALL:
|
|
459
|
+
return_values = [value[segment_name][data_field] for value in self.file_data['frames'][data_set][frame]]
|
|
460
|
+
else:
|
|
461
|
+
return_values = [value[segment_name][data_field][axis] for value in
|
|
462
|
+
self.file_data['frames'][data_set][frame]]
|
|
463
|
+
|
|
464
|
+
return return_values[0] if is_single_frame else return_values
|
|
File without changes
|