Spaces:
Build error
Build error
| """This script is to load 3D face model for Deep3DFaceRecon_pytorch | |
| """ | |
| import os.path as osp | |
| from array import array | |
| import numpy as np | |
| from PIL import Image | |
| from scipy.io import loadmat | |
| from scipy.io import savemat | |
| # load expression basis | |
| def LoadExpBasis(bfm_folder="BFM"): | |
| n_vertex = 53215 | |
| Expbin = open(osp.join(bfm_folder, "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) | |
| Expbin.close() | |
| expPC = np.array(expPC) | |
| expPC = np.reshape(expPC, [exp_dim[0], -1]) | |
| expPC = np.transpose(expPC) | |
| expEV = np.loadtxt(osp.join(bfm_folder, "std_exp.txt")) | |
| return expPC, expEV | |
| # transfer original BFM09 to our face model | |
| def transferBFM09(bfm_folder="BFM"): | |
| print("Transfer BFM09 to BFM_model_front......") | |
| original_BFM = loadmat(osp.join(bfm_folder, "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 along face landmarks and contains only 35709 vertex. | |
| # original BFM09 contains 53490 vertex, and expression basis provided by Guo et al. contains 53215 vertex. | |
| # thus we select corresponding vertex to get our face model. | |
| index_exp = loadmat(osp.join(bfm_folder, "BFM_front_idx.mat")) | |
| index_exp = index_exp["idx"].astype(np.int32) - 1 # starts from 0 (to 53215) | |
| index_shape = loadmat(osp.join(bfm_folder, "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(osp.join(bfm_folder, "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( | |
| osp.join(bfm_folder, "BFM_model_front.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, | |
| }, | |
| ) | |
| # load landmarks for standard face, which is used for image preprocessing | |
| def load_lm3d(bfm_folder): | |
| Lm3D = loadmat(osp.join(bfm_folder, "similarity_Lm3D_all.mat")) | |
| Lm3D = Lm3D["lm"] | |
| # calculate 5 facial landmarks using 68 landmarks | |
| lm_idx = np.array([31, 37, 40, 43, 46, 49, 55]) - 1 | |
| Lm3D = np.stack( | |
| [ | |
| Lm3D[lm_idx[0], :], | |
| np.mean(Lm3D[lm_idx[[1, 2]], :], 0), | |
| np.mean(Lm3D[lm_idx[[3, 4]], :], 0), | |
| Lm3D[lm_idx[5], :], | |
| Lm3D[lm_idx[6], :], | |
| ], | |
| axis=0, | |
| ) | |
| Lm3D = Lm3D[[1, 2, 0, 3, 4], :] | |
| return Lm3D | |