Face3D学习笔记(4)3DMM示例源码解析【中上】3DMM模型
寫在前面
-
為了保證整個示例項目更加直觀,方便理解,在展示一些函數(shù)的源碼時會使用numpy版本進行展示,而在示例程序中并未使用numpy版本的庫,在Cython版本與numpy版本出現(xiàn)差異的原碼前會有標注,希望讀者留意。
-
3DMM實例程序的jupyter版本后續(xù)會更新,完全免費,歡迎大家下載
預備
上一篇文章在MATLAB里面對BFM模型執(zhí)行了Face3D提供的程序生成了新的模型數(shù)據(jù)BFM.mat、BFM_info.mat、BFM_UV.mat。這三個文件的格式分別如下:
MATLAB里面的程序到底干了些啥,下面從原理進行一些分析:
首先要知道3DMM的公式為
其中, S ̄\overline{S}S代表平均人臉形狀,SiS_iSi?表示形狀PCA主成分,αi\alpha_iαi?是形狀系數(shù), EiE_iEi?是人臉表情PCA主成分,βi\beta_iβi?是人臉表情系數(shù)。
BFM模型不直接提供原始人臉數(shù)據(jù)或參數(shù)化后的人臉,只提供了形狀和紋理信息
PS:在BMF模型經(jīng)過去中心化后的數(shù)據(jù)所對應式中的m、n均為199。
01_MorphableModel.mat中具體包含數(shù)據(jù)如下
如表所示:
| shapeMU | 平均人臉形狀 | (160470,1) |
| shapePC | 形狀主成分 | (160470,199) |
| shapeEV | 形狀主成分方差 | (199,1) |
| texMU | 平均人臉紋理 | (160470,1) |
| texPC | 紋理主成分 | (160470,199) |
| texEV | 紋理主成分方差 | (199,1) |
| tl | 三角面片 | (106466,3) |
| segbin | 區(qū)域分割信息 | (53490,4) |
在經(jīng)過MATLAB運算輸出的BFM.mat從3DDFA那里獲取了表情數(shù)據(jù),這樣來看face3d里面的3dmm例程:
bfm = MorphabelModel('Data/BFM/Out/BFM.mat') print('init bfm model success')其中MorphabelModel所對應的源碼為
class MorphabelModel(object):"""docstring for MorphabelModelmodel: nver: number of vertices. ntri: number of triangles. *: must have. ~: can generate ones array for place holder.'shapeMU': [3*nver, 1]. *'shapePC': [3*nver, n_shape_para]. *'shapeEV': [n_shape_para, 1]. ~'expMU': [3*nver, 1]. ~ 'expPC': [3*nver, n_exp_para]. ~'expEV': [n_exp_para, 1]. ~'texMU': [3*nver, 1]. ~'texPC': [3*nver, n_tex_para]. ~'texEV': [n_tex_para, 1]. ~'tri': [ntri, 3] (start from 1, should sub 1 in python and c++). *'tri_mouth': [114, 3] (start from 1, as a supplement to mouth triangles). ~'kpt_ind': [68,] (start from 1). ~"""def __init__(self, model_path, model_type = 'BFM'):super( MorphabelModel, self).__init__()if model_type=='BFM':self.model = load.load_BFM(model_path)else:print('sorry, not support other 3DMM model now')exit()# fixed attributesself.nver = self.model['shapePC'].shape[0]/3self.ntri = self.model['tri'].shape[0]self.n_shape_para = self.model['shapePC'].shape[1]self.n_exp_para = self.model['expPC'].shape[1]self.n_tex_para = self.model['texPC'].shape[1]self.kpt_ind = self.model['kpt_ind']self.triangles = self.model ['tri']self.full_triangles = np.vstack((self.model['tri'], self.model['tri_mouth']))就可以理解self.model = load.load_BFM(model_path)所讀取的model里面所包含的元素都是什么了,下面以表格的形式列出來。
| shapeMU | 平均人臉形狀 | (159645,1) |
| shapePC | 形狀主成分 | (159645,199) |
| shapeEV | 形狀主成分方差 | (199,1) |
| expMU | 平均人臉表情 | (159645,1) |
| expPC | 表情主成分 | (159645,29) |
| expEV | 表情主成分方差 | (29,1) |
| texMU | 平均人臉紋理 | (159645,1) |
| texPC | 紋理主成分 | (159645,199) |
| texEV | 紋理主成分方差 | (199,1) |
| tri | 三角格坐標 | (105840,3) |
| tri_mouth | 嘴部三角格坐標 | (114, 3) |
| kpt_ind | 特征點 | (68,) |
源碼解讀
1.讀取模型&&生成面部網(wǎng)格
讀取處理過的BFM模型
bfm = MorphabelModel('Data/BFM/Out/BFM.mat') print('init bfm model success')用隨機的形狀系數(shù)和表情系數(shù)生成面部網(wǎng)格
sp = bfm.get_shape_para('random') ep = bfm.get_exp_para('random') vertices = bfm.generate_vertices(sp, ep)tp = bfm.get_tex_para('random') colors = bfm.generate_colors(tp) colors = np.minimum(np.maximum(colors, 0), 1)sp對應形狀系數(shù)α\alphaα,ep對應表情系數(shù)β\betaβ,tp對應的是紋理系數(shù)。這些系數(shù)均隨機產(chǎn)生。
這部分對應的源碼如下:
形狀和表情部分進行了下式的矩陣運算:
紋理部分也進行了類似運算,這里不贅述。
到這里產(chǎn)生了新的人臉模型。
2. 網(wǎng)格位置變換
變換網(wǎng)格頂點位置到合適處。
s = 8e-04 angles = [10, 30, 20] t = [0, 0, 0] transformed_vertices = bfm.transform(vertices, s, angles, t) projected_vertices = transformed_vertices.copy() # using stantard camera & orth projection def transform(self, vertices, s, angles, t3d):R = mesh.transform.angle2matrix(angles)return mesh.transform.similarity_transform(vertices, s, R, t3d)對應的源碼:
def similarity_transform(vertices, s, R, t3d):''' similarity transform. dof = 7.3D: s*R.dot(X) + tHomo: M = [[sR, t],[0^T, 1]]. M.dot(X)Args:(float32)vertices: [nver, 3]. s: [1,]. scale factor.R: [3,3]. rotation matrix.t3d: [3,]. 3d translation vector.Returns:transformed vertices: [nver, 3]'''t3d = np.squeeze(np.array(t3d, dtype = np.float32))transformed_vertices = s * vertices.dot(R.T) + t3d[np.newaxis, :]return transformed_vertices這部分和之前pipeline源碼分析中的頂點位置變換部分相同,輸入為網(wǎng)格頂點vertices、縮放比例s、旋轉(zhuǎn)矩陣R和平移向量t3d執(zhí)行空間坐標變換s*R.dot(X) + t后輸出變換后的頂點位置
3.轉(zhuǎn)化為二維圖像
這部分同樣與pipeline例程相同,放出來代碼:
h = w = 256; c = 3 image_vertices = mesh.transform.to_image(projected_vertices, h, w) image = mesh.render.render_colors(image_vertices, bfm.triangles, colors, h, w) plt.imshow(image) plt.show()得到新生成的三維人臉模型圖片如下圖:
后續(xù)將繼續(xù)更新代碼后半部分的解讀,敬請關注
總結(jié)
以上是生活随笔為你收集整理的Face3D学习笔记(4)3DMM示例源码解析【中上】3DMM模型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: golang的sync包例子
- 下一篇: Git 常用命令整理(持续更新)