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.
Files changed (58) hide show
  1. __init__.py +33 -0
  2. biomechzoo/__init__.py +0 -0
  3. biomechzoo/__main__.py +6 -0
  4. biomechzoo/biomech_ops/__init__.py +0 -0
  5. biomechzoo/biomech_ops/continuous_relative_phase_data.py +31 -0
  6. biomechzoo/biomech_ops/continuous_relative_phase_line.py +36 -0
  7. biomechzoo/biomech_ops/filter_data.py +58 -0
  8. biomechzoo/biomech_ops/filter_line.py +85 -0
  9. biomechzoo/biomech_ops/movement_onset.py +53 -0
  10. biomechzoo/biomech_ops/normalize_data.py +36 -0
  11. biomechzoo/biomech_ops/normalize_line.py +51 -0
  12. biomechzoo/biomech_ops/phase_angle_data.py +39 -0
  13. biomechzoo/biomech_ops/phase_angle_line.py +48 -0
  14. biomechzoo/biomechzoo.py +447 -0
  15. biomechzoo/conversion/__init__.py +0 -0
  16. biomechzoo/conversion/c3d2zoo_data.py +95 -0
  17. biomechzoo/conversion/mvnx2zoo_data.py +113 -0
  18. biomechzoo/conversion/opencap2zoo_data.py +23 -0
  19. biomechzoo/conversion/table2zoo_data.py +114 -0
  20. biomechzoo/imu/__init__.py +0 -0
  21. biomechzoo/imu/kinematics.py +0 -0
  22. biomechzoo/imu/tilt_algorithm.py +112 -0
  23. biomechzoo/linear_algebra_ops/__init__.py +0 -0
  24. biomechzoo/linear_algebra_ops/compute_magnitude_data.py +43 -0
  25. biomechzoo/mvn/__init__.py +0 -0
  26. biomechzoo/mvn/load_mvnx.py +514 -0
  27. biomechzoo/mvn/main_mvnx.py +75 -0
  28. biomechzoo/mvn/mvn.py +232 -0
  29. biomechzoo/mvn/mvnx_file_accessor.py +464 -0
  30. biomechzoo/processing/__init__.py +0 -0
  31. biomechzoo/processing/addchannel_data.py +71 -0
  32. biomechzoo/processing/addevent_data.py +116 -0
  33. biomechzoo/processing/explodechannel_data.py +69 -0
  34. biomechzoo/processing/partition_data.py +46 -0
  35. biomechzoo/processing/removechannel_data.py +46 -0
  36. biomechzoo/processing/removeevent_data.py +57 -0
  37. biomechzoo/processing/renamechannel_data.py +79 -0
  38. biomechzoo/processing/renameevent_data.py +62 -0
  39. biomechzoo/processing/split_trial_data.py +40 -0
  40. biomechzoo/statistics/eventval.py +118 -0
  41. biomechzoo/utils/__init__.py +0 -0
  42. biomechzoo/utils/batchdisp.py +21 -0
  43. biomechzoo/utils/compute_sampling_rate_from_time.py +25 -0
  44. biomechzoo/utils/engine.py +88 -0
  45. biomechzoo/utils/findfield.py +11 -0
  46. biomechzoo/utils/get_split_events.py +33 -0
  47. biomechzoo/utils/peak_sign.py +24 -0
  48. biomechzoo/utils/set_zoosystem.py +66 -0
  49. biomechzoo/utils/version.py +5 -0
  50. biomechzoo/utils/zload.py +57 -0
  51. biomechzoo/utils/zplot.py +61 -0
  52. biomechzoo/utils/zsave.py +54 -0
  53. biomechzoo-0.5.9.dist-info/METADATA +46 -0
  54. biomechzoo-0.5.9.dist-info/RECORD +58 -0
  55. biomechzoo-0.5.9.dist-info/WHEEL +5 -0
  56. biomechzoo-0.5.9.dist-info/entry_points.txt +2 -0
  57. biomechzoo-0.5.9.dist-info/licenses/LICENSE +21 -0
  58. biomechzoo-0.5.9.dist-info/top_level.txt +2 -0
@@ -0,0 +1,514 @@
1
+ """
2
+ Script to load an mvnx
3
+
4
+ """
5
+
6
+ import xml.etree.ElementTree as ET
7
+ import collections
8
+ import numpy as np
9
+ from biomechzoo.mvn.mvnx_file_accessor import MvnxFileAccessor
10
+ from biomechzoo.mvn import mvn
11
+
12
+ # Xml namespace for mvnx files
13
+ ns = {'mvn': 'http://www.xsens.com/mvn/mvnx'}
14
+
15
+ # Map for easier conversion of foot contacts
16
+ FOOT_CONTACT_MAP = {'LeftFoot_Heel': {'type': 1, 'segment_index': mvn.SEGMENT_LEFT_FOOT, 'point_index': 2},
17
+ 'LeftFoot_Toe': {'type': 1, 'segment_index': mvn.SEGMENT_LEFT_TOE, 'point_index': 1},
18
+ 'RightFoot_Heel': {'type': 1, 'segment_index': mvn.SEGMENT_RIGHT_FOOT, 'point_index': 2},
19
+ 'RightFoot_Toe': {'type': 1, 'segment_index': mvn.SEGMENT_RIGHT_TOE, 'point_index': 1}}
20
+
21
+
22
+ def load_mvnx(file_name):
23
+ """
24
+ This function opens and reads the file as an mvnx formatted XML file
25
+
26
+ :param file_name: Name of the file to open, must have full path and .mvnx extension
27
+ :returns: A dictionary with the data from the mvnx file
28
+ """
29
+
30
+ mvnx_file = MvnxFileAccessor()
31
+ init_file_data(mvnx_file)
32
+ tree = ET.parse(file_name)
33
+ root = tree.getroot()
34
+
35
+ # Get the version
36
+ mvnx_file.file_data['meta_data']['version'] = root.get('version')
37
+
38
+ # Find the comment element
39
+ comment_element = root.find('mvn:comment', ns)
40
+ if comment_element is not None:
41
+ mvnx_file.file_data['meta_data']['comments'] = comment_element.text
42
+
43
+ # Find the subject element
44
+ subject_element = root.find('mvn:subject', ns)
45
+ mvnx_file.file_data['meta_data']['name'] = subject_element.get('label')
46
+ mvnx_file.file_data['meta_data']['color'] = subject_element.get('torsoColor')
47
+ mvnx_file.file_data['meta_data']['sample_rate'] = subject_element.get('frameRate')
48
+ mvnx_file.file_data['meta_data']['rec_date'] = subject_element.get('recDate')
49
+ mvnx_file.file_data['meta_data']['original_filename'] = subject_element.get('originalFilename')
50
+ mvnx_file.file_data['meta_data']['configuration'] = subject_element.get('configuration')
51
+ mvnx_file.file_data['meta_data']['scenario'] = subject_element.get('userScenario')
52
+ mvnx_file.file_data['meta_data']['quality'] = subject_element.get('processingQuality')
53
+
54
+ # Parse the segments and their points
55
+ segments_element = subject_element.find('mvn:segments', ns)
56
+ segment_elements = segments_element.findall('mvn:segment', ns)
57
+ mvnx_file.file_data['segments'] = parse_segments(segment_elements)
58
+ mvnx_file.create_index_to_segment_dict() # for later convenience on retrieving segment names
59
+
60
+ # Parse sensor information
61
+ sensors_element = subject_element.find('mvn:sensors', ns)
62
+ if sensors_element is not None:
63
+ mvnx_file.file_data['sensors'] = parse_sensor(sensors_element, mvnx_file.file_data['segments']['names'])
64
+
65
+ # Parse joint information
66
+ joints_element = subject_element.find('mvn:joints', ns)
67
+ if joints_element is not None:
68
+ mvnx_file.file_data['joints'] = parse_joints(joints_element, mvnx_file.file_data['segments'])
69
+
70
+ # Parse ergo joint information
71
+ ergo_joints_element = subject_element.find('mvn:ergonomicJointAngles', ns)
72
+ if ergo_joints_element is not None:
73
+ mvnx_file.file_data['ergo_joints'] = parse_ergo_joints(ergo_joints_element)
74
+
75
+ # Parse foot contact
76
+ foot_contact_definitions_element = subject_element.find('mvn:footContactDefinition', ns)
77
+ if foot_contact_definitions_element is not None:
78
+ foot_contact_definition_elements = foot_contact_definitions_element.findall('mvn:contactDefinition', ns)
79
+ for foot_contact_definition_element in foot_contact_definition_elements:
80
+ contact_label = foot_contact_definition_element.get('label')
81
+ contact_index = int(foot_contact_definition_element.get('index'))
82
+ mvnx_file.file_data['foot_contact_def'][contact_index] = FOOT_CONTACT_MAP[contact_label]
83
+
84
+ # Parse the finger segments and their points
85
+ for side in mvnx_file.file_data['finger_segments']['elements']:
86
+ finger_segment_elements = subject_element.find('mvn:fingerTrackingSegments' + side.capitalize(), ns)
87
+ if finger_segment_elements is not None:
88
+ finger_segments = parse_segments(finger_segment_elements)
89
+ mvnx_file.file_data['finger_segments']['elements'][side] = finger_segments['elements']
90
+ mvnx_file.file_data['finger_segments']['names'][side] = finger_segments['names']
91
+
92
+ # Parse finger joint information
93
+ for side in mvnx_file.file_data['finger_joints']['elements']:
94
+ finger_joints_element = subject_element.find('mvn:fingerTrackingJoints' + side.capitalize(), ns)
95
+ if finger_joints_element is not None:
96
+ finger_segments = {'names': mvnx_file.file_data['finger_segments']['names'][side],
97
+ 'elements': mvnx_file.file_data['finger_segments']['elements'][side]}
98
+ finger_joints = parse_joints(finger_joints_element, finger_segments)
99
+ mvnx_file.file_data['finger_joints']['elements'][side] = finger_joints['elements']
100
+ mvnx_file.file_data['finger_joints']['names'][side] = finger_joints['names']
101
+
102
+ # At last, parse the actual frames
103
+ frames_element = subject_element.find('mvn:frames', ns)
104
+ mvnx_file.file_data['frames'], mvnx_file.file_data['tpose'],\
105
+ mvnx_file.file_data['tpose_isb'], mvnx_file.file_data['identity'] = parse_frames(frames_element, mvnx_file)
106
+
107
+ mvnx_file.reset_frame_window() # Reset window so frame count displays total frame count
108
+ return mvnx_file
109
+
110
+
111
+ def parse_sensor(sensors_element, segment_names):
112
+ """
113
+ Parse the sensor element
114
+
115
+ :param sensors_element: The joint element to parse
116
+ :param segment_names: a list with the segment names
117
+ :return: a dictionary with sensor data indexed by sensor name and a list with the sensor names
118
+ """
119
+ sensor_elements = sensors_element.findall('mvn:sensor', ns)
120
+ sensor_number = 0
121
+ sensors = {}
122
+ sensor_names = []
123
+ for sensor_element in sensor_elements:
124
+ sensor_name = sensor_element.get('label')
125
+ sensor_names.append(sensor_name)
126
+ sensor = {'type': 'Sensor',
127
+ 'label': sensor_name,
128
+ 'info': {
129
+ 'sensor_number': sensor_number,
130
+ 'sensor_location': segment_names.index(sensor_name) + 1}}
131
+
132
+ sensors[sensor_name] = sensor
133
+ sensor_number += 1
134
+ return {'names': sensor_names, 'elements': sensors}
135
+
136
+
137
+ def parse_joints(joints_element, segments):
138
+ """
139
+ Parse the joint element
140
+
141
+ :param joints_element: The joint element to parse
142
+ :param segments: The dictionary with segment data
143
+ :return: a dictionary with joint data indexed by joint name and a list with the joint names
144
+ """
145
+ joint_elements = joints_element.findall('mvn:joint', ns)
146
+
147
+ joints = []
148
+ joint_names = []
149
+
150
+ for joint_element in joint_elements:
151
+ joint = {'label': joint_element.get('label')}
152
+ joint_names.append(joint['label'])
153
+
154
+ segment1_index, point1_index = get_connector_indices(joint_element, 'mvn:connector1', segments)
155
+ segment2_index, point2_index = get_connector_indices(joint_element, 'mvn:connector2', segments)
156
+ joint['seg_points'] = np.array([[segment1_index, point1_index], [segment2_index, point2_index]])
157
+ joints.append(joint)
158
+
159
+ return {'names': joint_names, 'elements': joints}
160
+
161
+
162
+ def parse_ergo_joints(ergo_joints_element):
163
+ """
164
+ Parse the ergo joint element
165
+
166
+ :param ergo_joints_element: The joint element to parse
167
+ :return: a dictionary with ergo joint data indexed by joint name and a list with the ergo joint names
168
+ """
169
+ ergo_joint_elements = ergo_joints_element.findall('mvn:ergonomicJointAngle', ns)
170
+
171
+ ergo_joints = []
172
+ ergo_joint_names = []
173
+ for ergo_joint_index in range(len(ergo_joint_elements)):
174
+ ergo_joint_element = ergo_joint_elements[ergo_joint_index]
175
+ ergo_joint = {'label': ergo_joint_element.get('label'),
176
+ 'index': ergo_joint_index,
177
+ 'parent_segment': ergo_joint_element.get('parentSegment'),
178
+ 'child_segment': ergo_joint_element.get('childSegment')}
179
+ ergo_joint_names.append(ergo_joint['label'])
180
+ ergo_joints.append(ergo_joint)
181
+
182
+ return {'names': ergo_joint_names, 'elements': ergo_joints}
183
+
184
+
185
+ def parse_segments(segment_elements):
186
+ """
187
+ Parse the segment element
188
+
189
+ :param segment_elements: The segment element to parse
190
+ :return: a dictionary a list with the segment names and segment data indexed by segment name
191
+ """
192
+ segments = collections.OrderedDict()
193
+ segment_names = []
194
+
195
+ for segment_index in range(len(segment_elements)):
196
+ segment_element = segment_elements[segment_index]
197
+ segment_name = segment_element.get('label')
198
+ segment_names.append(segment_name)
199
+ segment = {'points_mvn': collections.OrderedDict(),
200
+ 'type': 'Segment',
201
+ 'info': {},
202
+ 'label': segment_name}
203
+
204
+ info = {'segment_number': segment_index,
205
+ 'point_label_from_index': {},
206
+ 'point_origin': '',
207
+ 'adjacent_joints': []}
208
+
209
+ points_element = segment_element.find('mvn:points', ns)
210
+ point_elements = points_element.findall('mvn:point', ns)
211
+
212
+ point_labels_from_index = {}
213
+ for point_index in range(len(point_elements)):
214
+ point_element = point_elements[point_index]
215
+
216
+ point_name = point_element.get('label')
217
+ point_labels_from_index[point_index] = point_name
218
+
219
+ pos_b = point_element.find('mvn:pos_b', ns)
220
+ segment['points_mvn'][point_name] = np.array([float(pos) for pos in pos_b.text.split(' ')])
221
+
222
+ # if the point offset is really small, consider it the origin (could just pick 1st or all 0's as well)
223
+ if np.sqrt(np.sum([sq * sq for sq in segment['points_mvn'][point_name]])) < 0.00001:
224
+ info['point_origin'] = point_name
225
+
226
+ # wild guess...
227
+ if point_name[0] == 'j':
228
+ info['adjacent_joints'].append(point_name)
229
+
230
+ info['point_label_from_index'] = point_labels_from_index
231
+ segment['info'] = info
232
+ segments[segment_name] = segment
233
+
234
+ return {'names': segment_names, 'elements': segments}
235
+
236
+
237
+ def get_connector_indices(joint_element, connector, segments):
238
+ connector_element = joint_element.find(connector, ns)
239
+ tokens = connector_element.text.split('/')
240
+ segment_index = segments['names'].index(tokens[0])
241
+ point_index = -1
242
+ for key, value in segments['elements'][tokens[0]]['info']['point_label_from_index'].items():
243
+ if value == tokens[1]:
244
+ point_index = key
245
+ break
246
+
247
+ return segment_index, point_index
248
+
249
+
250
+ def parse_frames(frames_element, mvnx_file):
251
+ """
252
+ Parse the frames element
253
+
254
+ :param frames_element: The frames element to parse
255
+ :param mvnx_file: a dictionary containing, among others, a list of names
256
+ :return: a dictionary with frames data
257
+ """
258
+ frames = {'time': [],
259
+ 'segment_data': [],
260
+ 'sensor_data': [],
261
+ 'joint_data': [],
262
+ 'joint_data_xzy': [],
263
+ 'ergo_joint_data': [],
264
+ 'ergo_joint_data_xzy': [],
265
+ 'contacts_data': [],
266
+ 'finger_segment_data': [],
267
+ 'finger_joint_data': {'left': [], 'right': []},
268
+ 'finger_joint_data_xzy': {'left': [], 'right': []}}
269
+ tpose = {}
270
+ tpose_isb = {}
271
+ identity = {}
272
+
273
+ get_count = lambda element: int(element) if element is not None else None
274
+ frames['segment_count'] = get_count(frames_element.get('segmentCount'))
275
+ frames['sensor_count'] = get_count(frames_element.get('sensorCount'))
276
+ frames['joint_count'] = get_count(frames_element.get('jointCount'))
277
+ frames['finger_joint_count'] = get_count(frames_element.get('fingerJointCount'))
278
+ frame_elements = frames_element.findall('mvn:frame', ns)
279
+ for frame_element in frame_elements:
280
+ if frame_element.get('type') == 'normal':
281
+ frames['time'].append(frame_element.get('time'))
282
+ frames['joint_data'].append(
283
+ get_joint_data_from_frame(frame_element, 'jointAngle', mvnx_file.file_data['joints']['names']))
284
+ frames['joint_data_xzy'].append(
285
+ get_joint_data_from_frame(frame_element, 'jointAngleXZY', mvnx_file.file_data['joints']['names']))
286
+ frames['ergo_joint_data'].append(
287
+ get_joint_data_from_frame(frame_element, 'jointAngleErgo', mvnx_file.file_data['ergo_joints']['names']))
288
+ frames['ergo_joint_data_xzy'].append(
289
+ get_joint_data_from_frame(frame_element, 'jointAngleErgoXZY', mvnx_file.file_data['ergo_joints']['names']))
290
+ frames['segment_data'].append(
291
+ get_segment_data_from_frame(frame_element, mvnx_file.file_data['segments']['names']))
292
+ frames['sensor_data'].append(
293
+ get_sensor_data_from_frame(frame_element, mvnx_file.file_data['sensors']['names']))
294
+ frames['contacts_data'].append(
295
+ get_contact_data_from_frame(frame_element, mvnx_file.file_data['foot_contact_def']))
296
+ frames['finger_segment_data'].append(
297
+ get_finger_data_from_frame(frame_element, mvnx_file.file_data['finger_segments']['names']))
298
+ for side in frames['finger_joint_data']:
299
+ element_name = 'jointAngleFingers' + side.capitalize()
300
+ frames['finger_joint_data'][side].append(get_joint_data_from_frame(
301
+ frame_element, element_name, mvnx_file.file_data['finger_joints']['names'][side]))
302
+ element_name = 'jointAngleFingers' + side.capitalize() + 'XZY'
303
+ frames['finger_joint_data_xzy'][side].append(get_joint_data_from_frame(
304
+ frame_element, element_name, mvnx_file.file_data['finger_joints']['names'][side]))
305
+ elif frame_element.get('type') == 'tpose':
306
+ tpose = get_t_pose_data_from_frame(frame_element, mvnx_file.file_data['segments']['names'])
307
+ elif frame_element.get('type') == 'tpose-isb':
308
+ tpose_isb = get_t_pose_data_from_frame(frame_element, mvnx_file.file_data['segments']['names'])
309
+ elif frame_element.get('type') == 'identity':
310
+ identity = get_t_pose_data_from_frame(frame_element, mvnx_file.file_data['segments']['names'])
311
+
312
+ return frames, tpose, tpose_isb, identity
313
+
314
+
315
+ def get_joint_data_from_frame(frame_element, joint_element_name, joint_names):
316
+ """
317
+ Extract joint data from a frame
318
+
319
+ :param frame_element: The frame element to process
320
+ :param joint_element_name: The name of the frame element to process
321
+ :param joint_names: a list with the joint names
322
+ :return: a dictionary with joint data indexed by joint name
323
+ """
324
+
325
+ joint_data = collections.OrderedDict()
326
+
327
+ angles = frame_element_as_floats(frame_element, joint_element_name)
328
+
329
+ for index in range(len(joint_names)):
330
+ joint_data[joint_names[index]] = get_3d_vector(angles, index)
331
+
332
+ return joint_data
333
+
334
+
335
+ def get_t_pose_data_from_frame(frame_element, segment_names):
336
+ """
337
+ Extract segment data from a frame
338
+
339
+ :param frame_element: The frame element to process
340
+ :param segment_names: a list with the segment names
341
+ :return: a dictionary with segment data indexed by segment name
342
+ """
343
+
344
+ t_pose = {'segments_counts': len(segment_names), 'segments': []}
345
+
346
+ orientations = frame_element_as_floats(frame_element, 'orientation')
347
+ offsets = frame_element_as_floats(frame_element, 'position')
348
+
349
+ for index in range(len(segment_names)):
350
+ segment = {'pos_g': get_3d_vector(offsets, index),
351
+ 'q_gb': get_4d_vector(orientations, index)}
352
+ t_pose['segments'].append(segment)
353
+
354
+ return t_pose
355
+
356
+
357
+ def get_segment_data_from_frame(frame_element, segment_names):
358
+ """
359
+ Extract segment data from a frame
360
+
361
+ :param frame_element: The frame element to process
362
+ :param segment_names: a list with the segment names
363
+ :return: a dictionary with segment data indexed by segment name
364
+ """
365
+
366
+ segment_data = collections.OrderedDict()
367
+
368
+ orientations = frame_element_as_floats(frame_element, 'orientation')
369
+ offsets = frame_element_as_floats(frame_element, 'position')
370
+ velocities = frame_element_as_floats(frame_element, 'velocity')
371
+ accelerations = frame_element_as_floats(frame_element, 'acceleration')
372
+ angular_velocity = frame_element_as_floats(frame_element, 'angularVelocity')
373
+ angular_acceleration = frame_element_as_floats(frame_element, 'angularAcceleration')
374
+
375
+ for index in range(len(segment_names)):
376
+ segment_name = segment_names[index]
377
+ segment_data[segment_name] = collections.OrderedDict()
378
+ segment_data[segment_name]['ori'] = get_4d_vector(orientations, index)
379
+ segment_data[segment_name]['pos'] = get_3d_vector(offsets, index)
380
+ segment_data[segment_name]['vel'] = get_3d_vector(velocities, index)
381
+ segment_data[segment_name]['acc'] = get_3d_vector(accelerations, index)
382
+ segment_data[segment_name]['ang_vel'] = get_3d_vector(angular_velocity, index)
383
+ segment_data[segment_name]['ang_acc'] = get_3d_vector(angular_acceleration, index)
384
+
385
+ center_of_mass = frame_element_as_floats(frame_element, 'centerOfMass')
386
+ if center_of_mass:
387
+ segment_data['com'] = {'pos': [], 'vel': [], 'acc': []}
388
+ index = 0
389
+ for com_field in segment_data['com']:
390
+ segment_data['com'][com_field] = get_3d_vector(center_of_mass, index)
391
+ index += 1
392
+
393
+ return segment_data
394
+
395
+
396
+ def get_sensor_data_from_frame(frame_element, sensor_names):
397
+ """
398
+ Extract sensor data from a frame
399
+
400
+ :param frame_element: The frame element to process
401
+ :param sensor_names: a list with the segment names
402
+ :return: a dictionary with sensor data indexed by sensor name
403
+ """
404
+
405
+ sensor_data = collections.OrderedDict()
406
+
407
+ orientations = frame_element_as_floats(frame_element, 'sensorOrientation')
408
+ free_accelerations = frame_element_as_floats(frame_element, 'sensorFreeAcceleration')
409
+ magnetic_field = frame_element_as_floats(frame_element, 'sensorMagneticField')
410
+
411
+ for index in range(len(sensor_names)):
412
+ sensor_name = sensor_names[index]
413
+ sensor_data[sensor_name] = collections.OrderedDict()
414
+ sensor_data[sensor_name]["ori"] = get_4d_vector(orientations, index)
415
+ sensor_data[sensor_name]["mag"] = get_4d_vector(magnetic_field, index)
416
+ sensor_data[sensor_name]["acc"] = get_3d_vector(free_accelerations, index)
417
+
418
+ return sensor_data
419
+
420
+
421
+ def get_finger_data_from_frame(frame_element, finger_segment_names):
422
+ """
423
+ Extract finger data from a frame
424
+
425
+ :param frame_element: The frame element to process
426
+ :param finger_segment_names: a list with the finger segment names
427
+ :return: a dictionary with finger data indexed by finger name
428
+ """
429
+
430
+ finger_data = {'left': {}, 'right': {}}
431
+
432
+ for side in finger_data:
433
+ orientations = frame_element_as_floats(frame_element, 'orientationFingers' + side.capitalize())
434
+ offsets = frame_element_as_floats(frame_element, 'positionFingers' + side.capitalize())
435
+
436
+ for index in range(len(finger_segment_names[side])):
437
+ finger_name = finger_segment_names[side][index]
438
+ finger_data[side][finger_name] = collections.OrderedDict()
439
+ finger_data[side][finger_name]["ori"] = get_4d_vector(orientations, index)
440
+ finger_data[side][finger_name]["pos"] = get_3d_vector(offsets, index)
441
+
442
+ return finger_data
443
+
444
+
445
+ def get_contact_data_from_frame(frame_element, foot_contact_def):
446
+ """
447
+ Extract contact data from a frame
448
+
449
+ :param frame_element: The frame element to process
450
+ :param foot_contact_def: a list with the foot contact definitions
451
+ :return: a list with contacts
452
+ """
453
+
454
+ contact_data = []
455
+ element_value = frame_element.find('mvn:footContacts', ns)
456
+ if element_value is not None:
457
+ contacts = [int(value) for value in element_value.text.split(' ')]
458
+
459
+ for index in range(len(contacts)):
460
+ if contacts[index] == 1:
461
+ contact_data.append(foot_contact_def[index])
462
+
463
+ return contact_data
464
+
465
+
466
+ def frame_element_as_floats(frame_element, element):
467
+ """
468
+ Find a named element in a frame element, extract the text from it, split that and return
469
+ the values as an array of floats
470
+
471
+ :param frame_element: The mvnx frame element to process
472
+ :param element: The name of the sub element to find
473
+ :return: an array of floating point values
474
+ """
475
+
476
+ element_value = frame_element.find('mvn:' + element, ns)
477
+ return [float(value) for value in element_value.text.split(' ')] if element_value is not None else []
478
+
479
+
480
+ def get_4d_vector(raw_vector, index):
481
+ return np.array(raw_vector[index * 4:index * 4 + 4])
482
+
483
+
484
+ def get_3d_vector(raw_vector, index):
485
+ return np.array(raw_vector[index * 3:index * 3 + 3])
486
+
487
+
488
+ def init_file_data(mvnx_file):
489
+ meta_data = {'version': '',
490
+ 'original_filename': '',
491
+ 'rec_date': '',
492
+ 'name': '',
493
+ 'color': '',
494
+ 'comments': '',
495
+ 'scenario': '',
496
+ 'quality': '',
497
+ 'sample_rate': 240}
498
+
499
+ mvnx_file.file_data = {'segments': {},
500
+ 'finger_segments': {'names': {'left': {}, 'right': {}},
501
+ 'elements': {'left': collections.OrderedDict(),
502
+ 'right': collections.OrderedDict()}},
503
+ 'sensors': {'names': [], 'elements': collections.OrderedDict()},
504
+ 'joints': {'names': [], 'elements': collections.OrderedDict()},
505
+ 'ergo_joints': {'names': [], 'elements': collections.OrderedDict()},
506
+ 'finger_joints': {'names': {'left': {}, 'right': {}},
507
+ 'elements': {'left': collections.OrderedDict(),
508
+ 'right': collections.OrderedDict()}},
509
+ 'foot_contact_def': {},
510
+ 'frames': {},
511
+ 'tpose': {},
512
+ 'tpose_isb': {},
513
+ 'identity': {},
514
+ 'meta_data': meta_data}
@@ -0,0 +1,75 @@
1
+ import os
2
+ import argparse
3
+ import matplotlib.pyplot as plt
4
+ from biomechzoo.mvn.load_mvnx import load_mvnx
5
+
6
+
7
+ # Convert mvnx file to python data
8
+ def main(file_name):
9
+ # Check for file existence
10
+ if not os.path.isfile(file_name):
11
+ raise Exception("File %s could not be found" % file_name)
12
+
13
+ tokens = file_name.lower().split('.')
14
+ extension = tokens[-1]
15
+
16
+ # Check for file extension
17
+ if not extension == 'mvnx':
18
+ raise Exception("File must be an .mvnx file")
19
+
20
+ # Load data
21
+ mvnx_file = load_mvnx(file_name)
22
+
23
+ # Read some basic data from the file
24
+ comments = mvnx_file.comments
25
+ frame_rate = mvnx_file.frame_rate
26
+ configuration = mvnx_file.configuration
27
+ original_file_name = mvnx_file.original_file_name
28
+ recording_date = mvnx_file.recording_date
29
+ actor_name = mvnx_file.actor_name
30
+ frame_count = mvnx_file.frame_count
31
+ version = mvnx_file.version
32
+ segment_count = mvnx_file.segment_count
33
+ joint_count = mvnx_file.joint_count
34
+
35
+ # Read the data from the structure e.g. first segment
36
+ idx = 0
37
+ segment_name = mvnx_file.segment_name_from_index(idx)
38
+ segment_pos = mvnx_file.get_segment_pos(idx)
39
+
40
+ # Alternatively, use the generic method get_data() with the data set and field. E.g.:
41
+ # segment_pos = mvnx_file.get_data('segment_data', 'pos', idx)
42
+
43
+ if segment_pos:
44
+ # Plot position of a segment
45
+ plt.figure(0)
46
+ plt.plot(segment_pos)
47
+ plt.xlabel('frames')
48
+ plt.ylabel('Position in the global frame')
49
+ plt.title('Position of ' + segment_name + ' segment')
50
+ plt.legend(['x', 'y', 'z'])
51
+ plt.draw()
52
+
53
+ # Plot 3D displacement of a segment
54
+ x, y, z = map(list, zip(*[[frame[0], frame[1], frame[2]] for frame in segment_pos]))
55
+ plt.figure(1)
56
+ plt.axes(projection="3d")
57
+ plt.plot(x, y, z)
58
+ plt.xlabel('frames')
59
+ plt.title('Position of ' + segment_name + ' segment in 3D')
60
+ plt.draw()
61
+
62
+ plt.show()
63
+
64
+
65
+ if __name__ == '__main__':
66
+
67
+ # Program entry point
68
+ parser = argparse.ArgumentParser()
69
+ parser.add_argument('--mvnx_file', required=True, type=str, help='The MVNX file to load', nargs='?')
70
+ args = parser.parse_args()
71
+
72
+ try:
73
+ main(args.mvnx_file)
74
+ except Exception as e:
75
+ print("Error: %s" % e)