Upload 11 files
Browse files- REC-MV_preprocess.md +68 -0
- depth2normal.py +146 -0
- get_smpl_rec_camera.py +84 -0
- inference.py +31 -0
- mv_featurelines.py +42 -0
- normal_test.py +34 -0
- parsing_mask_to_fl.py +388 -0
- process_data_all.py +149 -0
- rename.py +18 -0
- requirements.txt +266 -0
- smpl_process.py +40 -0
REC-MV_preprocess.md
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# This is the tutorial of data processing of REC-MV.
|
2 |
+
|
3 |
+
The data pre-processing part includes img, mask, normal, parsing (garment segmentation), camera, smpl parameters (beta & theta), featurelines, skinning weight.
|
4 |
+
## Step0
|
5 |
+
set up the environment (or you can directly use REC-MV environment)
|
6 |
+
```
|
7 |
+
pip install -r requirements.txt
|
8 |
+
```
|
9 |
+
|
10 |
+
|
11 |
+
## Step1
|
12 |
+
You should make directory to save all processed data, named, to say, xiaoming.
|
13 |
+
And you turn the video into images:
|
14 |
+
```
|
15 |
+
encodepngffmpeg()
|
16 |
+
{
|
17 |
+
# $1: target folder
|
18 |
+
# $2: save video name
|
19 |
+
ffmpeg -r ${1} -pattern_type glob -i '*.png' -vcodec libx264 -crf 18 -vf "pad=ceil(iw/2)*2:ceil(ih/2)*2" -pix_fmt yuv420p ${2}
|
20 |
+
}
|
21 |
+
|
22 |
+
|
23 |
+
encodepngffmpeg 30 ./xiaoming.mp4
|
24 |
+
```
|
25 |
+
Then, your data directory:
|
26 |
+
```
|
27 |
+
xiaoming/
|
28 |
+
└── imgs
|
29 |
+
```
|
30 |
+
## Step2 Normal, Parsing, and Mask
|
31 |
+
Get the normal map, parsing mask, masks.
|
32 |
+
```
|
33 |
+
python prcess_data_all.py --gid <gpu_id> --root <Your data root> --gender <data gender>
|
34 |
+
# example
|
35 |
+
python prcess_data_all.py --gid 0 --root /data/xiaoming --gender male
|
36 |
+
```
|
37 |
+
Your data directory:
|
38 |
+
```
|
39 |
+
xiaoming/
|
40 |
+
├── imgs
|
41 |
+
├── masks
|
42 |
+
├── normals
|
43 |
+
└── parsing_SCH_ATR
|
44 |
+
```
|
45 |
+
|
46 |
+
## Step3 SMPL & Camera
|
47 |
+
To get smpl paramaters (pose and shape), here we use [videoavatar](https://github.com/thmoa/videoavatars):
|
48 |
+
- Set up the env (**Note it use python2**)
|
49 |
+
- Prepare keypoints files for each frame in the video and put them under `xiaoming/openpose`, which I use [Openpose](https://github.com/CMU-Perceptual-Computing-Lab/openpose).
|
50 |
+
- Run three python files in videoavatars/prepare_data, you'll get `keypoints.hdf5, masks.hdf5, camera.hdf5.` Or you can just use my script: ```cd videoavatars; python get_reconstructed_poses.py --root xiaoming --out xiaoming --gender male```
|
51 |
+
- `bash run_step1.sh`
|
52 |
+
|
53 |
+
After you run through videoavatar, you will get `camera.pkl, reconstructed_poses.hdf5`. Put it also under the root(xiaoming).
|
54 |
+
|
55 |
+
You can get `smpl_rec.npz, camera.npz` by running:
|
56 |
+
```
|
57 |
+
python get_smpl_rec_camera.py --root xiaoming --save_root xiaoming --gender male
|
58 |
+
```
|
59 |
+
|
60 |
+
**Note: You can use any other smpl estimation algorithm, but you should follow the way how smpl_rec.npz save pose, shape, and trans.**
|
61 |
+
|
62 |
+
## Step4 Skining Weight
|
63 |
+
We follow [fite](https://github.com/jsnln/fite) to get the lbs skinning weight to prevent artifacts.
|
64 |
+
|
65 |
+
In fite's readme, you'll get a skining weight cube after finishing 3.Diffused Skinning. Name it `diffused_skinning_weights.npy` and put it under xiaoming.
|
66 |
+
|
67 |
+
|
68 |
+
|
depth2normal.py
ADDED
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import cv2
|
2 |
+
from cv2 import imread
|
3 |
+
import numpy as np
|
4 |
+
from numpy import unique, load
|
5 |
+
import argparse
|
6 |
+
import os, os.path as osp
|
7 |
+
import tqdm
|
8 |
+
import pdb
|
9 |
+
|
10 |
+
def parse_args():
|
11 |
+
parser = argparse.ArgumentParser()
|
12 |
+
parser.add_argument('--root', type=str, required=True, help='root dir of one identity')
|
13 |
+
parser.add_argument('--cam_file', type=str, default='camera.npz')
|
14 |
+
|
15 |
+
parser.add_argument('--depth_dir', help='depth map path', default='depth', type=str)
|
16 |
+
parser.add_argument('--out_dir', '-n', help='outputnormal path', default='normal_depth', type=str)
|
17 |
+
parser.add_argument('--mask_dir', help='mask path', default='masks', type=str)
|
18 |
+
parser.add_argument('--mask_total_dir', help='total mask path', default='masks_total', type=str)
|
19 |
+
args = parser.parse_args()
|
20 |
+
return args
|
21 |
+
|
22 |
+
def get_surface_normal_by_depth(depth, fx, fy):
|
23 |
+
"""
|
24 |
+
depth: (h, w) of float, the unit of depth is meter
|
25 |
+
K: (3, 3) of float, the depth camere's intrinsic
|
26 |
+
"""
|
27 |
+
|
28 |
+
dz_dv, dz_du = np.gradient(depth) # u, v mean the pixel coordinate in the image
|
29 |
+
# u*depth = fx*x + cx --> du/dx = fx / dept
|
30 |
+
# smooth
|
31 |
+
# dz_du = cv2.Sobel(depth, cv2.CV_64F, 1, 0, ksize=5)
|
32 |
+
# dz_dv = cv2.Sobel(depth, cv2.CV_64F, 0, 1, ksize=5)
|
33 |
+
du_dx = fx / depth # x is xyz of camera coordinate
|
34 |
+
dv_dy = fy / depth
|
35 |
+
|
36 |
+
dz_dx = dz_du * du_dx
|
37 |
+
dz_dy = dz_dv * dv_dy
|
38 |
+
# cross-product (1,0,dz_dx)X(0,1,dz_dy) = (-dz_dx, -dz_dy, 1)
|
39 |
+
normal_cross = np.dstack((-dz_dx, -dz_dy, np.ones_like(depth)))
|
40 |
+
# normalize to unit vector
|
41 |
+
normal_unit = normal_cross / np.linalg.norm(normal_cross, axis=2, keepdims=True)
|
42 |
+
# set default normal to [0, 0, 1]
|
43 |
+
# pdb.set_trace()
|
44 |
+
nan_mask = np.isfinite(normal_unit).all(2)
|
45 |
+
normal_unit[~np.isfinite(normal_unit).all(2)] = [-1, -1, -1]
|
46 |
+
return normal_unit, nan_mask
|
47 |
+
|
48 |
+
# def delete_holes(img):
|
49 |
+
# im = img.copy()
|
50 |
+
# h, w = im.shape[:2]
|
51 |
+
# mask = np.zeros((h+2, w+2), dtype=np.uint8)
|
52 |
+
# holes = cv2.floodFill(im.copy(), mask, (0, 0), 255)[1]
|
53 |
+
# holes = ~holes
|
54 |
+
# im[holes == 255] = 255
|
55 |
+
# return im
|
56 |
+
def denoise(img):
|
57 |
+
|
58 |
+
kernel = np.ones((11, 11), np.uint8)
|
59 |
+
img= cv2.erode(img, kernel, iterations=2)
|
60 |
+
img= cv2.dilate(img, kernel, iterations=2)
|
61 |
+
|
62 |
+
return img
|
63 |
+
|
64 |
+
def main():
|
65 |
+
args = parse_args()
|
66 |
+
root = args.root
|
67 |
+
cam_file = osp.join(root, args.cam_file)
|
68 |
+
depth_dir = osp.join(root, args.depth_dir)
|
69 |
+
out_dir = osp.join(root, args.out_dir)
|
70 |
+
os.makedirs(out_dir, exist_ok=True)
|
71 |
+
mask_dir = osp.join(root, args.mask_dir)
|
72 |
+
mask_total_dir = osp.join(root, args.mask_total_dir)
|
73 |
+
os.makedirs(mask_total_dir, exist_ok=True)
|
74 |
+
|
75 |
+
cam = np.load(cam_file)
|
76 |
+
fx, fy = cam['fx'], cam['fy']
|
77 |
+
|
78 |
+
assert osp.exists(depth_dir), 'depth dir not exists'
|
79 |
+
|
80 |
+
depth_paths = sorted([
|
81 |
+
osp.join(depth_dir, f) for f in os.listdir(depth_dir)])
|
82 |
+
mask_paths = sorted([osp.join(mask_dir, f) for f in os.listdir(mask_dir)])
|
83 |
+
|
84 |
+
|
85 |
+
assert depth_paths[0].endswith('.npy'), 'depth dir must be .npy'
|
86 |
+
|
87 |
+
# [-1,1] -> [0, 2]/2 -> [0,1]*255 -> [0,255]
|
88 |
+
vis_normal = lambda normal: np.uint8((normal + 1) / 2 * 255)[..., ::-1]
|
89 |
+
for idx, depth_p in enumerate(depth_paths):
|
90 |
+
|
91 |
+
# mask is [0, 1]
|
92 |
+
mask = cv2.imread(mask_paths[idx], -1)[..., 0] / 255
|
93 |
+
assert len(mask.shape) == 2, 'dims of mask are not 2'
|
94 |
+
|
95 |
+
depth = np.load(depth_p) # the unit of depth is meter
|
96 |
+
# the val of normal is between [-1, 1]
|
97 |
+
normal, nan_mask = get_surface_normal_by_depth(depth, fx, fy)
|
98 |
+
mask_total = nan_mask * mask
|
99 |
+
#mask_total = denoise(mask_total)
|
100 |
+
# normal should be filtered by mask and nan_mask
|
101 |
+
normal = vis_normal(normal) * mask_total[..., None]
|
102 |
+
|
103 |
+
cv2.imwrite(osp.join(out_dir, f'{idx:05d}.png'), normal)
|
104 |
+
cv2.imwrite(osp.join(mask_total_dir, f'{idx:05d}.png'), mask_total.astype(np.uint8) * 255)
|
105 |
+
#cv2.imwrite(osp.join(root, 'nan_mask.png'), nan_mask.astype(np.uint8))
|
106 |
+
#xxx
|
107 |
+
|
108 |
+
|
109 |
+
|
110 |
+
if __name__ == '__main__':
|
111 |
+
#os.makedirs(args.normalPath, exist_ok = True)
|
112 |
+
main()
|
113 |
+
''' if args.totalmaskPath:
|
114 |
+
os.makedirs(args.totalmaskPath, exist_ok = True)
|
115 |
+
for img_name in tqdm.tqdm(sorted(os.listdir(args.depthPath))):
|
116 |
+
img_path = os.path.join(args.depthPath, img_name)
|
117 |
+
depth = cv2.imread(img_path, -1) / 1000.0
|
118 |
+
normal, nan_mask = get_surface_normal_by_depth(depth)
|
119 |
+
|
120 |
+
vis_normal = lambda normal: np.uint8((normal + 1) / 2 * 255)[..., ::-1]
|
121 |
+
normal = vis_normal(normal)
|
122 |
+
if args.maskPath:
|
123 |
+
mask_path = os.path.join(args.maskPath, img_name[:-4] + '_mask' + img_name[-4:])
|
124 |
+
mask = cv2.imread(mask_path)
|
125 |
+
mask = cv2.rotate(mask, cv2.ROTATE_90_CLOCKWISE)
|
126 |
+
total_mask = mask[..., 0] * nan_mask
|
127 |
+
# cv2.imwrite(os.path.join(args.totalmaskPath, img_name), np.uint8(nan_mask*255))
|
128 |
+
# cv2.imwrite(os.path.join(args.totalmaskPath, img_name), total_mask)
|
129 |
+
kernel = np.ones((11, 11), np.uint8)
|
130 |
+
total_mask = cv2.erode(total_mask, kernel, iterations=1)
|
131 |
+
total_mask = cv2.dilate(total_mask, kernel, iterations=1)
|
132 |
+
# pdb.set_trace()
|
133 |
+
normal = np.uint8(total_mask[..., None]/255) * normal
|
134 |
+
|
135 |
+
if args.totalmaskPath:
|
136 |
+
# cv2.imwrite(os.path.join(args.totalmaskPath, img_name), delete_holes(total_mask))
|
137 |
+
total_mask = cv2.rotate(total_mask, cv2.ROTATE_90_COUNTERCLOCKWISE)
|
138 |
+
cv2.imwrite(os.path.join(args.totalmaskPath, img_name), total_mask)
|
139 |
+
# pdb.set_trace()
|
140 |
+
|
141 |
+
normal_path = os.path.join(args.normalPath, img_name)
|
142 |
+
normal = cv2.rotate(normal, cv2.ROTATE_90_COUNTERCLOCKWISE)
|
143 |
+
cv2.imwrite(normal_path, normal)
|
144 |
+
|
145 |
+
'''
|
146 |
+
|
get_smpl_rec_camera.py
ADDED
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'''
|
2 |
+
@Desc: From camera.pkl and reconstructed_poses.hdf5, get the camera.npz and smpl_rec.npz
|
3 |
+
Example: python xxx.py --root /home/zjp/DeepDynamicFashion/Data_depth/xinyu_a --save_root /home/zjp/DeepDynamicFashion/Data_depth/xinyu_a --gender female
|
4 |
+
'''
|
5 |
+
import h5py
|
6 |
+
import pickle
|
7 |
+
import numpy as np
|
8 |
+
import torch
|
9 |
+
import os
|
10 |
+
import os.path as osp
|
11 |
+
import cv2
|
12 |
+
from tqdm import tqdm
|
13 |
+
from glob import glob
|
14 |
+
import shutil
|
15 |
+
import argparse
|
16 |
+
parser = argparse.ArgumentParser(description='neu video body rec')
|
17 |
+
parser.add_argument('--root',default=None,metavar='M',
|
18 |
+
help='data root')
|
19 |
+
parser.add_argument('--sid',default=0,type=int,metavar='IDs',
|
20 |
+
help='start frame index')
|
21 |
+
parser.add_argument('--save_root',default=None,metavar='M',
|
22 |
+
help='save data root')
|
23 |
+
parser.add_argument('--gender', type=str, default='female')
|
24 |
+
args = parser.parse_args()
|
25 |
+
|
26 |
+
root=args.root
|
27 |
+
sid=args.sid
|
28 |
+
gender=args.gender
|
29 |
+
save_root=args.save_root
|
30 |
+
os.makedirs(save_root,exist_ok=True)
|
31 |
+
|
32 |
+
#rgb_root=osp.join(save_root,'imgs')
|
33 |
+
#if not osp.isdir(rgb_root):
|
34 |
+
# os.makedirs(rgb_root)
|
35 |
+
#
|
36 |
+
img_files = sorted(glob(os.path.join(root,'imgs/*.jpg')))
|
37 |
+
frame_num = len(img_files)
|
38 |
+
|
39 |
+
#for ind in tqdm(range(len(img_files)),desc='rgbs'):
|
40 |
+
# src_img = img_files[ind]
|
41 |
+
# target_img = osp.join(rgb_root,'%06d.jpg'%(ind-sid))
|
42 |
+
# shutil.copy2(src_img, target_img)
|
43 |
+
|
44 |
+
|
45 |
+
with h5py.File(osp.join(root,'reconstructed_poses.hdf5'),'r') as ff:
|
46 |
+
shape=ff['betas'][:].reshape(10)
|
47 |
+
poses=ff['pose'][:].reshape(-1,24,3)[sid:,:,:]
|
48 |
+
trans=ff['trans'][:].reshape(-1,3)[sid:,:]
|
49 |
+
assert(poses.shape[0]>=frame_num-sid and trans.shape[0]>=frame_num-sid)
|
50 |
+
np.savez(osp.join(save_root,'smpl_rec.npz'),poses=poses,shape=shape,trans=trans,gender=gender)
|
51 |
+
|
52 |
+
#with h5py.File(osp.join(root,'masks.hdf5'),'r') as ff:
|
53 |
+
# fnum=ff['masks'].shape[0]
|
54 |
+
# assert fnum>sid
|
55 |
+
# mask_root=osp.join(save_root,'masks')
|
56 |
+
# os.makedirs(mask_root,exist_ok=True)
|
57 |
+
# for ind in tqdm(range(sid,fnum),desc='masks'):
|
58 |
+
# cv2.imwrite(osp.join(mask_root,'%06d.png'%(ind-sid)),ff['masks'][ind]*255)
|
59 |
+
|
60 |
+
|
61 |
+
with open(osp.join(root,'camera.pkl'),'rb') as ff:
|
62 |
+
cam_data=pickle.load(ff,encoding='latin1')
|
63 |
+
ps=cam_data['camera_c']
|
64 |
+
fs=cam_data['camera_f']
|
65 |
+
trans=cam_data['camera_t']
|
66 |
+
rt=cam_data['camera_rt']
|
67 |
+
assert(np.linalg.norm(rt)<0.0001) # The cameras of snapshot dataset seems no rotation and translation
|
68 |
+
H=cam_data['height']
|
69 |
+
W=cam_data['width']
|
70 |
+
|
71 |
+
quat=np.array([np.cos(np.pi/2.),0.,0.,np.sin(np.pi/2.)])
|
72 |
+
T=trans
|
73 |
+
fx=fs[0]
|
74 |
+
fy=fs[1]
|
75 |
+
cx=ps[0]
|
76 |
+
cy=ps[1]
|
77 |
+
print(fx,fy,cx,cy,quat,T)
|
78 |
+
|
79 |
+
np.savez(osp.join(save_root,'camera.npz'),fx=fx,fy=fy,cx=cx,cy=cy,quat=quat,T=T)
|
80 |
+
|
81 |
+
|
82 |
+
|
83 |
+
|
84 |
+
|
inference.py
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'''
|
2 |
+
This file is written to finish the preprocess of REC-MV:
|
3 |
+
- mask
|
4 |
+
- normal
|
5 |
+
- smpl params
|
6 |
+
- parse masks
|
7 |
+
'''
|
8 |
+
|
9 |
+
import json, os, os.path as osp, sys, shutil, glob, pdb, argparse
|
10 |
+
|
11 |
+
def parse_args():
|
12 |
+
parser = argparse.ArgumentParser()
|
13 |
+
parser.add_argument('--root', type=str)
|
14 |
+
parser.add_argument('--avatar_dir', type=str)
|
15 |
+
args = parser.parse_args()
|
16 |
+
return args
|
17 |
+
|
18 |
+
def main():
|
19 |
+
args = parse_args()
|
20 |
+
root = args.root
|
21 |
+
# TODO: get mask
|
22 |
+
|
23 |
+
# TODO: get normal
|
24 |
+
os.system('cd ./pifuhd && python generate_normals.py --imgpath {}'.format(osp.join(root, 'imgs')))
|
25 |
+
# get smpl_rec.npz
|
26 |
+
avatar_dir = osp.join(args.root, args.avatar_dir)
|
27 |
+
os.system('cd ./videoavatars && python get_reconstructed_poses.py --root {} --out {}'.format(args.root, avatar_dir))
|
28 |
+
os.system('cd ../ && python get_smpl_rec_camera.py --root {} --save-root {}'.format(args.root, args.root))
|
29 |
+
|
30 |
+
if __name__ == '__main__':
|
31 |
+
main()
|
mv_featurelines.py
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'''
|
2 |
+
@File : mv_featurelines.py
|
3 |
+
@Author : Jiapeng Zhou
|
4 |
+
@Desc : move part of featurelines to another annotation labelme json files (bottom_curve are good, but left_cuff arenot)
|
5 |
+
'''
|
6 |
+
|
7 |
+
import os, os.path as osp, sys, pdb, json, shutil, argparse
|
8 |
+
|
9 |
+
def parse_args():
|
10 |
+
parser = argparse.ArgumentParser()
|
11 |
+
parser.add_argument('--src-dir', type=str)
|
12 |
+
parser.add_argument('--dst-dir', type=str)
|
13 |
+
args = parser.parse_args()
|
14 |
+
return args
|
15 |
+
|
16 |
+
def main():
|
17 |
+
args = parse_args()
|
18 |
+
src_dir = args.src_dir
|
19 |
+
dst_dir = args.dst_dir
|
20 |
+
src_files = sorted([osp.join(src_dir, f) for f in os.listdir(src_dir) if f.endswith('.json')])
|
21 |
+
dst_files = sorted([osp.join(dst_dir, f) for f in os.listdir(dst_dir) if f.endswith('.json')])
|
22 |
+
assert len(src_files) == len(dst_files), 'src_files and dst_files should have same length'
|
23 |
+
for idx, (src_file, dst_file) in enumerate(zip(src_files, dst_files)):
|
24 |
+
with open(src_file) as fp:
|
25 |
+
src_json = json.load(fp)
|
26 |
+
with open(dst_file) as fp:
|
27 |
+
dst_json = json.load(fp)
|
28 |
+
src_shapes = src_json['shapes']
|
29 |
+
dst_shapes = dst_json['shapes']
|
30 |
+
|
31 |
+
for src_shape in src_shapes:
|
32 |
+
if src_shape['label'] == 'bottom_curve':
|
33 |
+
dst_shapes.append(src_shape)
|
34 |
+
dst_json['shapes'] = dst_shapes
|
35 |
+
|
36 |
+
with open(dst_file, 'w') as fp:
|
37 |
+
json.dump(dst_json, fp)
|
38 |
+
print('finish {}/{}'.format(idx+1, len(src_files)))
|
39 |
+
|
40 |
+
|
41 |
+
if __name__ == '__main__':
|
42 |
+
main()
|
normal_test.py
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'''
|
2 |
+
@Description: The script is to transfer the normal map from world coordinate to camera coordinate
|
3 |
+
'''
|
4 |
+
import os, os.path as osp, numpy as np, cv2, argparse, tqdm, pdb
|
5 |
+
|
6 |
+
def parse_args():
|
7 |
+
parser = argparse.ArgumentParser()
|
8 |
+
parser.add_argument('--root', type=str)
|
9 |
+
parser.add_argument('--out_dir', type=str, default='normal_test')
|
10 |
+
return parser.parse_args()
|
11 |
+
|
12 |
+
def convert_normal_map():
|
13 |
+
args = parse_args()
|
14 |
+
normal_dir = osp.join(args.root, 'normals')
|
15 |
+
normal_paths = sorted([osp.join(normal_dir, name) for name in os.listdir(normal_dir)])
|
16 |
+
out_dir = osp.join(args.root, args.out_dir)
|
17 |
+
os.makedirs(out_dir, exist_ok=True)
|
18 |
+
|
19 |
+
for idx, norm_f in enumerate(normal_paths):
|
20 |
+
normals = cv2.imread(norm_f)[:, :, ::-1]
|
21 |
+
normals = 2.* normals.astype(np.float32)/255. - 1. # [0, 255] -> [-1, 1]
|
22 |
+
normals =
|
23 |
+
cv2.imwrite(osp.join(out_dir, f'{idx:05d}.png'), normals)
|
24 |
+
pdb.set_trace()
|
25 |
+
|
26 |
+
|
27 |
+
|
28 |
+
|
29 |
+
|
30 |
+
def main():
|
31 |
+
convert_normal_map()
|
32 |
+
|
33 |
+
if __name__ == '__main__':
|
34 |
+
main()
|
parsing_mask_to_fl.py
ADDED
@@ -0,0 +1,388 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
@File: parsing_mask_to_fl.py
|
3 |
+
@Author: Lingteng Qiu
|
4 |
+
@Email: qiulingteng@link.cuhk.edu.cn
|
5 |
+
@Date: 2022-10-19
|
6 |
+
@Desc: parsing mask to polygons, given a series of mask infos
|
7 |
+
"""
|
8 |
+
import sys
|
9 |
+
sys.path.extend('./')
|
10 |
+
import argparse
|
11 |
+
import os
|
12 |
+
import glob
|
13 |
+
import os.path as osp
|
14 |
+
import numpy as np
|
15 |
+
import cv2
|
16 |
+
import pdb
|
17 |
+
import cv2
|
18 |
+
import json
|
19 |
+
from pytorch3d.ops.knn import knn_points
|
20 |
+
import torch
|
21 |
+
from utils.constant import FL_EXTRACT, TEMPLATE_GARMENT
|
22 |
+
'''
|
23 |
+
关于如何从parsing_mask提取featureline:
|
24 |
+
需要 parse_mask,标的两个点的json文件,但是如果出现了手遮挡住腰间的情况(或者头发遮挡neck),那么就要标注六个点绕过去
|
25 |
+
'''
|
26 |
+
|
27 |
+
FL_COLOR = {
|
28 |
+
'neck':(0, 0, 255),
|
29 |
+
'right_cuff': (0, 255, 0),
|
30 |
+
'left_cuff':(255, 0, 0),
|
31 |
+
'left_pant': (127, 127, 0),
|
32 |
+
'right_pant':(0, 127, 127),
|
33 |
+
'upper_bottom': (127, 0, 127),
|
34 |
+
'bottom_curve':(0, 127, 127),
|
35 |
+
}
|
36 |
+
|
37 |
+
def draw_lines(pts, color, img=None):
|
38 |
+
#pdb.set_trace()
|
39 |
+
if img is None:
|
40 |
+
img = np.zeros((1080, 1080, 3), np.uint8)
|
41 |
+
for i in range(len(pts)-1):
|
42 |
+
cv2.line(img, (int(pts[i][0]), int(pts[i][1])), (int(pts[i+1][0]), int(pts[i+1][1])), color, 2)
|
43 |
+
return img
|
44 |
+
|
45 |
+
def draw_pts(pts, color, img=None):
|
46 |
+
#pdb.set_trace()
|
47 |
+
if img is None:
|
48 |
+
img = np.zeros((1080, 1080, 3), np.uint8)
|
49 |
+
for i, pt in enumerate(pts):
|
50 |
+
cv2.circle(img, (int(pt[0]), int(pt[1])), 2, color, -1)
|
51 |
+
return img
|
52 |
+
|
53 |
+
|
54 |
+
class PolyMask(object):
|
55 |
+
def __init__(self, mask):
|
56 |
+
self.mask = mask
|
57 |
+
|
58 |
+
def query(self,query_sets ,labels, garment_key):
|
59 |
+
'''
|
60 |
+
query_sets 必须要偶数个 why?
|
61 |
+
1、计算featureline和mask的交点
|
62 |
+
2、如果交点数 > 2,找到一个交点对(两个交点),线段在特征线上并且在mask中的部分最长
|
63 |
+
3、通过这个交点对来获得featureline: 交点对 + 两点之间的mask边界
|
64 |
+
Args:
|
65 |
+
labels: only cloth?
|
66 |
+
'''
|
67 |
+
|
68 |
+
mask = np.zeros_like(self.mask, dtype= np.bool)
|
69 |
+
#pdb.set_trace()
|
70 |
+
|
71 |
+
for label in labels:
|
72 |
+
label_mask = np.zeros_like(self.mask, dtype =np.bool)
|
73 |
+
#pdb.set_trace()
|
74 |
+
i,j = np.where(self.mask == label)
|
75 |
+
label_mask[i,j] = True
|
76 |
+
|
77 |
+
mask |= label_mask
|
78 |
+
|
79 |
+
# [0, 255]
|
80 |
+
mask = mask.astype(np.uint8)*255
|
81 |
+
mask = self.smooth_noise(mask)
|
82 |
+
|
83 |
+
mask_polygons, mask_area = self.mask2polygon(mask)
|
84 |
+
# img_org = cv2.imread('./debug/多边形.png', -1)
|
85 |
+
# img=draw_lines(query_sets['neck'], (0, 255, 0), img_org)
|
86 |
+
length_dp = []
|
87 |
+
for mask_polygon in mask_polygons:
|
88 |
+
#pdb.set_trace()
|
89 |
+
dis = [0]
|
90 |
+
dis.extend([abs(mask_polygon[p_i][0]- mask_polygon[p_i+1][0]) + abs(mask_polygon[p_i][1]- mask_polygon[p_i+1][1]) for p_i in range(mask_polygon.shape[0]-1)])
|
91 |
+
dis.append(abs(mask_polygon[0][0]- mask_polygon[-1][0]) + abs(mask_polygon[0][1]- mask_polygon[-1][1]))
|
92 |
+
# 累计距离
|
93 |
+
dp = np.cumsum(dis)
|
94 |
+
length_dp.append(dp)
|
95 |
+
new_query_sets = {}
|
96 |
+
reply_pts = np.concatenate(mask_polygons, axis=0)
|
97 |
+
reply_pts = torch.from_numpy(reply_pts).float().cuda()
|
98 |
+
|
99 |
+
#pdb.set_trace()
|
100 |
+
|
101 |
+
for key in query_sets.keys():
|
102 |
+
polygon = query_sets[key]
|
103 |
+
# len(featureline points) % 2 == 0
|
104 |
+
assert polygon.shape[0] % 2 == 0
|
105 |
+
# 两两组合
|
106 |
+
polygons = polygon.reshape(-1, 2, 2)
|
107 |
+
|
108 |
+
group = []
|
109 |
+
for group_id, mask_polygon in enumerate(mask_polygons):
|
110 |
+
group.extend([group_id for i in range(mask_polygon.shape[0])])
|
111 |
+
group = torch.tensor(group).long()
|
112 |
+
new_polygons=[]
|
113 |
+
pre_polygon = None
|
114 |
+
# 循环每个顶点对
|
115 |
+
for polygon in polygons:
|
116 |
+
|
117 |
+
polygon = torch.from_numpy(polygon).float().cuda()
|
118 |
+
if pre_polygon is not None:
|
119 |
+
dis = torch.sqrt(((polygon[0] - pre_polygon[-1]) **2).sum())
|
120 |
+
# if two pts are close, directly add the polygon the new_polygons, avoid the situation that the hands or hair block the mask
|
121 |
+
if dis < 10:
|
122 |
+
new_polygons.append(polygon.detach().cpu().numpy())
|
123 |
+
pre_polygon = None
|
124 |
+
continue
|
125 |
+
pre_polygon = polygon.detach().clone()
|
126 |
+
|
127 |
+
# find the nearest edge in mask of the featureline
|
128 |
+
dist = knn_points(polygon[None], reply_pts[None])
|
129 |
+
idx = dist.idx[0, ...,0]
|
130 |
+
group_id = group[idx]
|
131 |
+
|
132 |
+
if dist.dists.max()>1000:
|
133 |
+
new_polygons.append(polygon.detach().cpu().numpy())
|
134 |
+
continue
|
135 |
+
|
136 |
+
|
137 |
+
# pick the id which is in a larger mask area => pick which the mask area
|
138 |
+
prefer_id = group_id[0] if mask_area[group_id[0]] > mask_area[group_id[1]] else group_id[1]
|
139 |
+
prefer_pts = torch.from_numpy(mask_polygons[prefer_id]).float().cuda()
|
140 |
+
# find the nearest edge in mask of the featureline two points
|
141 |
+
dist = knn_points(polygon[None], prefer_pts[None])
|
142 |
+
idx = dist.idx[0, ...,0].sort()
|
143 |
+
polygon= polygon[idx.indices]
|
144 |
+
idx=idx.values
|
145 |
+
|
146 |
+
reverse_flag = (not idx[0] == dist.idx[0, 0, 0])
|
147 |
+
|
148 |
+
|
149 |
+
# obtain slice_curve
|
150 |
+
|
151 |
+
dp = length_dp[prefer_id]
|
152 |
+
# compute the length of the two points in mask edge
|
153 |
+
# find the shortest path
|
154 |
+
slice_a = dp[idx[1]] - dp[idx[0]]
|
155 |
+
slice_b = dp[-1] - slice_a
|
156 |
+
|
157 |
+
#obtain slice_b
|
158 |
+
if slice_a>slice_b:
|
159 |
+
# 找最短的路径,当前这个edge的后一个点
|
160 |
+
segment = torch.cat([polygon[1:],prefer_pts[idx[1]:], prefer_pts[:idx[0]+1], polygon[0:1]], dim = 0)
|
161 |
+
reverse_flag = (not reverse_flag)
|
162 |
+
|
163 |
+
else:
|
164 |
+
segment = torch.cat([polygon[0:1], prefer_pts[idx[0]:idx[1]+1], polygon[1:]], dim=0)
|
165 |
+
|
166 |
+
segment = segment.detach().cpu().numpy()
|
167 |
+
if reverse_flag:
|
168 |
+
segment = segment[::-1]
|
169 |
+
|
170 |
+
new_polygons.append(segment)
|
171 |
+
|
172 |
+
|
173 |
+
new_polygons = np.concatenate(new_polygons, axis = 0)
|
174 |
+
new_query_sets[key] = new_polygons
|
175 |
+
#pdb.set_trace()
|
176 |
+
return new_query_sets, mask
|
177 |
+
|
178 |
+
def smooth_noise(self, mask):
|
179 |
+
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5, 5))
|
180 |
+
mask = cv2.erode(mask, kernel, iterations=2)
|
181 |
+
mask = cv2.dilate(mask, kernel, iterations=2)
|
182 |
+
|
183 |
+
return mask
|
184 |
+
|
185 |
+
def mask2polygon(self, mask):
|
186 |
+
contours, hierarchy = cv2.findContours((mask).astype(np.uint8), cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
|
187 |
+
# mask_new, contours, hierarchy = cv2.findContours((mask).astype(np.uint8), cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
|
188 |
+
segmentation = []
|
189 |
+
polygon_size = []
|
190 |
+
for contour in contours:
|
191 |
+
contour_list = contour.flatten().tolist()
|
192 |
+
if len(contour_list) > 4:# and cv2.contourArea(contour)>10000
|
193 |
+
|
194 |
+
area = self.polygons_to_mask(mask.shape, contour_list).sum()
|
195 |
+
polygon_size.append(area)
|
196 |
+
|
197 |
+
contour_numpy = np.asarray(contour_list).reshape(-1, 2)
|
198 |
+
segmentation.append(contour_numpy)
|
199 |
+
|
200 |
+
|
201 |
+
return segmentation, polygon_size
|
202 |
+
|
203 |
+
def polygons_to_mask(self, img_shape, polygons):
|
204 |
+
mask = np.zeros(img_shape, dtype=np.uint8)
|
205 |
+
|
206 |
+
polygons = np.asarray(polygons, np.int32) # 这里必须是int32,其他类型使用fillPoly会报错
|
207 |
+
shape=polygons.shape
|
208 |
+
|
209 |
+
polygons=polygons.reshape(-1,2)
|
210 |
+
cv2.fillPoly(mask, [polygons],color=1) # 非int32 会报错
|
211 |
+
return mask
|
212 |
+
|
213 |
+
|
214 |
+
|
215 |
+
def get_upper_bttom_type(parsing_type, key):
|
216 |
+
|
217 |
+
# 'ATR': ['Background', 'Hat', 'Hair', 'Sunglasses', 'Upper-clothes', 'Skirt', 'Pants', 'Dress', 'Belt',
|
218 |
+
# 'Left-shoe', 'Right-shoe', 'Face', 'Left-leg', 'Right-leg', 'Left-arm', 'Right-arm', 'Bag', 'Scarf'],
|
219 |
+
ATR_PARSING = {
|
220 |
+
'upper':[4, 16, 17], # 4: upper-clothes, 16: Bag, 17: Scarf
|
221 |
+
#'upper':[4], # 4: upper-clothes, 16: Bag, 17: Scarf
|
222 |
+
#without head
|
223 |
+
# 'upper':[1, 2, 3, 4, 11, 16, 17],
|
224 |
+
'bottom':[5, 6, 8],
|
225 |
+
#'bottom':[5, 6 ], # 5: skirt, 6: pants, 8: belt
|
226 |
+
# with head and hand
|
227 |
+
#'upper_bottom':[4, 5, 6, 7 ]
|
228 |
+
'upper_bottom':[4, 5, 6, 7, 8, 16, 17]
|
229 |
+
}
|
230 |
+
CLO_PARSING = {
|
231 |
+
# with head and hand
|
232 |
+
'upper':[1,2,3],
|
233 |
+
#without head
|
234 |
+
# 'upper':[1, 2, 3, 4, 11, 16, 17],
|
235 |
+
'bottom':[1,2,3],
|
236 |
+
# with head and hand
|
237 |
+
'upper_bottom':[1,2,3]
|
238 |
+
# w/o hand
|
239 |
+
# 'upper_bottom':[4, 5, 7, 16, 17]
|
240 |
+
}
|
241 |
+
|
242 |
+
if parsing_type =='ATR':
|
243 |
+
return ATR_PARSING[key]
|
244 |
+
else:
|
245 |
+
return CLO_PARSING[key]
|
246 |
+
|
247 |
+
|
248 |
+
def get_parsing_label(parsing_type):
|
249 |
+
parsing_table ={
|
250 |
+
'ATR': ['Background', 'Hat', 'Hair', 'Sunglasses', 'Upper-clothes', 'Skirt', 'Pants', 'Dress', 'Belt',
|
251 |
+
'Left-shoe', 'Right-shoe', 'Face', 'Left-leg', 'Right-leg', 'Left-arm', 'Right-arm', 'Bag', 'Scarf'],
|
252 |
+
'CLO':['background', 'upper', 'bottom', 'upper-bottom']
|
253 |
+
}
|
254 |
+
|
255 |
+
return parsing_table[parsing_type]
|
256 |
+
|
257 |
+
def get_parse():
|
258 |
+
parser = argparse.ArgumentParser(description='')
|
259 |
+
parser.add_argument('--parsing_type', default='ATR', help='garment_parsing type', choices=['ATR', 'CLO'])
|
260 |
+
parser.add_argument('--input_path', default='', help='select model')
|
261 |
+
parser.add_argument('--output_path', default='', help='polygons output')
|
262 |
+
|
263 |
+
args = parser.parse_args()
|
264 |
+
return args
|
265 |
+
|
266 |
+
def parsing_curve(query_file, parsing_file, parsing_type, class_type, debug_path, name):
|
267 |
+
|
268 |
+
query_sets = {}
|
269 |
+
with open(query_file) as reader:
|
270 |
+
fl_infos = json.load(reader)
|
271 |
+
shapes = fl_infos['shapes']
|
272 |
+
for fl in shapes:
|
273 |
+
query_sets[fl['label']] = np.asarray(fl['points']).astype(np.float32)
|
274 |
+
|
275 |
+
class_table = dict(
|
276 |
+
female_outfit3=['upper_bottom'],
|
277 |
+
female_outfit1=['upper_bottom'],
|
278 |
+
anran_run = ['short_sleeve_upper', 'skirt'],
|
279 |
+
anran_tic = ['short_sleeve_upper', 'skirt'],
|
280 |
+
leyang_jump = ['dress'],
|
281 |
+
leyang_steps = ['dress'],
|
282 |
+
)
|
283 |
+
|
284 |
+
garment_table = dict(
|
285 |
+
short_sleeve_upper='upper',
|
286 |
+
skirt='bottom',
|
287 |
+
dress='upper_bottom',
|
288 |
+
long_sleeve_upper='upper',
|
289 |
+
long_pants='bottom',
|
290 |
+
short_pants='bottom',
|
291 |
+
)
|
292 |
+
|
293 |
+
masks = np.load(parsing_file, allow_pickle= True) # [H, W]
|
294 |
+
parsing_name = parsing_file.split('/')[-1]
|
295 |
+
|
296 |
+
poly_mask = PolyMask(masks)
|
297 |
+
new_query_sets = {}
|
298 |
+
|
299 |
+
for garment_key in TEMPLATE_GARMENT[class_type]:
|
300 |
+
pdb.set_trace()
|
301 |
+
garment_class = get_upper_bttom_type(parsing_type, garment_table[garment_key])
|
302 |
+
fl_names = 'bottom_curve' #FL_EXTRACT[garment_key]
|
303 |
+
fl_query_sets = {}
|
304 |
+
|
305 |
+
for fl_name in fl_names:
|
306 |
+
if fl_name in query_sets.keys():
|
307 |
+
fl_query_sets[fl_name] = query_sets[fl_name]
|
308 |
+
|
309 |
+
#pdb.set_trace()
|
310 |
+
new_fl_query_sets, mask = poly_mask.query(fl_query_sets, garment_class, garment_key)
|
311 |
+
new_query_sets.update(new_fl_query_sets)
|
312 |
+
|
313 |
+
cv2.imwrite(osp.join(debug_path, 'mask_{}_'.format(garment_key)+name), mask)
|
314 |
+
|
315 |
+
return new_query_sets, mask
|
316 |
+
|
317 |
+
|
318 |
+
def main(args):
|
319 |
+
# ATR, CLO
|
320 |
+
parsing_type = args.parsing_type
|
321 |
+
parsing_label = get_parsing_label(parsing_type)
|
322 |
+
parsing_dir = osp.join(args.input_path, 'parsing_SCH_{}'.format(parsing_type))
|
323 |
+
img_dir = osp.join(args.input_path, 'imgs/')
|
324 |
+
#json_files = sorted(glob.glob(osp.join(args.input_path, 'featurelines/*.json')))
|
325 |
+
json_files = sorted(glob.glob(osp.join(args.input_path, 'json_hand_label_no_bottom_curve/*.json')))
|
326 |
+
img_files = sorted(glob.glob(osp.join(img_dir, '*.jpg')))
|
327 |
+
img_files += sorted(glob.glob(osp.join(img_dir, '*.png')))
|
328 |
+
# get the id: 000342
|
329 |
+
json_key = [json_file.split('/')[-1][:-5] for json_file in json_files]
|
330 |
+
|
331 |
+
parsing_files = sorted(glob.glob(osp.join(parsing_dir,'*.npy')))
|
332 |
+
# given the small json files (less than no.imgs), find the corresponding parsing files and img files
|
333 |
+
filter_parsing_files = list(filter(lambda x: x.split('/')[-1].split('_')[-1][:-4] in json_key, parsing_files))
|
334 |
+
filter_img_files = list(filter(lambda x: x.split('/')[-1][:-4] in json_key, img_files))
|
335 |
+
|
336 |
+
if args.input_path[-1] =='/':
|
337 |
+
input_path = args.input_path[:-1]
|
338 |
+
else:
|
339 |
+
input_path = args.input_path
|
340 |
+
|
341 |
+
class_type = input_path.split('/')[-1]
|
342 |
+
debug_path = osp.join('./debug/{}/polymask'.format(class_type))
|
343 |
+
output_path = args.output_path
|
344 |
+
os.makedirs(output_path, exist_ok = True)
|
345 |
+
os.makedirs(debug_path, exist_ok= True)
|
346 |
+
|
347 |
+
for idx, (parsing_file, json_file, filter_img_file) in enumerate(zip(filter_parsing_files, json_files, filter_img_files)):
|
348 |
+
pdb.set_trace()
|
349 |
+
print('processing: {}'.format(filter_img_file))
|
350 |
+
img = cv2.imread(filter_img_file)
|
351 |
+
name = filter_img_file.split('/')[-1]
|
352 |
+
# if idx == 5:
|
353 |
+
# pdb.set_trace()
|
354 |
+
|
355 |
+
new_query_sets, mask = parsing_curve(json_file, parsing_file, args.parsing_type, class_type, debug_path, name)
|
356 |
+
|
357 |
+
with open(json_file) as reader:
|
358 |
+
fl_infos = json.load(reader)
|
359 |
+
shapes = fl_infos['shapes']
|
360 |
+
for fl in shapes:
|
361 |
+
# query_sets[fl['label']] = np.asarray(fl['points']).astype(np.float32)
|
362 |
+
fl['points']= new_query_sets[fl['label']].tolist()
|
363 |
+
|
364 |
+
|
365 |
+
json_name = json_file.split('/')[-1]
|
366 |
+
new_json_file = os.path.join(output_path, json_name)
|
367 |
+
with open(new_json_file, 'w') as writer:
|
368 |
+
json.dump(fl_infos, writer)
|
369 |
+
|
370 |
+
|
371 |
+
for key in new_query_sets.keys():
|
372 |
+
color = FL_COLOR[key]
|
373 |
+
pt_list = new_query_sets[key].astype(np.int)
|
374 |
+
for pt in new_query_sets[key].astype(np.int):
|
375 |
+
img = cv2.circle(img, (pt[0], pt[1]),2, color,2)
|
376 |
+
|
377 |
+
for pt_idx in range(pt_list.shape[0]-1):
|
378 |
+
img = cv2.line(img, (pt_list[pt_idx][0],pt_list[pt_idx][1]), (pt_list[pt_idx+1][0],pt_list[pt_idx+1][1]), color, 2)
|
379 |
+
|
380 |
+
|
381 |
+
cv2.imwrite(osp.join(debug_path, name), img)
|
382 |
+
|
383 |
+
if __name__ == '__main__':
|
384 |
+
|
385 |
+
args = get_parse()
|
386 |
+
main(args)
|
387 |
+
|
388 |
+
|
process_data_all.py
ADDED
@@ -0,0 +1,149 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'''
|
2 |
+
@Author: Jiapeng Zhou
|
3 |
+
@Email: jiapengzhou@link.cuhk.edu.cn
|
4 |
+
@Desc: script to process all data of RECMV.
|
5 |
+
Before run this bash, what you only need to do is :
|
6 |
+
- run openpose to get keypoints.json file in the dir: (self.root, openpose)
|
7 |
+
- have a conda environment of videoavatar, named: "videoavatar"
|
8 |
+
Usage: python process_data_all.py --root ~/DeepDxxx/xinyu_a/ --gid 0 --gender female
|
9 |
+
'''
|
10 |
+
|
11 |
+
import pdb, os, os.path as osp, sys, argparse
|
12 |
+
from typing import Any
|
13 |
+
import numpy as np, cv2
|
14 |
+
|
15 |
+
class RECMVDataProcessor():
|
16 |
+
def __init__(self, args) -> None:
|
17 |
+
self.args = args
|
18 |
+
self.gender = args.gender
|
19 |
+
|
20 |
+
self.root = args.root
|
21 |
+
#out = osp.join(self.root, args.out)
|
22 |
+
#os.makedirs(out, exist_ok=True)
|
23 |
+
self.img_dir = osp.join(self.root, 'imgs')
|
24 |
+
assert osp.exists(self.img_dir) and len(os.listdir(self.img_dir)) > 0, 'img file does not exist'
|
25 |
+
self.gid = args.gid
|
26 |
+
|
27 |
+
def __len__(self):
|
28 |
+
return len(os.listdir(self.img_dir))
|
29 |
+
|
30 |
+
def __call__(self):
|
31 |
+
'''get normals, ATR-parsing, masks, camera, smpl_params, depth, featurelines'''
|
32 |
+
|
33 |
+
# get ATR_parsing
|
34 |
+
self.get_ATR_parsing()
|
35 |
+
|
36 |
+
# get masks
|
37 |
+
self.get_masks()
|
38 |
+
|
39 |
+
# get normal from pifuhd
|
40 |
+
self.get_normals()
|
41 |
+
|
42 |
+
'''cannot directly ca videoavatar
|
43 |
+
# get reconstructed_poses.hdf5 from videoavatar
|
44 |
+
self.get_poses()
|
45 |
+
|
46 |
+
# get camera.npz and smpl_rec.npz
|
47 |
+
self.get_camera_smpl_rec()
|
48 |
+
|
49 |
+
'''
|
50 |
+
|
51 |
+
# get depth
|
52 |
+
#self.get_depth()
|
53 |
+
|
54 |
+
# get featurelines
|
55 |
+
#self.get_featurelines()
|
56 |
+
|
57 |
+
def get_featurelines(self):
|
58 |
+
fl_dir = osp.join(self.root, 'featurelines')
|
59 |
+
if osp.exists(fl_dir) and len(os.listdir(fl_dir)) >= self.__len__():
|
60 |
+
print('featurelines files exists')
|
61 |
+
else:
|
62 |
+
print('featurelines file does not exist')
|
63 |
+
|
64 |
+
def get_depth(self):
|
65 |
+
depth_dir = osp.join(self.root, 'depth')
|
66 |
+
if osp.exists(depth_dir) and len(os.listdir(depth_dir)) >= self.__len__():
|
67 |
+
print('depth files exists')
|
68 |
+
else:
|
69 |
+
print('depth file does not exist')
|
70 |
+
|
71 |
+
def get_masks(self):
|
72 |
+
mask_dir = osp.join(self.root, 'masks')
|
73 |
+
if osp.exists(mask_dir) and len(os.listdir(mask_dir)) >= self.__len__():
|
74 |
+
print('mask files exists')
|
75 |
+
return
|
76 |
+
os.makedirs(mask_dir, exist_ok=True)
|
77 |
+
# mask是否需要按照单通道保存?
|
78 |
+
print('\n-----------------Getting Masks-------------------------')
|
79 |
+
os.system(f'cd ./RobustVideoMatting && python inference_itw_rotate.py \
|
80 |
+
--input_pth {self.img_dir} --output_pth {mask_dir} --device {self.gid}')
|
81 |
+
|
82 |
+
|
83 |
+
def get_normals(self):
|
84 |
+
normal_dir = osp.join(self.root, 'normals')
|
85 |
+
if osp.exists(normal_dir) and len(os.listdir(normal_dir)) >= self.__len__():
|
86 |
+
print('normal files exists')
|
87 |
+
return
|
88 |
+
|
89 |
+
print('\n-------------------Getting Normals----------------------')
|
90 |
+
os.makedirs(normal_dir, exist_ok=True)
|
91 |
+
os.system('cd ./pifuhd && python ./generate_normals.py --gid {} --imgpath {}'.format(self.gid, self.img_dir))
|
92 |
+
|
93 |
+
def get_ATR_parsing(self):
|
94 |
+
input_dir = osp.join(self.root, 'imgs')
|
95 |
+
output_dir = osp.join(self.root, 'parsing_SCH_ATR')
|
96 |
+
if osp.exists(output_dir) and len(os.listdir(output_dir)) >= self.__len__():
|
97 |
+
print('ATR parsing files exists')
|
98 |
+
return
|
99 |
+
print('\n--------------------Getting ATR_Parsing------------------')
|
100 |
+
os.makedirs(output_dir, exist_ok=True)
|
101 |
+
|
102 |
+
os.system(f'cd ./Self-Correction-Human-Parsing && python simple_extractor.py \
|
103 |
+
--dataset atr --model-restore exp-schp-201908301523-atr.pth --gpu {self.gid} \
|
104 |
+
--input-dir {self.img_dir} --output-dir {output_dir} --logits')
|
105 |
+
|
106 |
+
|
107 |
+
def get_poses(self):
|
108 |
+
openpose_p = osp.join(self.root, 'openpose')
|
109 |
+
assert osp.exists(openpose_p) and len(os.listdir(openpose_p)) >= self.__len__(), 'openpose keypoint folder doesnot exist or it is emtpy'
|
110 |
+
|
111 |
+
output_dir = osp.join(self.root, 'videoavatars')
|
112 |
+
if osp.exists(output_dir) and osp.exists(osp.join(output_dir, 'reconstructed_poses.hdf5')):
|
113 |
+
print('reconstructed_poses.hdf5 files exists')
|
114 |
+
return
|
115 |
+
|
116 |
+
print('\n------------------Getting Poses---------------------------')
|
117 |
+
os.makedirs(output_dir, exist_ok=True)
|
118 |
+
# Note: Here needs to conda actiavte the environment of videoavatar
|
119 |
+
os.system(f'cd ./videoavatars && bash get_reconstructed_poses.sh {self.root} {output_dir} {self.gender}')
|
120 |
+
|
121 |
+
|
122 |
+
def get_camera_smpl_rec(self):
|
123 |
+
if osp.exists(osp.join(self.root, 'camera.npz')) and osp.exists(osp.join(self.root, 'smpl_rec.npz')):
|
124 |
+
print('camera.npz and smpl_rec.npz files exists')
|
125 |
+
return
|
126 |
+
|
127 |
+
print('\n---------------------Getting camera and smpl_rec--------------------')
|
128 |
+
os.system(' python get_smpl_rec_camera.py --root {} --save_root {} --gender {}'.\
|
129 |
+
format(osp.join(self.root, 'videoavatars'), self.root, self.gender))
|
130 |
+
|
131 |
+
|
132 |
+
|
133 |
+
|
134 |
+
def parse_args():
|
135 |
+
parser = argparse.ArgumentParser()
|
136 |
+
parser.add_argument('--gid', type=int, default=0)
|
137 |
+
parser.add_argument('--root', type=str, required=True)
|
138 |
+
parser.add_argument('--gender', type=str, choices=['male', 'female'], required=True)
|
139 |
+
args = parser.parse_args()
|
140 |
+
return args
|
141 |
+
|
142 |
+
def main():
|
143 |
+
args = parse_args()
|
144 |
+
processor = RECMVDataProcessor(args)
|
145 |
+
processor()
|
146 |
+
|
147 |
+
if __name__ == '__main__':
|
148 |
+
main()
|
149 |
+
|
rename.py
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os, os.path as osp, sys, shutil, argparse, re, glob, time, argparse, pdb
|
2 |
+
|
3 |
+
def rename(dir):
|
4 |
+
for root, dirs, files in os.walk(dir):
|
5 |
+
pdb.set_trace()
|
6 |
+
for file in files:
|
7 |
+
if file.endswith('.npy'):
|
8 |
+
new_name = file.split('_')[-1]
|
9 |
+
new_name = osp.join(root, new_name)
|
10 |
+
|
11 |
+
old_name = os.path.join(root, file)
|
12 |
+
os.rename(old_name, new_name)
|
13 |
+
print('Renamed {} to {}'.format(old_name, new_name))
|
14 |
+
|
15 |
+
|
16 |
+
if __name__ == '__main__':
|
17 |
+
dir = '/home/zjp/DeepDynamicFashion/REC-MV/data/yanzhi_a/parsing'
|
18 |
+
rename(dir)
|
requirements.txt
ADDED
@@ -0,0 +1,266 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
absl-py==1.4.0
|
2 |
+
addict==2.4.0
|
3 |
+
aiohttp==3.8.1
|
4 |
+
aioice==0.7.6
|
5 |
+
aiortc==1.3.2
|
6 |
+
aiosignal==1.3.1
|
7 |
+
alabaster==0.7.13
|
8 |
+
anyio==3.6.2
|
9 |
+
appdirs==1.4.4
|
10 |
+
argon2-cffi==21.3.0
|
11 |
+
argon2-cffi-bindings==21.2.0
|
12 |
+
asttokens==2.2.1
|
13 |
+
async-timeout==4.0.2
|
14 |
+
attrs==22.2.0
|
15 |
+
aux==0.0.2
|
16 |
+
av==8.0.3
|
17 |
+
Babel==2.11.0
|
18 |
+
backcall==0.2.0
|
19 |
+
bcrypt==4.0.1
|
20 |
+
beautifulsoup4==4.11.2
|
21 |
+
bidict==0.22.1
|
22 |
+
bleach==6.0.0
|
23 |
+
blessed==1.20.0
|
24 |
+
cachetools==5.3.0
|
25 |
+
certifi==2022.12.7
|
26 |
+
cffi==1.15.1
|
27 |
+
chardet==4.0.0
|
28 |
+
charset-normalizer==2.0.12
|
29 |
+
chumpy==0.70
|
30 |
+
click==8.1.3
|
31 |
+
colorama==0.4.6
|
32 |
+
comm==0.1.2
|
33 |
+
commonmark==0.9.1
|
34 |
+
ConfigArgParse==1.5.3
|
35 |
+
cppcuda-tutorial @ file:///home/zjp/Learning/pytorch_cppcuda_tutorial
|
36 |
+
cryptography==39.0.0
|
37 |
+
cycler==0.11.0
|
38 |
+
d2l==0.17.6
|
39 |
+
dash==2.8.1
|
40 |
+
dash-core-components==2.0.0
|
41 |
+
dash-html-components==2.0.0
|
42 |
+
dash-table==5.0.0
|
43 |
+
datasets==2.12.0
|
44 |
+
debugpy==1.6.6
|
45 |
+
decorator==5.1.1
|
46 |
+
defusedxml==0.7.1
|
47 |
+
descartes==1.1.0
|
48 |
+
dill==0.3.6
|
49 |
+
dnspython==2.3.0
|
50 |
+
docker-pycreds==0.4.0
|
51 |
+
docstring-parser==0.14.1
|
52 |
+
docutils==0.19
|
53 |
+
einops==0.6.0
|
54 |
+
exceptiongroup==1.1.1
|
55 |
+
executing==1.2.0
|
56 |
+
fabric==3.0.0
|
57 |
+
fastjsonschema==2.16.2
|
58 |
+
FastMinv==0.0.0
|
59 |
+
filelock==3.9.0
|
60 |
+
filterpy==1.4.5
|
61 |
+
fire==0.5.0
|
62 |
+
Flask==2.2.2
|
63 |
+
fonttools==4.38.0
|
64 |
+
freetype-py==2.3.0
|
65 |
+
frozendict==2.3.4
|
66 |
+
frozenlist==1.3.3
|
67 |
+
fsspec==2023.5.0
|
68 |
+
fvcore==0.1.5.post20221221
|
69 |
+
gdown==4.5.1
|
70 |
+
gitdb==4.0.10
|
71 |
+
GitPython==3.1.30
|
72 |
+
google-auth==2.16.0
|
73 |
+
google-auth-oauthlib==1.0.0
|
74 |
+
google-crc32c==1.5.0
|
75 |
+
gpustat==1.0.0
|
76 |
+
grpcio==1.51.1
|
77 |
+
h5py==3.8.0
|
78 |
+
happytransformer==2.4.1
|
79 |
+
huggingface-hub==0.14.1
|
80 |
+
idna==2.10
|
81 |
+
imageio==2.21.1
|
82 |
+
imagesize==1.4.1
|
83 |
+
importlib-metadata==6.0.0
|
84 |
+
importlib-resources==5.10.2
|
85 |
+
iniconfig==2.0.0
|
86 |
+
interplate==0.0.0
|
87 |
+
invoke==2.0.0
|
88 |
+
iopath==0.1.10
|
89 |
+
ipykernel==6.21.1
|
90 |
+
ipython==8.9.0
|
91 |
+
ipython-genutils==0.2.0
|
92 |
+
ipywidgets==8.0.4
|
93 |
+
itsdangerous==2.1.2
|
94 |
+
jedi==0.18.2
|
95 |
+
Jinja2==3.1.2
|
96 |
+
joblib==1.2.0
|
97 |
+
json5==0.9.11
|
98 |
+
jsonschema==4.17.3
|
99 |
+
jupyter==1.0.0
|
100 |
+
jupyter-console==6.4.4
|
101 |
+
jupyter-server==1.23.5
|
102 |
+
jupyter_client==8.0.2
|
103 |
+
jupyter_core==5.2.0
|
104 |
+
jupyterlab==3.3.4
|
105 |
+
jupyterlab-pygments==0.2.2
|
106 |
+
jupyterlab-widgets==3.0.5
|
107 |
+
kiwisolver==1.4.4
|
108 |
+
linecache2==1.0.0
|
109 |
+
lpips==0.1.4
|
110 |
+
lxml==4.9.2
|
111 |
+
Markdown==3.4.1
|
112 |
+
MarkupSafe==2.1.2
|
113 |
+
matplotlib==3.5.1
|
114 |
+
matplotlib-inline==0.1.6
|
115 |
+
MCGpu==0.0.0
|
116 |
+
mediapy==1.1.0
|
117 |
+
mistune==2.0.4
|
118 |
+
msgpack==1.0.4
|
119 |
+
msgpack-numpy==0.4.8
|
120 |
+
multidict==6.0.4
|
121 |
+
multiprocess==0.70.14
|
122 |
+
nbclassic==0.5.1
|
123 |
+
nbclient==0.7.2
|
124 |
+
nbconvert==7.2.9
|
125 |
+
nbformat==5.5.0
|
126 |
+
nerfacc==0.3.4
|
127 |
+
nest-asyncio==1.5.6
|
128 |
+
netifaces==0.11.0
|
129 |
+
networkx==3.0
|
130 |
+
ninja==1.11.1
|
131 |
+
nose==1.3.7
|
132 |
+
notebook==6.5.2
|
133 |
+
notebook_shim==0.2.2
|
134 |
+
numpy==1.21.5
|
135 |
+
nuscenes-devkit==1.1.9
|
136 |
+
nvidia-ml-py==11.495.46
|
137 |
+
oauthlib==3.2.2
|
138 |
+
open3d==0.16.0
|
139 |
+
opencv-python==4.6.0.66
|
140 |
+
openmesh==1.2.1
|
141 |
+
packaging==23.0
|
142 |
+
pandas==1.2.4
|
143 |
+
pandocfilters==1.5.0
|
144 |
+
paramiko==3.1.0
|
145 |
+
parso==0.8.3
|
146 |
+
pathtools==0.1.2
|
147 |
+
pexpect==4.8.0
|
148 |
+
pickleshare==0.7.5
|
149 |
+
Pillow==9.4.0
|
150 |
+
PIMS==0.5
|
151 |
+
pkgutil_resolve_name==1.3.10
|
152 |
+
platformdirs==2.6.2
|
153 |
+
plotly==5.7.0
|
154 |
+
pluggy==1.0.0
|
155 |
+
portalocker==2.7.0
|
156 |
+
POT==0.9.0
|
157 |
+
prometheus-client==0.16.0
|
158 |
+
prompt-toolkit==3.0.36
|
159 |
+
protobuf==3.20.0
|
160 |
+
psutil==5.9.4
|
161 |
+
ptyprocess==0.7.0
|
162 |
+
pure-eval==0.2.2
|
163 |
+
pyarrow==12.0.0
|
164 |
+
pyasn1==0.4.8
|
165 |
+
pyasn1-modules==0.2.8
|
166 |
+
pycocotools==2.0.6
|
167 |
+
pycparser==2.21
|
168 |
+
pyee==9.0.4
|
169 |
+
pyglet==2.0.5
|
170 |
+
Pygments==2.14.0
|
171 |
+
pyhocon==0.3.60
|
172 |
+
pylibsrtp==0.8.0
|
173 |
+
pymeshlab==2022.2.post2
|
174 |
+
PyNaCl==1.5.0
|
175 |
+
pyngrok==5.1.0
|
176 |
+
PyOpenGL==3.1.0
|
177 |
+
pyparsing==3.0.9
|
178 |
+
pyquaternion==0.9.9
|
179 |
+
pyrender==0.1.45
|
180 |
+
pyrsistent==0.19.3
|
181 |
+
PySocks==1.7.1
|
182 |
+
pytest==7.3.1
|
183 |
+
python-dateutil==2.8.2
|
184 |
+
python-engineio==4.3.4
|
185 |
+
python-socketio==5.7.1
|
186 |
+
pytorch3d==0.4.0
|
187 |
+
pytz==2022.7.1
|
188 |
+
PyWavelets==1.4.1
|
189 |
+
PyYAML==6.0
|
190 |
+
pyzmq==25.0.0
|
191 |
+
qtconsole==5.4.0
|
192 |
+
QtPy==2.3.0
|
193 |
+
regex==2023.5.5
|
194 |
+
requests==2.25.1
|
195 |
+
requests-oauthlib==1.3.1
|
196 |
+
responses==0.18.0
|
197 |
+
rich==12.5.1
|
198 |
+
rsa==4.9
|
199 |
+
scikit-image==0.19.3
|
200 |
+
scikit-learn==1.2.1
|
201 |
+
scikit-sparse==0.4.8
|
202 |
+
scipy==1.10.0
|
203 |
+
seaborn==0.12.2
|
204 |
+
Send2Trash==1.8.0
|
205 |
+
sentencepiece==0.1.99
|
206 |
+
sentry-sdk==1.14.0
|
207 |
+
setproctitle==1.3.2
|
208 |
+
shapely==2.0.1
|
209 |
+
shtab==1.5.8
|
210 |
+
six==1.16.0
|
211 |
+
slicerator==1.1.0
|
212 |
+
smmap==5.0.0
|
213 |
+
smplx==0.1.28
|
214 |
+
sniffio==1.3.0
|
215 |
+
snowballstemmer==2.2.0
|
216 |
+
soupsieve==2.3.2.post1
|
217 |
+
Sphinx==6.1.3
|
218 |
+
sphinxcontrib-applehelp==1.0.4
|
219 |
+
sphinxcontrib-devhelp==1.0.2
|
220 |
+
sphinxcontrib-htmlhelp==2.0.1
|
221 |
+
sphinxcontrib-jsmath==1.0.1
|
222 |
+
sphinxcontrib-qthelp==1.0.3
|
223 |
+
sphinxcontrib-serializinghtml==1.1.5
|
224 |
+
stack-data==0.6.2
|
225 |
+
tabulate==0.9.0
|
226 |
+
tenacity==8.1.0
|
227 |
+
tensorboard==2.12.1
|
228 |
+
tensorboard-data-server==0.7.0
|
229 |
+
tensorboard-plugin-wit==1.8.1
|
230 |
+
termcolor==2.2.0
|
231 |
+
terminado==0.17.1
|
232 |
+
threadpoolctl==3.1.0
|
233 |
+
tifffile==2023.2.3
|
234 |
+
tinycss2==1.2.1
|
235 |
+
tinycudann==1.7
|
236 |
+
tokenizers==0.13.3
|
237 |
+
tomli==2.0.1
|
238 |
+
torch==1.10.2+cu113
|
239 |
+
torch-fidelity==0.3.0
|
240 |
+
torch-scatter==2.0.9
|
241 |
+
torchmetrics==0.11.1
|
242 |
+
torchtyping==0.1.4
|
243 |
+
torchvision==0.11.3+cu113
|
244 |
+
tornado==6.2
|
245 |
+
tqdm==4.65.0
|
246 |
+
traceback2==1.4.0
|
247 |
+
traitlets==5.9.0
|
248 |
+
transformers==4.28.1
|
249 |
+
trimesh==3.18.3
|
250 |
+
typeguard==2.13.3
|
251 |
+
typing_extensions==4.4.0
|
252 |
+
tyro==0.3.38
|
253 |
+
u-msgpack-python==2.7.2
|
254 |
+
unittest2==1.1.0
|
255 |
+
urllib3==1.26.14
|
256 |
+
wandb==0.13.9
|
257 |
+
wcwidth==0.2.6
|
258 |
+
webencodings==0.5.1
|
259 |
+
websocket-client==1.5.1
|
260 |
+
Werkzeug==2.2.2
|
261 |
+
widgetsnbextension==4.0.5
|
262 |
+
xatlas==0.0.7
|
263 |
+
xxhash==3.2.0
|
264 |
+
yacs==0.1.8
|
265 |
+
yarl==1.8.2
|
266 |
+
zipp==3.12.1
|
smpl_process.py
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'''
|
2 |
+
@Desc: This file is used to process the smpl: convert rotation matrix to axis-angle
|
3 |
+
'''
|
4 |
+
|
5 |
+
import numpy as np
|
6 |
+
import os, os.path as osp, sys, pdb, argparse
|
7 |
+
from scipy.spatial.transform import Rotation
|
8 |
+
|
9 |
+
def convert_rotmat_to_axis_angle(rotmat):
|
10 |
+
'''
|
11 |
+
Args: rotmat: (N, 3, 3)
|
12 |
+
Return: axis_angle: (N, 3)
|
13 |
+
'''
|
14 |
+
rotation = Rotation.from_matrix(rotmat)
|
15 |
+
axis_angle = rotation.as_rotvec()
|
16 |
+
return axis_angle
|
17 |
+
|
18 |
+
def parse_args():
|
19 |
+
argparser = argparse.ArgumentParser()
|
20 |
+
argparser.add_argument('--root', help='the root dir of an identity')
|
21 |
+
argparser.add_argument('--smpl_file')
|
22 |
+
return argparser.parse_args()
|
23 |
+
|
24 |
+
def main():
|
25 |
+
args = parse_args()
|
26 |
+
root = args.root
|
27 |
+
smpl_file = osp.join(root, args.smpl_file)
|
28 |
+
npz = np.load(smpl_file, allow_pickle=True)
|
29 |
+
smpl_params = {}
|
30 |
+
for key in npz.keys():
|
31 |
+
smpl_params[key] = npz[key]
|
32 |
+
|
33 |
+
pdb.set_trace()
|
34 |
+
rotmat_batch = smpl_params['poses'].reshape(-1, 3, 3)
|
35 |
+
smpl_params['poses'] = convert_rotmat_to_axis_angle(rotmat_batch).reshape(-1, 24, 3)
|
36 |
+
np.savez(smpl_file, **smpl_params)
|
37 |
+
return
|
38 |
+
|
39 |
+
if __name__ == '__main__':
|
40 |
+
main()
|