Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ A library for using motion capture data for machine learning
* Convert data representations
* [Euler angles to positions](#convert-to-positions)
* Euler angles to exponential maps
* Euler angles to axis angles
* Exponential maps to euler angles
* Body-oriented global translation and rotation calculation with inverse tranform
* Root-centric position normalizer with inverse tranform
Expand Down
76 changes: 76 additions & 0 deletions pymo/preprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ def transform(self, X, y=None):
return X
elif self.param_type == 'position':
return self._to_pos(X)
elif self.param_type == 'axis_angle':
return self._to_axis_angle(X)
else:
raise UnsupportedParamError('Unsupported param: %s. Valid param types are: euler, quat, expmap, position' % self.param_type)
# return X
Expand Down Expand Up @@ -153,6 +155,80 @@ def _to_pos(self, X):
return Q


def _to_axis_angle(self, X):
'''Converts joints rotations in Euler angles to axis angle rotations'''

Q = []
for track in X:
# fix track names
# adapt joint name so that it's equal for either male or female
channels = []
titles = []
euler_df = track.values

# Create a new DataFrame to store the axis angle values
axis_anlge_df = pd.DataFrame(index=euler_df.index)

# List the columns that contain rotation channels
rot_cols = [c for c in euler_df.columns if ('rotation' in c)]

# List the columns that contain position channels
pos_cols = [c for c in euler_df.columns if ('position' in c)]

# List the joints that are not end sites, i.e., have channels
joints = (joint for joint in track.skeleton)

tree_data = {}

for joint in track.traverse():
parent = track.skeleton[joint]['parent']

# Get the rotation columns that belong to this joint
rc = euler_df[[c for c in rot_cols if joint in c]]

# Get the position columns that belong to this joint
pc = euler_df[[c for c in pos_cols if joint in c]]

# Make sure the columns are organized in xyz order
if rc.shape[1] < 3:
euler_values = [[0,0,0] for f in rc.iterrows()]
else:
euler_values = [[f[1]['%s_Xrotation'%joint],
f[1]['%s_Yrotation'%joint],
f[1]['%s_Zrotation'%joint]] for f in rc.iterrows()]

################# in euler angle, the order of rotation axis is very important #####################
rotation_order = rc.columns[0][rc.columns[0].find('rotation') - 1] + rc.columns[1][rc.columns[1].find('rotation') - 1] + rc.columns[2][rc.columns[2].find('rotation') - 1] #rotation_order is string : 'XYZ' or'ZYX' or ...
####################################################################################################

if pc.shape[1] < 3:
pos_values = [[0,0,0] for f in pc.iterrows()]
else:
pos_values =[[f[1]['%s_Xposition'%joint],
f[1]['%s_Yposition'%joint],
f[1]['%s_Zposition'%joint]] for f in pc.iterrows()]

# Convert the eulers to axis angles
############################ input rotation order as Rotation class's argument #########################
axis_angles = np.asarray([Rotation([f[0], f[1], f[2]], 'euler', rotation_order, from_deg=True).to_axis_angle() for f in euler_values])
########################################################################################################

# Create the corresponding columns in the new DataFrame
axis_anlge_df['%s_Xposition'%joint] = pd.Series(data=[e[0] for e in pos_values], index=axis_anlge_df.index)
axis_anlge_df['%s_Yposition'%joint] = pd.Series(data=[e[1] for e in pos_values], index=axis_anlge_df.index)
axis_anlge_df['%s_Zposition'%joint] = pd.Series(data=[e[2] for e in pos_values], index=axis_anlge_df.index)

axis_anlge_df['%s_Xrotation'%joint] = pd.Series(data=[e[0] for e in axis_angles], index=axis_anlge_df.index)
axis_anlge_df['%s_Yrotation'%joint] = pd.Series(data=[e[1] for e in axis_angles], index=axis_anlge_df.index)
axis_anlge_df['%s_Zrotation'%joint] = pd.Series(data=[e[2] for e in axis_angles], index=axis_anlge_df.index)


new_track = track.clone()
new_track.values = axis_anlge_df
Q.append(new_track)
return Q


def _to_expmap(self, X):
'''Converts Euler angles to Exponential Maps'''

Expand Down
10 changes: 10 additions & 0 deletions pymo/rotation_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import math
import numpy as np
from scipy.spatial.transform import Rotation as SpRotation

def deg2rad(x):
return x/180*math.pi
Expand Down Expand Up @@ -99,6 +100,15 @@ def get_euler_axis(self):
axis = axis/(2*math.sin(theta))
return theta, axis

def to_axis_angle(self):
# transpose matrix because we're building the rotation matrix in a different way
transposed_rot_matrix = np.matrix.transpose(self.rotmat)

sp_rot = SpRotation.from_matrix(transposed_rot_matrix)
rot_vec = sp_rot.as_rotvec()

return rot_vec

def to_expmap(self):
theta, axis = self.get_euler_axis()
rot_arr = theta * axis
Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
'numpy',
'pandas',
'matplotlib',
'scipy',
'scikit-learn'
]
)
)