-
Notifications
You must be signed in to change notification settings - Fork 97
/
Copy pathconvert_bfm09_data.py
102 lines (76 loc) · 3.51 KB
/
convert_bfm09_data.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
from scipy.io import loadmat, savemat
import numpy as np
from array import array
# load expression basis
def LoadExpBasis():
n_vertex = 53215
Expbin = open('BFM/Exp_Pca.bin', 'rb')
exp_dim = array('i')
exp_dim.fromfile(Expbin, 1)
expMU = array('f')
expPC = array('f')
expMU.fromfile(Expbin, 3*n_vertex)
expPC.fromfile(Expbin, 3*exp_dim[0]*n_vertex)
expPC = np.array(expPC)
expPC = np.reshape(expPC, [exp_dim[0], -1])
expPC = np.transpose(expPC)
expEV = np.loadtxt('BFM/std_exp.txt')
return expPC, expEV
# transfer original BFM09 to our face model
def transferBFM09():
original_BFM = loadmat('BFM/01_MorphableModel.mat')
shapePC = original_BFM['shapePC'] # shape basis
shapeEV = original_BFM['shapeEV'] # corresponding eigen value
shapeMU = original_BFM['shapeMU'] # mean face
texPC = original_BFM['texPC'] # texture basis
texEV = original_BFM['texEV'] # eigen value
texMU = original_BFM['texMU'] # mean texture
expPC, expEV = LoadExpBasis()
# transfer BFM09 to our face model
idBase = shapePC*np.reshape(shapeEV, [-1, 199])
idBase = idBase/1e5 # unify the scale to decimeter
idBase = idBase[:, :80] # use only first 80 basis
exBase = expPC*np.reshape(expEV, [-1, 79])
exBase = exBase/1e5 # unify the scale to decimeter
exBase = exBase[:, :64] # use only first 64 basis
texBase = texPC*np.reshape(texEV, [-1, 199])
texBase = texBase[:, :80] # use only first 80 basis
# our face model is cropped align face landmarks which contains only 35709 vertex.
# original BFM09 contains 53490 vertex, and expression basis provided by JuYong contains 53215 vertex.
# thus we select corresponding vertex to get our face model.
index_exp = loadmat('BFM/BFM_front_idx.mat')
index_exp = index_exp['idx'].astype(
np.int32) - 1 # starts from 0 (to 53215)
index_shape = loadmat('BFM/BFM_exp_idx.mat')
index_shape = index_shape['trimIndex'].astype(
np.int32) - 1 # starts from 0 (to 53490)
index_shape = index_shape[index_exp]
idBase = np.reshape(idBase, [-1, 3, 80])
idBase = idBase[index_shape, :, :]
idBase = np.reshape(idBase, [-1, 80])
texBase = np.reshape(texBase, [-1, 3, 80])
texBase = texBase[index_shape, :, :]
texBase = np.reshape(texBase, [-1, 80])
exBase = np.reshape(exBase, [-1, 3, 64])
exBase = exBase[index_exp, :, :]
exBase = np.reshape(exBase, [-1, 64])
meanshape = np.reshape(shapeMU, [-1, 3])/1e5
meanshape = meanshape[index_shape, :]
meanshape = np.reshape(meanshape, [1, -1])
meantex = np.reshape(texMU, [-1, 3])
meantex = meantex[index_shape, :]
meantex = np.reshape(meantex, [1, -1])
# other info contains triangles, region used for computing photometric loss,
# region used for skin texture regularization, and 68 landmarks index etc.
other_info = loadmat('BFM/facemodel_info.mat')
frontmask2_idx = other_info['frontmask2_idx']
skinmask = other_info['skinmask']
keypoints = other_info['keypoints']
point_buf = other_info['point_buf']
tri = other_info['tri']
tri_mask2 = other_info['tri_mask2']
# save our face model
savemat('BFM/BFM09_model_info.mat', {'meanshape': meanshape, 'meantex': meantex, 'idBase': idBase, 'exBase': exBase, 'texBase': texBase,
'tri': tri, 'point_buf': point_buf, 'tri_mask2': tri_mask2, 'keypoints': keypoints, 'frontmask2_idx': frontmask2_idx, 'skinmask': skinmask})
if __name__ == '__main__':
transferBFM09()