xuehongyang
ser
83d8d3c
"""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