from ..src import mvn
import warnings
[docs]class MvnxFileAccessor:
@property
def original_file_name(self):
return self.file_data['meta_data']['original_filename']
@property
def actor_name(self):
return self.file_data['meta_data']['name']
@property
def actor_color(self):
return self.file_data['meta_data']['color']
@property
def profile(self):
return self.file_data['meta_data']['scenario']
@property
def configuration(self):
return self.file_data['meta_data']['configuration']
@property
def comments(self):
return self.file_data['meta_data']['comments']
@property
def quality(self):
return self.file_data['meta_data']['quality']
@property
def frame_count(self):
return self._last_frame - self._first_frame
@property
def segment_count(self):
return self.file_data['frames']['segment_count']
@property
def joint_count(self):
return self.file_data['frames']['joint_count']
@property
def finger_joint_count(self):
return self.file_data['frames']['finger_joint_count']
@property
def ergo_joint_count(self):
ergo_joint_count = len(self.file_data['ergo_joints']['names']) if self.file_data[
'ergo_joints'] is not None else None
return ergo_joint_count # 'ergoJointCount' non-existing in mvnx
@property
def sensor_count(self):
return self.file_data['frames']['sensor_count']
@property
def frame_rate(self) -> int:
if 'sample_rate' in self.file_data['meta_data']:
return int(self.file_data['meta_data']['sample_rate'])
else:
warnings.warn('Using default sample rate of 240')
return 240
@property
def recording_date(self) -> str:
return self.file_data['meta_data']['rec_date']
@property
def version(self):
return self.file_data['meta_data']['version']
def __init__(self):
self.file_data = {}
self._all_frames_slice = None
self._first_frame = 0
self._last_frame = 0
self._index_to_segment = {}
self._index_to_joint = {}
self._index_to_sensor = {}
self._index_to_ergo_joint = {}
[docs] def create_index_to_segment_dict(self):
segment_index = 0
for _, segment in self.file_data['segments']['elements'].items():
if 'label' in segment:
self._index_to_segment[segment_index] = segment['label']
segment_index += 1
[docs] def create_index_to_joint_dict(self):
joint_index = 0
for joint in self.file_data['joints']['elements']:
if 'label' in joint:
self._index_to_joint[joint_index] = joint['label']
joint_index += 1
[docs] def create_index_to_sensor_dict(self):
sensor_index = 0
for sensor in self.file_data['sensors']['elements']:
if 'label' in sensor:
self._index_to_sensor[sensor_index] = sensor['label']
sensor_index += 1
[docs] def create_index_to_ergo_joint_dict(self):
ergo_joint_index = 0
for ergo_joint in self.file_data['ergo_joints']['elements']:
if 'label' in ergo_joint:
self._index_to_ergo_joint[ergo_joint_index] = ergo_joint['label']
ergo_joint_index += 1
[docs] def set_frame_window(self, first_frame, last_frame):
self._first_frame = first_frame
self._last_frame = last_frame
self._all_frames_slice = slice(self._first_frame, self._last_frame)
[docs] def reset_frame_window(self):
self._first_frame = 0
self._last_frame = len(self.file_data['frames']['segment_data'])
self._all_frames_slice = slice(self._first_frame, self._last_frame)
[docs] def window_profile(self):
"""
This method determines the filter profile (aka scenario) for the currently selected window on the
data.
:return: The profile name (singleLevel, multiLevel, ...) or 'mixed' if different profiles
ere applied to the window.
"""
if 'profiles' not in self.file_data['meta_data']:
return self.profile
else:
profiles = set()
for profile_spec in self.file_data['meta_data']['profiles']:
if profile_spec[1] > self._first_frame and profile_spec[0] <= self._last_frame:
profiles.add(profile_spec[2])
if len(profiles) == 1:
return profiles.pop()
else:
return 'mixed'
[docs] def frame_to_mapped_slice(self, frame) -> (slice, bool):
# convert the frame parameter to a slice that is mapped to the current view on the file
single_frame = False
if not isinstance(frame, slice):
if frame == mvn.FRAMES_ALL:
# all frames slice already is mapped to the current view
self.reset_frame_window()
frame = self._all_frames_slice # use the prepared 'all frames' slice
else:
# for a single frame, map the frame to the current view on all data by adding the virtual first frame
frame = slice(self._first_frame + frame, self._first_frame + frame + 1) # create a single frame slice
single_frame = True
else:
# shift the slice to the current virtual 'view'
start = frame.start + self._first_frame
if frame.stop:
stop = frame.stop + self._first_frame
else: # a slice with end given as None implies end at last frame
stop = self._last_frame
step = frame.step
frame = slice(start, stop, step)
return frame, single_frame
[docs] def segment_name_from_index(self, segment_index):
return self._index_to_segment[segment_index]
[docs] def joint_name_from_index(self, joint_index):
return self._index_to_joint[joint_index]
[docs] def sensor_name_from_index(self, sensor_index):
return self._index_to_sensor[sensor_index]
[docs] def ergo_joint_name_from_index(self, ergo_joint_index):
return self._index_to_ergo_joint[ergo_joint_index]
[docs] def point_name_from_indices(self, segment_index, point_index):
segment_name = self.segment_name_from_index(segment_index)
segment = self.file_data['segments']['elements'][segment_name]
return segment['info']['point_label_from_index'][point_index]
""" Pose methods """
[docs] def identity_pose_is_valid(self):
return ('identity' in self.file_data) and \
(self.identity_pose()['segments_counts'] > 0)
[docs] def identity_pose_segment_pos(self, segment):
return self.identity_pose()['segments'][segment]['pos_g']
[docs] def identity_pose_segment_ori(self, segment):
return self.identity_pose()['segments'][segment]['q_gb']
[docs] def t_pose_is_valid(self):
return ('tpose' in self.file_data) and \
(self.t_pose()['segments_counts'] > 0)
[docs] def t_pose_segment_pos(self, segment):
return self.t_pose()['segments'][segment]['pos_g']
[docs] def t_pose_segment_ori(self, segment):
return self.t_pose()['segments'][segment]['q_gb']
[docs] def identity_pose(self):
return self.file_data['identity']
[docs] def t_pose(self):
return self.file_data['tpose']
""" Segment methods """
[docs] def get_segment_pos(self, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
"""
Get the position information for a segment
:param segment: The index of the segment to return the data for (Mvn.SEGMENT_.... )
:param frame: Can be the index of the frame to return, a slice to return a range of frames
or Mvn.FRAMES_ALL (default) to return all frames
:param axis: The frame number to return the data for (Mvn.AXIS_... ALL for all axes)
:return: A single value, list, or list of lists with position values
"""
return self.get_segment_data('pos', segment, frame, axis)
[docs] def get_segment_ori(self, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
"""
Get the orientation information for a segment
:param segment: The index of the segment to return the data for (Mvn.SEGMENT_.... )
:param frame: Can be the index of the frame to return, a slice to return a range of frames
or Mvn.FRAMES_ALL (default) to return all frames
:param axis: The frame number to return the data for (Mvn.AXIS_... ALL for all axes)
:return: A single value, list, or list of lists with orientation values
"""
# For orientation data, if all axes requested, return all. If specific axis requested, shift index so that w,
# x,y,z becomes 0,1,2,3
axis = (axis + 1) % 4 if axis != mvn.AXIS_ALL else axis
return self.get_segment_data('ori', segment, frame, axis)
[docs] def get_segment_point_pos(self, segment, point):
segment_name = mvn.SEGMENTS[segment]
segment_info = self.file_data['segments'][segment_name]
points = segment_info['info']['point_label_from_index']
point_name = points[point]
return segment_info['points_mvn'][point_name]
[docs] def get_point_pos(self, segment, point):
segment_name = mvn.SEGMENTS[segment]
if segment_name == 'LeftFoot':
point_name = mvn.POINTS_LEFT_FOOT[point]
elif segment_name == 'RightFoot':
point_name = mvn.POINTS_RIGHT_FOOT[point]
elif segment_name == 'LeftToe':
point_name = mvn.POINTS_LEFT_TOE[point]
elif segment_name == 'RightToe':
point_name = mvn.POINTS_RIGHT_TOE[point]
return self.file_data['segments'][segment_name]['points_mvn'][point_name]
[docs] def get_segment_vel(self, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
"""
Get the local velocity information for a segment
:param segment: The index of the segment to return the data for (Mvn.SEGMENT_.... )
:param frame: Can be the index of the frame to return, a slice to return a range of frames
or Mvn.FRAMES_ALL (default) to return all frames
:param axis: The frame number to return the data for (Mvn.AXIS_... ALL for all axes)
:return: A single value, list, or list of lists with velocity values
"""
return self.get_segment_data('vel', segment, frame, axis)
[docs] def get_segment_acc(self, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
"""
Get the acceleration information for a segment
:param segment: The index of the segment to return the data for (Mvn.SEGMENT_.... )
:param frame: Can be the index of the frame to return, a slice to return a range of frames
or Mvn.FRAMES_ALL (default) to return all frames
:param axis: The frame number to return the data for (Mvn.AXIS_... ALL for all axes)
:return: A single value, list, or list of lists with acceleration values
"""
return self.get_segment_data('acc', segment, frame, axis)
[docs] def get_segment_angular_vel(self, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
"""
Get the acceleration information for a segment
:param segment: The index of the segment to return the data for (Mvn.SEGMENT_.... )
:param frame: Can be the index of the frame to return, a slice to return a range of frames
or Mvn.FRAMES_ALL (default) to return all frames
:param axis: The frame number to return the data for (Mvn.AXIS_... ALL for all axes)
:return: A single value, list, or list of lists with angular velocity values
"""
return self.get_segment_data('ang_vel', segment, frame, axis)
[docs] def get_segment_angular_acc(self, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
"""
Get the acceleration information for a segment
:param segment: The index of the segment to return the data for (Mvn.SEGMENT_.... )
:param frame: Can be the index of the frame to return, a slice to return a range of frames
or Mvn.FRAMES_ALL (default) to return all frames
:param axis: The frame number to return the data for (Mvn.AXIS_... ALL for all axes)
:return: A single value, list, or list of lists with acceleration values
"""
return self.get_segment_data('ang_acc', segment, frame, axis)
[docs] def get_segment_data(self, data_field, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
return self.get_data('segment_data', data_field, segment, frame, axis)
[docs] def get_finger_segment_pos(self, hand_idx, segment_name, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
return self.get_finger_segment_data('pos', hand_idx, segment_name, frame, axis)
[docs] def get_finger_segment_ori(self, hand_idx, segment_name, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
return self.get_finger_segment_data('ori', hand_idx, segment_name, frame, axis)
[docs] def get_finger_segment_data(self, data_field, hand_idx, segment_name, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
frame, is_single_frame = self.frame_to_mapped_slice(frame)
if axis == mvn.AXIS_ALL:
return_values = [value[hand_idx][segment_name][data_field] for value in
self.file_data['frames']['finger_segment_data'][frame]]
else:
return_values = [value[hand_idx][segment_name][data_field][axis] for value in
self.file_data['frames']['finger_segment_data'][frame]]
return return_values[0] if is_single_frame else return_values
""" Joint methods """
[docs] def get_joint_angle(self, joint, frame=mvn.FRAMES_ALL, angle=mvn.ANGLE_ALL):
joint_name = mvn.JOINTS[joint]
data_set = 'joint_data'
frame, is_single_frame = self.frame_to_mapped_slice(frame)
if angle == mvn.ANGLE_ALL:
return_values = [value[joint_name] for value in self.file_data['frames'][data_set][frame]]
else:
return_values = [value[joint_name][angle] for value in self.file_data['frames'][data_set][frame]]
return return_values[0] if is_single_frame else return_values
[docs] def get_joint_angle_xzy(self, joint, frame=mvn.FRAMES_ALL, angle=mvn.ANGLE_ALL):
joint_name = mvn.JOINTS[joint]
data_set = 'joint_data_xzy'
frame, is_single_frame = self.frame_to_mapped_slice(frame)
if angle == mvn.ANGLE_ALL:
return_values = [value[joint_name] for value in self.file_data['frames'][data_set][frame]]
else:
return_values = [value[joint_name][angle] for value in self.file_data['frames'][data_set][frame]]
return return_values[0] if is_single_frame else return_values
[docs] def get_ergo_joint_angle(self, joint, frame=mvn.FRAMES_ALL, angle=mvn.ANGLE_ALL):
joint_name = mvn.ERGO_JOINTS[joint]
data_set = 'ergo_joint_data'
frame, is_single_frame = self.frame_to_mapped_slice(frame)
if angle == mvn.ANGLE_ALL:
return_values = [value[joint_name] for value in self.file_data['frames'][data_set][frame]]
else:
return_values = [value[joint_name][angle] for value in self.file_data['frames'][data_set][frame]]
return return_values[0] if is_single_frame else return_values
""" Center of Mass methods """
[docs] def get_center_of_mass_pos(self, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
"""
Get the position information for center of mass
:param frame: Can be the index of the frame to return, a slice to return a range of frames
or Mvn.FRAMES_ALL (default) to return all frames
:param axis: The axis to return the data for (Mvn.AXIS_... ALL for all axes)
:return: A single value, list, or list of lists with position values
"""
return self.get_segment_data('pos', mvn.SEGMENT_CENTER_OF_MASS, frame, axis)
[docs] def get_center_of_mass_vel(self, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
"""
Get the velocity information for center of mass
:param frame: Can be the index of the frame to return, a slice to return a range of frames
or Mvn.FRAMES_ALL (default) to return all frames
:param axis: The axis to return the data for (Mvn.AXIS_... ALL for all axes)
:return: A single value, list, or list of lists with position values
"""
return self.get_segment_data('vel', mvn.SEGMENT_CENTER_OF_MASS, frame, axis)
[docs] def get_center_of_mass_acc(self, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
"""
Get the acceleration information for center of mass
:param frame: Can be the index of the frame to return, a slice to return a range of frames
or Mvn.FRAMES_ALL (default) to return all frames
:param axis: The axis to return the data for (Mvn.AXIS_... ALL for all axes)
:return: A single value, list, or list of lists with position values
"""
return self.get_segment_data('acc', mvn.SEGMENT_CENTER_OF_MASS, frame, axis)
""" Sensor methods """
[docs] def get_sensor_ori(self, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
"""
Get the orientation information for a sensor
:param segment: The index of the segment to return the sensor data for (Mvn.SEGMENT_.... )
:param frame: Can be the index of the frame to return, a slice to return a range of frames
or Mvn.FRAMES_ALL (default) to return all frames
:param axis: The frame number to return the data for (Mvn.AXIS_... ALL for all axes)
:return: A single value, list, or list of lists with orientation values
"""
# if all axes requested, return all. If specific axis requested, shift index so that w,x,y,z becomes 0,1,2,3
axis = (axis + 1) % 4 if axis != mvn.AXIS_ALL else axis
return self.get_sensor_data('ori', segment, frame, axis)
[docs] def get_sensor_free_acc(self, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
"""
Get the free acceleration information for a sensor
:param segment: The index of the segment to return the sensor data for (Mvn.SEGMENT_.... )
:param frame: Can be the index of the frame to return, a slice to return a range of frames
or Mvn.FRAMES_ALL (default) to return all frames
:param axis: The frame number to return the data for (Mvn.AXIS_... ALL for all axes)
:return: A single value, list, or list of lists with acceleration values
"""
return self.get_sensor_data('acc', segment, frame, axis)
[docs] def get_sensor_data(self, data_field, sensor_segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
return self.get_data('sensor_data', data_field, sensor_segment, frame, axis)
""" Contact methods """
""" Generic methods """
[docs] def get_data(self, data_set, data_field, segment, frame=mvn.FRAMES_ALL, axis=mvn.AXIS_ALL):
if segment == -1:
segment_name = 'com'
else:
segment_name = mvn.SEGMENTS[segment]
frame, is_single_frame = self.frame_to_mapped_slice(frame)
if data_set == 'joint_data':
return_values = [value[data_field] for value in self.file_data['frames'][data_set][frame]]
elif axis == mvn.AXIS_ALL:
return_values = [value[segment_name][data_field] for value in self.file_data['frames'][data_set][frame]]
else:
return_values = [value[segment_name][data_field][axis] for value in
self.file_data['frames'][data_set][frame]]
return return_values[0] if is_single_frame else return_values