158 lines
5.7 KiB
Python
158 lines
5.7 KiB
Python
'''
|
|
@ Date: 2021-03-15 12:23:12
|
|
@ Author: Qing Shuai
|
|
@ LastEditors: Qing Shuai
|
|
@ LastEditTime: 2021-04-01 16:17:34
|
|
@ FilePath: /EasyMocap/easymocap/mytools/file_utils.py
|
|
'''
|
|
import os
|
|
import json
|
|
import numpy as np
|
|
from os.path import join
|
|
|
|
mkdir = lambda x:os.makedirs(x, exist_ok=True)
|
|
mkout = lambda x:mkdir(os.path.dirname(x))
|
|
|
|
def read_json(path):
|
|
assert os.path.exists(path), path
|
|
with open(path) as f:
|
|
data = json.load(f)
|
|
return data
|
|
|
|
def save_json(file, data):
|
|
if not os.path.exists(os.path.dirname(file)):
|
|
os.makedirs(os.path.dirname(file))
|
|
with open(file, 'w') as f:
|
|
json.dump(data, f, indent=4)
|
|
|
|
def getFileList(root, ext='.jpg'):
|
|
files = []
|
|
dirs = os.listdir(root)
|
|
while len(dirs) > 0:
|
|
path = dirs.pop()
|
|
fullname = join(root, path)
|
|
if os.path.isfile(fullname) and fullname.endswith(ext):
|
|
files.append(path)
|
|
elif os.path.isdir(fullname):
|
|
for s in os.listdir(fullname):
|
|
newDir = join(path, s)
|
|
dirs.append(newDir)
|
|
files = sorted(files)
|
|
return files
|
|
|
|
def read_annot(annotname, mode='body25'):
|
|
data = read_json(annotname)
|
|
if not isinstance(data, list):
|
|
data = data['annots']
|
|
for i in range(len(data)):
|
|
if 'id' not in data[i].keys():
|
|
data[i]['id'] = data[i].pop('personID')
|
|
if 'keypoints2d' in data[i].keys() and 'keypoints' not in data[i].keys():
|
|
data[i]['keypoints'] = data[i].pop('keypoints2d')
|
|
for key in ['bbox', 'keypoints', 'handl2d', 'handr2d', 'face2d']:
|
|
if key not in data[i].keys():continue
|
|
data[i][key] = np.array(data[i][key])
|
|
if key == 'face2d':
|
|
# TODO: Make parameters, 17 is the offset for the eye brows,
|
|
# etc. 51 is the total number of FLAME compatible landmarks
|
|
data[i][key] = data[i][key][17:17+51, :]
|
|
data[i]['bbox'] = data[i]['bbox'][:5]
|
|
if data[i]['bbox'][-1] < 0.001:
|
|
# print('{}/{} bbox conf = 0, may be error'.format(annotname, i))
|
|
data[i]['bbox'][-1] = 1
|
|
if mode == 'body25':
|
|
data[i]['keypoints'] = data[i]['keypoints']
|
|
elif mode == 'body15':
|
|
data[i]['keypoints'] = data[i]['keypoints'][:15, :]
|
|
elif mode == 'total':
|
|
data[i]['keypoints'] = np.vstack([data[i][key] for key in ['keypoints', 'handl2d', 'handr2d', 'face2d']])
|
|
elif mode == 'bodyhand':
|
|
data[i]['keypoints'] = np.vstack([data[i][key] for key in ['keypoints', 'handl2d', 'handr2d']])
|
|
elif mode == 'bodyhandface':
|
|
data[i]['keypoints'] = np.vstack([data[i][key] for key in ['keypoints', 'handl2d', 'handr2d', 'face2d']])
|
|
conf = data[i]['keypoints'][..., -1]
|
|
conf[conf<0] = 0
|
|
data.sort(key=lambda x:x['id'])
|
|
return data
|
|
|
|
def write_common_results(dumpname, results, keys, fmt='%.3f'):
|
|
mkout(dumpname)
|
|
format_out = {'float_kind':lambda x: fmt % x}
|
|
with open(dumpname, 'w') as f:
|
|
f.write('[\n')
|
|
for idata, data in enumerate(results):
|
|
f.write(' {\n')
|
|
output = {}
|
|
output['id'] = data['id']
|
|
for key in keys:
|
|
if key not in data.keys():continue
|
|
output[key] = np.array2string(data[key], max_line_width=1000, separator=', ', formatter=format_out)
|
|
for key in output.keys():
|
|
f.write(' \"{}\": {}'.format(key, output[key]))
|
|
if key != keys[-1]:
|
|
f.write(',\n')
|
|
else:
|
|
f.write('\n')
|
|
f.write(' }')
|
|
if idata != len(results) - 1:
|
|
f.write(',\n')
|
|
else:
|
|
f.write('\n')
|
|
f.write(']\n')
|
|
|
|
def write_keypoints3d(dumpname, results):
|
|
# TODO:rewrite it
|
|
keys = ['keypoints3d']
|
|
write_common_results(dumpname, results, keys, fmt='%.3f')
|
|
|
|
def write_smpl(dumpname, results):
|
|
keys = ['Rh', 'Th', 'poses', 'expression', 'shapes']
|
|
write_common_results(dumpname, results, keys)
|
|
|
|
|
|
def get_bbox_from_pose(pose_2d, img, rate = 0.1):
|
|
# this function returns bounding box from the 2D pose
|
|
# here use pose_2d[:, -1] instead of pose_2d[:, 2]
|
|
# because when vis reprojection, the result will be (x, y, depth, conf)
|
|
validIdx = pose_2d[:, -1] > 0
|
|
if validIdx.sum() == 0:
|
|
return [0, 0, 100, 100, 0]
|
|
y_min = int(min(pose_2d[validIdx, 1]))
|
|
y_max = int(max(pose_2d[validIdx, 1]))
|
|
x_min = int(min(pose_2d[validIdx, 0]))
|
|
x_max = int(max(pose_2d[validIdx, 0]))
|
|
dx = (x_max - x_min)*rate
|
|
dy = (y_max - y_min)*rate
|
|
# 后面加上类别这些
|
|
bbox = [x_min-dx, y_min-dy, x_max+dx, y_max+dy, 1]
|
|
correct_bbox(img, bbox)
|
|
return bbox
|
|
|
|
def correct_bbox(img, bbox):
|
|
# this function corrects the bbox, which is out of image
|
|
w = img.shape[0]
|
|
h = img.shape[1]
|
|
if bbox[2] <= 0 or bbox[0] >= h or bbox[1] >= w or bbox[3] <= 0:
|
|
bbox[4] = 0
|
|
return bbox
|
|
|
|
def merge_params(param_list, share_shape=True):
|
|
output = {}
|
|
for key in ['poses', 'shapes', 'Rh', 'Th', 'expression']:
|
|
if key in param_list[0].keys():
|
|
output[key] = np.vstack([v[key] for v in param_list])
|
|
if share_shape:
|
|
output['shapes'] = output['shapes'].mean(axis=0, keepdims=True)
|
|
return output
|
|
|
|
def select_nf(params_all, nf):
|
|
output = {}
|
|
for key in ['poses', 'Rh', 'Th']:
|
|
output[key] = params_all[key][nf:nf+1, :]
|
|
if 'expression' in params_all.keys():
|
|
output['expression'] = params_all['expression'][nf:nf+1, :]
|
|
if params_all['shapes'].shape[0] == 1:
|
|
output['shapes'] = params_all['shapes']
|
|
else:
|
|
output['shapes'] = params_all['shapes'][nf:nf+1, :]
|
|
return output |