def test_matrix_representation(self): ref_motion = bvh.load(file=TEST_SINUSOIDAL_FILE) test_motion = bvh.load( file=TEST_SINUSOIDAL_FILE, load_motion=False, ) ref_matrix = ref_motion.to_matrix() test_motion = motion_class.Motion.from_matrix( ref_matrix, ref_motion.skel, ) self.assert_motion_equal(ref_motion, test_motion)
def test_load_motion(self): # Load file motion = asfamc.load(file="tests/data/01.asf", motion="tests/data/01_01.amc") motion_bvh = bvh.load(file="tests/data/01_01.bvh") for i in range(1, motion.num_frames()): pose = motion.get_pose_by_frame(i) pose_bvh = motion_bvh.get_pose_by_frame(i) """ for k, j in zip(pose.skel.joints, pose_bvh.skel.joints): print(k.name, j.name) root Hips lhipjoint LHipJoint lfemur LeftUpLeg ltibia LeftLeg lfoot LeftFoot ltoes LeftToeBase rhipjoint RHipJoint rfemur RightUpLeg rtibia RightLeg rfoot RightFoot rtoes RightToeBase lowerback LowerBack upperback Spine thorax Spine1 lowerneck Neck upperneck Neck1 head Head lclavicle LeftShoulder lhumerus LeftArm lradius LeftForeArm lwrist LeftHand lhand LeftFingerBase lfingers LFingers lthumb LThumb rclavicle RightShoulder rhumerus RightArm rradius RightForeArm rwrist RightHand rhand RightFingerBase rfingers RFingers rthumb RThumb """ for joint_idx, (k, j) in enumerate(zip(pose.data, pose_bvh.data)): # As asfamc and bvh are from different sources, we are not strictly comparing them. # We require no more than two different elements. failures = 0 if joint_idx == 0: compare_rotation = 0 else: compare_rotation = 1 for kk, jj in zip( np.nditer(k[:, :3 - compare_rotation]), np.nditer(j[:, :3 - compare_rotation]), ): if abs(kk - jj) > 0.2: failures += 1 assert failures <= 2, failures
def split_bvh(filepath, time_window, output_folder): motion = bvh.load(filepath) frames_per_time_window = time_window * motion.fps for num, i in enumerate( range(0, motion.num_frames(), int(frames_per_time_window / 2))): motion_slice = motion_ops.cut(motion, i, i + frames_per_time_window) filepath_slice = os.path.join( output_folder, filepath.split(".")[-2].split("/")[-1] + "_" + str(num) + ".bvh", ) bvh.save(motion_slice, filepath_slice)
def __init__(self, root_folder, percentile=95, sliding_window=2): self.percentile = percentile self.velocities = defaultdict(list) self.sliding_window = sliding_window for root, _, files in os.walk(root_folder, topdown=False): for filename in tqdm.tqdm(files): motion = bvh.load(os.path.join(root, filename)) self.joints = [joint.name for joint in motion.skel.joints] self._update_velocities( motion.positions(local=False), 1 / motion.fps, ) self.thresholds = self._compute_p95_thresholds()
def test_motion(self): motion = bvh.load(file=TEST_SINUSOIDAL_FILE) # Inspect 0th frame, root joint T = motion.get_pose_by_frame(0).get_transform(0, local=False) _, p = conversions.T2Rp(T) self.assertListEqual(list(p), [-3, 6, 5]) # Inspect 100th frame, root joint T = motion.get_pose_by_frame(100).get_transform(0, local=False) _, p = conversions.T2Rp(T) self.assertListEqual(list(p), [-3, 6, 5]) # Inspect 100th frame, "child2" joint T = motion.get_pose_by_frame(100).get_transform("child2", local=False) _, p = conversions.T2Rp(T) self.assertListEqual(list(p), [-8, 11, 5])
def test_append_motion(self): motion1 = bvh.load(file="tests/data/sinusoidal.bvh") motion2 = bvh.load(file="tests/data/sinusoidal.bvh") num_frames = motion1.num_frames() # Append motion 1 and motion 2, and check total combined frames combined_motion1 = motion_ops.append(motion1, motion2) self.assertEqual( combined_motion1.num_frames(), motion1.num_frames() + motion2.num_frames(), ) # Append motion 1 and motion 3, and check total combined frames motion3 = bvh.load(file="tests/data/sinusoidal.bvh") combined_motion2 = motion_ops.append(motion1, motion3) self.assertEqual( combined_motion2.num_frames(), motion1.num_frames() + motion3.num_frames(), ) # Ensure operation has not been done in place self.assertEqual( motion1.num_frames(), num_frames, ) # Test blending blend_length = 0.1 combined_motion3 = motion_ops.append_and_blend( motion1, motion2, blend_length=blend_length, ) self.assertEqual( combined_motion3.num_frames(), (motion1.num_frames() + motion2.num_frames() - blend_length * motion1.fps), )
def load_motion_at_idx(self, idx, file): motion = velocity.MotionWithVelocity(skel=self.skel) motion = bvh.load( file=file, motion=motion, scale=self.scale, load_skel=self.skel is None, v_up_skel=self.skel.v_up, v_face_skel=self.skel.v_face, v_up_env=self.skel.v_up_env, ) motion.resample(fps=self.fps) self.motions[idx] = motion if self.verbose: logging.info(f"Loaded: {file}")
def main(args): motion = bvh.load(args.input_file) trajectory = motion.positions(local=False).reshape(motion.num_frames(), -1) print("Total length (in s) ", motion.length()) # Assumes you have a trajectory that has axis 0 as time and axis 1 as # state dimensions. acc = np.diff(trajectory, n=2, axis=0) acc_norm = np.linalg.norm(acc, axis=1) segs = find_peaks(acc_norm, height=0.075)[0] # sega = argrelextrema(acc_norm, np.greater, order=8)[0] print("Number of detected segments ", len(segs)) if args.output_plot is not None: plot_changepoints(acc_norm, segs, args.output_plot)
def test_load_motion(self): # Load file motion = bvh.load(file=TEST_SINUSOIDAL_FILE) # Read pose data from all frames (in Euler angle) with open(TEST_SINUSOIDAL_FILE) as f: file_content = f.readlines() for frame_num, line in enumerate(file_content[-motion.num_frames():]): # Skip first 3 entries that store translation data, and read the # Euler angle data of joints angle_data = np.array(list(map(float, line.strip().split()))[3:]).reshape( -1, 3) for T, true_E in zip(motion.poses[frame_num].data, angle_data): R, _ = conversions.T2Rp(T) E = conversions.R2E(R, order="XYZ", degrees=True) np.testing.assert_almost_equal(E, true_E)
def test_save_motion(self): # Load file motion = bvh.load(file=TEST_SINUSOIDAL_FILE) with tempfile.NamedTemporaryFile() as fp: # Save loaded file bvh.save(motion, fp.name, rot_order="XYZ") # Reload saved file and test if it is same as reference file # Read pose data from all frames (in Euler angle) with open(TEST_SINUSOIDAL_FILE) as f: orig_file = f.readlines() with open(fp.name) as f: saved_file = f.readlines() for orig_line, saved_line in zip( orig_file[-motion.num_frames():], saved_file[-motion.num_frames():], ): # Skip first 3 entries that store translation data, and read # the Euler angle data of joints orig_data, saved_data = [ np.array(list(map(float, line.strip().split()))) for line in [orig_line, saved_line] ] np.testing.assert_almost_equal(orig_data, saved_data) # Reload saved file and test if it has the same data as original # motion object with open(TEST_SINUSOIDAL_FILE) as f: file_content = f.readlines() for frame_num, line in enumerate( file_content[-motion.num_frames():]): # Skip first 3 entries that store translation data, and read # the Euler angle data of joints angle_data = np.array( list(map(float, line.strip().split()))[3:]).reshape(-1, 3) for T, true_E in zip(motion.poses[frame_num].data, angle_data): R, _ = conversions.T2Rp(T) E = conversions.R2E(R, order="XYZ", degrees=True) np.testing.assert_almost_equal(E, true_E)
def load_motions(motion_files, skel, char_info, verbose): assert motion_files is not None motion_file_names = [] for names in motion_files: head, tail = os.path.split(names) motion_file_names.append(tail) if isinstance(motion_files[0], str): motion_dict = {} motion_all = [] for i, file in enumerate(motion_files): ''' If the same file is already loaded, do not load again for efficiency''' if file in motion_dict: m = motion_dict[file] else: if file.endswith('bvh'): m = bvh.load(motion=Motion(name=file, skel=skel), file=file, scale=1.0, load_skel=False, v_up_skel=char_info.v_up, v_face_skel=char_info.v_face, v_up_env=char_info.v_up_env) m = MotionWithVelocity.from_motion(m) elif file.endswith('bin'): m = pickle.load(open(file, "rb")) elif file.endswith('gzip') or file.endswith('gz'): with gzip.open(file, "rb") as f: m = pickle.load(f) else: raise Exception('Unknown Motion File Type') if verbose: print('Loaded: %s' % file) motion_all.append(m) elif isinstance(motion_files[0], MotionWithVelocity): motion_all = motion_files else: raise Exception('Unknown Type for Reference Motion') return motion_all, motion_file_names
def main(args): v_up_env = utils.str_to_axis(args.axis_up) if args.bvh_files: motions = [ bvh.load( file=filename, v_up_skel=v_up_env, v_face_skel=utils.str_to_axis(args.axis_face), v_up_env=v_up_env, scale=args.scale, ) for filename in args.bvh_files ] else: motions = [ asfamc.load(file=f, motion=m) for f, m in zip(args.asf_files, args.amc_files) ] for i in range(len(motions)): motion_ops.translate(motions[i], [args.x_offset * i, 0, 0]) cam = camera.Camera( pos=np.array(args.camera_position), origin=np.array(args.camera_origin), vup=v_up_env, fov=45.0, ) viewer = MocapViewer( motions=motions, play_speed=args.speed, scale=args.scale, thickness=args.thickness, render_overlay=args.render_overlay, hide_origin=args.hide_origin, title="Motion Graph Viewer", cam=cam, size=(1280, 720), ) viewer.run()
def __init__(self, config): project_dir = config['project_dir'] char_info_module = config['character'].get('char_info_module') sim_char_file = config['character'].get('sim_char_file') base_motion_file = config['character'].get('base_motion_file') ref_motion_scale = config['character'].get('ref_motion_scale') environment_file = config['character'].get('environment_file') ref_motion_file = config['character'].get('ref_motion_file') self_collision = config['character'].get('self_collision') actuation = config['character'].get('actuation') ''' Append project_dir to the given file path ''' if project_dir: for i in range(len(char_info_module)): char_info_module[i] = os.path.join(project_dir, char_info_module[i]) sim_char_file[i] = os.path.join(project_dir, sim_char_file[i]) base_motion_file[i] = os.path.join(project_dir, base_motion_file[i]) if environment_file is not None: for i in range(len(environment_file)): environment_file[i] = os.path.join(project_dir, environment_file[i]) ''' Create a base tracking environment ''' self._base_env = env_humanoid_tracking.Env( fps_sim=config['fps_sim'], fps_act=config['fps_con'], verbose=config['verbose'], char_info_module=char_info_module, sim_char_file=sim_char_file, ref_motion_scale=ref_motion_scale, self_collision=self_collision, contactable_body=config['early_term'].get( 'falldown_contactable_body'), actuation=actuation, ) self._pb_client = self._base_env._pb_client self._dt_con = 1.0 / config['fps_con'] ''' Copy some of frequently used attributes from the base environemnt ''' self._num_agent = self._base_env._num_agent assert self._num_agent == len(base_motion_file) self._sim_agent = [ self._base_env._agent[i] for i in range(self._num_agent) ] self._v_up = self._base_env._v_up ''' State ''' self._state_choices = [ Env.StateChoice.from_string(s) for s in config['state']['choices'] ] ''' Early Terminations ''' self._early_term_choices = [ Env.EarlyTermChoice.from_string(s) for s in config['early_term']['choices'] ] self._reward_fn_def = config['reward']['fn_def'] self._reward_fn_map = config['reward']['fn_map'] self._reward_names = [ self.get_reward_names(self._reward_fn_def[self._reward_fn_map[i]]) for i in range(self._num_agent) ] ''' Check the existence of reward definitions, which are defined in our reward map ''' assert len(self._reward_fn_map) == self._num_agent for key in self._reward_fn_map: assert key in self._reward_fn_def.keys() self._verbose = config['verbose'] if Env.EarlyTermChoice.LowReward in self._early_term_choices: self._et_low_reward_thres = config['early_term'][ 'low_reward_thres'] self._rew_queue = self._num_agent * [None] for i in range(self._num_agent): self._rew_queue[i] = deque(maxlen=int(1.0 / self._dt_con)) ''' The environment automatically terminates after 'sim_window' seconds ''' if Env.EarlyTermChoice.SimWindow in self._early_term_choices: self._sim_window_time = config['early_term']['sim_window_time'] ''' The environment continues for "eoe_margin" seconds after end-of-episode is set by TRUE. This is useful for making the controller work for boundaries of reference motions ''' self._eoe_margin = config['early_term']['eoe_margin'] self._action_type = Env.ActionMode.from_string( config['action']['type']) ''' Base motion defines the initial posture (like t-pose) ''' self._base_motion = [] for i in range(self._num_agent): m = bvh.load(file=base_motion_file[i], motion=MotionWithVelocity(), scale=1.0, load_skel=True, load_motion=True, v_up_skel=self._sim_agent[i]._char_info.v_up, v_face_skel=self._sim_agent[i]._char_info.v_face, v_up_env=self._sim_agent[i]._char_info.v_up_env) m = MotionWithVelocity.from_motion(m) self._base_motion.append(m) ''' Create Kinematic Agents ''' self._kin_agent = [] for i in range(self._num_agent): self._kin_agent.append( sim_agent.SimAgent(pybullet_client=self._base_env._pb_client, model_file=sim_char_file[i], char_info=self._sim_agent[i]._char_info, ref_scale=ref_motion_scale[i], self_collision=self_collision[i], kinematic_only=True, verbose=config['verbose'])) ''' Define the action space of this environment. Here I used a 'normalizer' where 'real' values correspond to joint angles, and 'norm' values correspond to the output value of NN policy. The reason why it is used is that NN policy somtimes could output values that are within much larger or narrow range than we need for the environment. For example, if we apply tanh activation function at the last layer of NN, the output are always within (-1, 1), but we need bigger values for joint angles because 1 corresponds only to 57.3 degree. ''' self._action_space = [] for i in range(self._num_agent): dim = self._sim_agent[i].get_num_dofs() normalizer = math.Normalizer( real_val_max=config['action']['range_max'] * np.ones(dim), real_val_min=config['action']['range_min'] * np.ones(dim), norm_val_max=config['action']['range_max_pol'] * np.ones(dim), norm_val_min=config['action']['range_min_pol'] * np.ones(dim), apply_clamp=True) self._action_space.append(normalizer) self._com_vel = self._num_agent * [None] for i in range(self._num_agent): self._com_vel[i] = deque(maxlen=int(1.0 / self._dt_con)) ''' Any necessary information needed for training this environment. This can be set by calling "set_learning_info". ''' self._learning_info = {} self.add_noise = config['add_noise']
def extract_features(filepath, feature_type, thresholds=None, up_vec="z"): motion = bvh.load(filepath) if feature_type == "manual": return extract_manual_features(motion) else: return extract_kinetic_features(motion, thresholds, up_vec)
def test_cut_motion(self): motion = bvh.load(file="tests/data/sinusoidal.bvh") # Inspect 0th frame, root joint cut_motion = motion_ops.cut(motion, 3, 5) self.assertEqual(cut_motion.num_frames(), 2)
def main(args): comp_device = torch.device("cuda" if torch.cuda.is_available() else "cpu") bm = BodyModel(model_type="smplh", bm_path=args.body_model_file, num_betas=10).to(comp_device) faces = c2c(bm.f) img_shape = (1600, 1600) motion = bvh.load( file=args.input_file, scale=0.5, v_up_skel=np.array([0.0, 1.0, 0.0]), v_face_skel=np.array([0.0, 0.0, 1.0]), v_up_env=np.array([0.0, 0.0, 1.0]), ) motion = motion_ops.rotate( motion, conversions.Ax2R(conversions.deg2rad(-90)), ) mv = prepare_mesh_viewer(img_shape) out = cv2.VideoWriter(args.video_output_file, cv2.VideoWriter_fourcc(*"XVID"), 30, img_shape) parents = bm.kintree_table[0].long()[:21 + 1] parents = parents.cpu().numpy() dfs_order = get_dfs_order(parents) for frame in tqdm.tqdm(range(motion.num_frames())): pose = motion.get_pose_by_frame(frame) R, p = conversions.T2Rp(pose.data[0]) root_orient = conversions.R2A(R) trans = p num_joints = len(pose.data) - 1 body_model_pose_data = np.zeros(num_joints * 3) for motion_joint, amass_joint in enumerate(dfs_order): # motion_joint is idx of joint in Motion class order # amass_joint is idx of joint in AMASS skeleton if amass_joint == 0: continue pose_idx = amass_joint - 1 # Convert rotation matrix to axis angle axis_angles = conversions.R2A( conversions.T2R(pose.data[motion_joint])) body_model_pose_data[pose_idx * 3:pose_idx * 3 + 3] = axis_angles pose_data_t = ( torch.Tensor(body_model_pose_data).to(comp_device).unsqueeze(0)) root_orient_t = torch.Tensor(root_orient).to(comp_device).unsqueeze(0) trans_t = torch.Tensor(trans).to(comp_device).unsqueeze(0) body = bm(pose_body=pose_data_t, root_orient=root_orient_t, trans=trans_t) body_mesh = trimesh.Trimesh( vertices=c2c(body.v[0]), faces=faces, vertex_colors=np.tile(colors["grey"], (6890, 1)), ) # TODO: Add floor trimesh to the scene to display the ground plane mv.set_static_meshes([body_mesh]) body_image = mv.render() img = body_image.astype(np.uint8) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) out.write(img) out.release()