def _to_expmap(self, X): '''Converts Euler angles to Exponential Maps''' Q = [] for track in X: channels = [] titles = [] euler_df = track.values # Create a new DataFrame to store the exponential map rep exp_df = pd.DataFrame(index=euler_df.index) # Copy the root positions into the new DataFrame rxp = '%s_Xposition' % track.root_name ryp = '%s_Yposition' % track.root_name rzp = '%s_Zposition' % track.root_name exp_df[rxp] = pd.Series(data=euler_df[rxp], index=exp_df.index) exp_df[ryp] = pd.Series(data=euler_df[ryp], index=exp_df.index) exp_df[rzp] = pd.Series(data=euler_df[rzp], index=exp_df.index) # List the columns that contain rotation channels rots = [ c for c in euler_df.columns if ('rotation' in c and 'Nub' not in c) ] # List the joints that are not end sites, i.e., have channels joints = (joint for joint in track.skeleton if 'Nub' not in joint) for joint in joints: r = euler_df[[c for c in rots if joint in c ]] # Get the columns that belong to this joint euler = [[ f[1]['%s_Xrotation' % joint], f[1]['%s_Yrotation' % joint], f[1]['%s_Zrotation' % joint] ] for f in r.iterrows() ] # Make sure the columsn are organized in xyz order exps = [ Rotation(f, 'euler', from_deg=True).to_expmap() for f in euler ] # Convert the eulers to exp maps # Create the corresponding columns in the new DataFrame exp_df['%s_alpha' % joint] = pd.Series( data=[e[0] for e in exps], index=exp_df.index) exp_df['%s_beta' % joint] = pd.Series( data=[e[1] for e in exps], index=exp_df.index) exp_df['%s_gamma' % joint] = pd.Series( data=[e[2] for e in exps], index=exp_df.index) new_track = track.clone() new_track.values = exp_df Q.append(new_track) return Q
def _to_pos(self, X): '''Converts joints rotations in Euler angles to joint positions''' Q = [] for track in X: channels = [] titles = [] euler_df = track.values # Create a new DataFrame to store the exponential map rep pos_df = pd.DataFrame(index=euler_df.index) # Copy the root rotations into the new DataFrame # rxp = '%s_Xrotation'%track.root_name # ryp = '%s_Yrotation'%track.root_name # rzp = '%s_Zrotation'%track.root_name # pos_df[rxp] = pd.Series(data=euler_df[rxp], index=pos_df.index) # pos_df[ryp] = pd.Series(data=euler_df[ryp], index=pos_df.index) # pos_df[rzp] = pd.Series(data=euler_df[rzp], index=pos_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()] #euler_values = [[0,0,0] for f in rc.iterrows()] #for deugging #pos_values = [[0,0,0] for f in pc.iterrows()] #for deugging # Convert the eulers to rotation matrices ############################ input rotation order as Rotation class's argument ######################### rotmats = np.asarray([ Rotation([f[0], f[1], f[2]], 'euler', rotation_order, from_deg=True).rotmat for f in euler_values ]) ######################################################################################################## tree_data[joint] = [ [], # to store the rotation matrix [] # to store the calculated position ] if track.root_name == joint: tree_data[joint][0] = rotmats # tree_data[joint][1] = np.add(pos_values, track.skeleton[joint]['offsets']) tree_data[joint][1] = pos_values else: # for every frame i, multiply this joint's rotmat to the rotmat of its parent tree_data[joint][0] = np.asarray([ np.matmul(rotmats[i], tree_data[parent][0][i]) for i in range(len(tree_data[parent][0])) ]) # add the position channel to the offset and store it in k, for every frame i k = np.asarray([ np.add(pos_values[i], track.skeleton[joint]['offsets']) for i in range(len(tree_data[parent][0])) ]) # multiply k to the rotmat of the parent for every frame i q = np.asarray([ np.matmul(k[i], tree_data[parent][0][i]) for i in range(len(tree_data[parent][0])) ]) # add q to the position of the parent, for every frame i tree_data[joint][1] = np.asarray([ np.add(q[i], tree_data[parent][1][i]) for i in range(len(tree_data[parent][1])) ]) # Create the corresponding columns in the new DataFrame pos_df['%s_Xposition' % joint] = pd.Series( data=[e[0] for e in tree_data[joint][1]], index=pos_df.index) pos_df['%s_Yposition' % joint] = pd.Series( data=[e[1] for e in tree_data[joint][1]], index=pos_df.index) pos_df['%s_Zposition' % joint] = pd.Series( data=[e[2] for e in tree_data[joint][1]], index=pos_df.index) new_track = track.clone() new_track.values = pos_df Q.append(new_track) return Q