|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import os |
|
import sys |
|
|
|
sys.path.append('.') |
|
|
|
import numpy as np |
|
import joblib |
|
import torch |
|
import os |
|
import joblib |
|
import argparse |
|
import numpy as np |
|
import json |
|
import smplx |
|
import glob |
|
import math |
|
|
|
from tqdm import tqdm |
|
import os.path as osp |
|
|
|
def get_body_model(model_type, gender, batch_size, device='cpu', ext='pkl'): |
|
''' |
|
type: smpl, smplx smplh and others. Refer to smplx tutorial |
|
gender: male, female, neutral |
|
batch_size: an positive integar |
|
''' |
|
mtype = model_type.upper() |
|
if gender != 'neutral': |
|
if not isinstance(gender, str): |
|
gender = str(gender.astype(str)).upper() |
|
else: |
|
gender = gender.upper() |
|
else: |
|
gender = gender.upper() |
|
ext = 'npz' |
|
body_model_path = f'./body_models/{model_type}/{mtype}_{gender}.{ext}' |
|
|
|
body_model = smplx.create(body_model_path, model_type=type, |
|
gender=gender, ext=ext, |
|
use_pca=False, |
|
num_pca_comps=12, |
|
create_global_orient=True, |
|
create_body_pose=True, |
|
create_betas=True, |
|
create_left_hand_pose=True, |
|
create_right_hand_pose=True, |
|
create_expression=True, |
|
create_jaw_pose=True, |
|
create_leye_pose=True, |
|
create_reye_pose=True, |
|
create_transl=True, |
|
batch_size=batch_size) |
|
if device == 'cuda': |
|
return body_model.cuda() |
|
else: |
|
return body_model |
|
|
|
|
|
AMASS_DIRS = [ |
|
'ACCAD/ACCAD', |
|
'BMLrub/BioMotionLab_NTroje', |
|
'CMU/CMU', |
|
'BMLmovi/BMLmovi', |
|
'EKUT/EKUT', |
|
'DFaust67/DFaust_67', |
|
'HumanEva/HumanEva', |
|
'EyesJapanDataset/Eyes_Japan_Dataset', |
|
'KIT/KIT', |
|
'MPIHDM05/MPI_HDM05', |
|
'MPILimits/MPI_Limits', |
|
'MPImosh/MPI_mosh', |
|
'SFU/SFU', |
|
'SSMsynced/SSM_synced', |
|
'TCDhandMocap/TCD_handMocap', |
|
'TotalCapture/TotalCapture', |
|
'Transitionsmocap/Transitions_mocap', |
|
'DanceDB/DanceDB', |
|
'BMLhandball/BMLhandball'] |
|
|
|
OUT_FPS = 30 |
|
DISCARD_SHORTER_THAN = 0.5 |
|
|
|
joints_to_use = np.array([ |
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, |
|
11, 12, 13, 14, 15, 16, 17, 18, 19, |
|
20, 21, 22, 37]) |
|
JOINT_SMPLH2SMPL = np.arange(0, 156).reshape((-1, 3))[joints_to_use].reshape(-1) |
|
|
|
''' |
|
EXAMPLE USAGE: |
|
|
|
python divotion/dataset/process_amass.py --input-path /ps/scratch/ps_shared/nathanasiou/data/amass_smplx |
|
--output-path /ps/scratch/ps_shared/nathanasiou/data/processed_amass_smplx_neutral_wshape |
|
--model-type smplx --use-betas |
|
|
|
''' |
|
|
|
|
|
def param_dict_for_body_model(pose_vector, trans, betas=None): |
|
body_params = {} |
|
|
|
assert pose_vector.shape[0] == trans.shape[0] |
|
seqlen = pose_vector.shape[0] |
|
|
|
if betas is None: |
|
betas = torch.from_numpy(np.zeros(10)).unsqueeze(0).repeat(seqlen, 1).float().cuda() |
|
else: |
|
betas = torch.from_numpy(betas[:10]).unsqueeze(0).repeat(seqlen, 1).float().cuda() |
|
|
|
body_params['global_orient'] = torch.from_numpy(pose_vector[:, :3]).float().cuda() |
|
body_params['body_pose'] = torch.from_numpy(pose_vector[:, 3:66]).float().cuda() |
|
body_params['left_hand_pose'] = torch.from_numpy(pose_vector[:, 66:111]).float().cuda() |
|
body_params['right_hand_pose'] = torch.from_numpy(pose_vector[:, 111:]).float().cuda() |
|
body_params['transl'] = torch.from_numpy(trans).float().cuda() |
|
body_params['betas'] = betas |
|
|
|
return body_params |
|
|
|
|
|
def process_sequence(filename, use_betas, |
|
gender): |
|
f_id = '/'.join(filename.split('/')[-4:]) |
|
|
|
|
|
try: |
|
amass_sequence_data = dict(np.load(filename, allow_pickle=True)) |
|
except: |
|
print(f'Could not load {filename}') |
|
return {} |
|
|
|
|
|
sequence_fps = amass_sequence_data['mocap_framerate'] |
|
|
|
|
|
if filename.find('BMLhandball') >= 0: |
|
sequence_fps = 240 |
|
if filename.find('20160930_50032') >= 0 or \ |
|
filename.find('20161014_50033') >= 0: |
|
sequence_fps = 59 |
|
|
|
num_frames = amass_sequence_data['poses'].shape[0] |
|
|
|
|
|
if num_frames < DISCARD_SHORTER_THAN * sequence_fps: |
|
return {} |
|
|
|
if OUT_FPS > sequence_fps: |
|
print('Cannot supersample data, saving at data rate!') |
|
else: |
|
fps_ratio = float(OUT_FPS) / sequence_fps |
|
new_num_frames = int(fps_ratio * num_frames) |
|
|
|
|
|
downsample_ids = np.linspace(0, num_frames - 1, |
|
num=new_num_frames, dtype=int) |
|
|
|
pose_feats = ['trans', 'poses'] |
|
|
|
for k, v in amass_sequence_data.items(): |
|
if k in pose_feats: |
|
amass_sequence_data[k] = v[downsample_ids] |
|
final_seq_data = {} |
|
|
|
final_seq_data['poses'] = amass_sequence_data['poses'] |
|
gender_of_seq = amass_sequence_data['gender'] |
|
if 'SSM_synced' in filename: |
|
gender_of_seq = np.array(amass_sequence_data['gender'], ndmin=1)[0] |
|
|
|
gender_of_seq = str(gender_of_seq, 'utf-8') \ |
|
if isinstance(gender_of_seq, bytes) \ |
|
else str(gender_of_seq) |
|
|
|
final_seq_data['trans'] = amass_sequence_data['trans'] |
|
final_seq_data['fps'] = OUT_FPS |
|
final_seq_data['fname'] = f_id |
|
if gender != 'amass': |
|
body_model_type = f'smplh_{gender}' |
|
if use_betas: |
|
final_seq_data['betas'] = amass_sequence_data['betas'] |
|
body_params = param_dict_for_body_model(final_seq_data['poses'], |
|
final_seq_data['trans'], |
|
betas=final_seq_data['betas']) |
|
else: |
|
body_params = param_dict_for_body_model(final_seq_data['poses'], |
|
final_seq_data['trans']) |
|
|
|
|
|
body_joint_chunk = [] |
|
slice_ids = [0, min([new_num_frames, 1500])] |
|
while slice_ids[0] < new_num_frames: |
|
|
|
sidx, eidx = slice_ids |
|
body_params_temp = {} |
|
for k, v in body_params.items(): |
|
body_params_temp[k] = v[sidx:eidx] |
|
bodymodel_seq = get_body_model('smplh', gender_of_seq if gender == 'amass' else gender, |
|
eidx - sidx, device='cuda') |
|
|
|
smplh_output = bodymodel_seq(return_verts=True, **body_params_temp) |
|
|
|
|
|
joints_temp = smplh_output.joints.detach().cpu().numpy() |
|
|
|
if model_type == 'smpl': |
|
joints_temp = smplh_output.joints[:, :22].detach().cpu().numpy() |
|
|
|
body_joint_chunk.append(joints_temp) |
|
|
|
slice_ids[0] = slice_ids[1] |
|
slice_ids[1] = min([new_num_frames, slice_ids[1] + 1000]) |
|
|
|
joint_pos = np.concatenate(body_joint_chunk, axis=0) |
|
|
|
final_seq_data['joint_positions'] = joint_pos |
|
|
|
return final_seq_data |
|
|
|
|
|
def read_data(input_dir, model_type, output_dir, use_betas, gender): |
|
amass_subsets = [f'{input_dir}/{x}' for x in AMASS_DIRS |
|
if os.path.isdir(f'{input_dir}/{x}')] |
|
|
|
all_data = [] |
|
for sset in amass_subsets: |
|
seqs = glob.glob(f'{sset}/*/*.npz') |
|
dataset_name = sset.strip().split('/')[-1] |
|
print('-- processing subset {:s}'.format(dataset_name)) |
|
dataset_db_list = [] |
|
out_dir = f'{output_dir}/{dataset_name}' |
|
if os.path.isdir(out_dir) and any(os.scandir(out_dir)): |
|
print(f'The directory: {out_dir}/{dataset_name} ' \ |
|
'is not empty, so continuing to the next dataset..') |
|
continue |
|
|
|
for seq in tqdm(seqs): |
|
|
|
if os.path.basename(seq) == 'neutral_stagei.npz' or \ |
|
os.path.basename(seq) == 'shape.npz': |
|
continue |
|
final_seq_data = process_sequence(seq, use_betas, gender) |
|
if final_seq_data: |
|
dataset_db_list.append(final_seq_data) |
|
os.makedirs(out_dir, exist_ok=True) |
|
|
|
dataset_db_fname = f'{out_dir}/{dataset_name}.pth.tar' |
|
no_segs = len(dataset_db_list) |
|
print(f'Finished {dataset_name} resulting in {no_segs} sequences..') |
|
print(f'Saving {dataset_name} dataset to {dataset_db_fname}...') |
|
joblib.dump(dataset_db_list, dataset_db_fname) |
|
all_data.extend(dataset_db_list) |
|
|
|
joblib.dump(all_data, f'{output_dir}/amass.pth.tar') |
|
|
|
|
|
if __name__ == '__main__': |
|
parser = argparse.ArgumentParser() |
|
|
|
parser.add_argument('--input-path', required=False, type=str, |
|
default='./Datasets/amass', |
|
help='input path of AMASS data in unzipped format without anything else.') |
|
parser.add_argument('--output-path', required=False, type=str, |
|
default='./data_loaders/babel/babel-smplh-30fps-male', |
|
help='output path of AMASS data in unzipped format without anything else.') |
|
parser.add_argument('--use-betas', default=False, action='store_true', |
|
help='creates submission files for cluster') |
|
parser.add_argument('--gender', required=True, choices=['male', 'female', |
|
'neutral', 'amass'], |
|
type=str, help='hard-code the gender or use amass gender') |
|
|
|
args = parser.parse_args() |
|
input_dir = args.input_path |
|
output_dir = args.output_path |
|
use_betas = args.use_betas |
|
gender = args.gender |
|
model_type = 'smplh' |
|
|
|
print(f'Input arguments: \n {args}') |
|
|
|
db = read_data(input_dir, model_type, output_dir, use_betas, gender) |
|
|