一:简介
eos: 一个轻量级的头型3D Morphable面部模型拟合库
GitHub - patrikhuber/eos: A lightweight 3D Morphable Face Model fitting library in modern C++14
1 目前支持以下三种3DMM
Surrey Face Model (SFM),
4D Face Model (4DFM)
Basel Face Model (BFM) 2009
2 使用到的计算相关库 Eigen,glm
3 其中具体示例代码对应的是一个低分辨率的SFM模型sfm_shape_3448.bin
3D 顶点数: 3448个
三角形个数:6736个
输入特征点个数:68个
PCA:
形状PCA: 63 个特征向量 63 * (3448 * 3)
表情PCA: 6 个特征向量 6 * (3448 * 3)
提供了三个文件
1 2D与3D特征点序号对应关系表:
landmarks 与 3D mesh顶点对应数据:只有内部的50个顶点;不包含16个轮廓点。
下巴底部点有对应的3D顶点,1-8为右轮廓点,10-17位左轮廓点
2 3D mesh 可能为边缘轮廓点的序号,分左边轮廓和右边轮廓
3D mesh上可能的边缘轮廓点序号,左轮廓有17个候选点,右轮廓有17个候选点;
3 相邻面,相邻顶点关系图
根据三角形关系可以得到10184个边,可以一个10184*2 的顶点相邻关系矩阵
根据这10184个边,每一个边对应两个三角形面,可以得到10184*2的三角形相邻关系矩阵
图1:2D与3D特征点序号对应关系表
图2:3D mesh 可能为边缘轮廓点的序号
图3: 相邻面
最终X_projection 是三维模型投影到二维平面的点,其中
需要求解的参数有:形状系数 α以及表情系数 β,旋转矩阵R,位移t_2d 以及缩放参数s。
P_orth为一个已知的正交投影矩阵。
最终的目标就是最小化输入的特征点X与投影到二维平面的X_projection的差。
1 求解旋转矩阵相关参数[1]
基于黄金标准算法求相机仿射矩阵,然后进行分解得到R,S,T
2 求解形状系数 α以及表情系数 β [2]
其中表情使用非负最小二乘法,形状使用最小二乘求解系数
[1]: Gold Standard Algorithm for estimating an affine camera matrix from world to image correspondences
[2] O. Aldrian & W. Smith, Inverse Rendering of Faces with a 3D Morphable Model, PAMI 2013.
二 算法总体介绍
即使只进行一次迭代,结果也很好;
当用于单图像拟合和,为了使所有参数完全收敛,最多需要300次迭代;
在实时跟踪中,如果基于前一帧作为初始参数,只需要迭代1-5次效果就很好;
这里的表情拟合和形状拟合是交替的,其实理论上可以将他们进行堆叠,一次性求解,
当然这两个特征向量很可能不是正交的。 但是在任何情况下,交替使用一般认为不会造成 任何伤害。
具体的算法大致流程:
1 获得相机pose
2 计算表情系数
开始循环迭代
{
1 3Dmesh 轮廓点确定(可见边+不可见边);
2 计算仿射矩阵
3 形状系数求解
4 表情系数求解
}
3DMM = mean + a * shape_pca + b * exp_pca
第一步:初始化 a和b均为0;没有颜色pca
current_combined_shape = mean + a * shape_pca + b * exp_pca
current_mesh(current_combined_shape,uv坐标,三角形关系图)
第二步:
vector model_points; // the points in the 3D shape model
vector vertex_indices; // their vertex indices 同样对应的也不一定是68个
vector image_points; // the corresponding 2D landmark points 不一定是68个
根据配置表:
可以确定内部50个2D和3D特征点对应关系;左右16个轮廓特征点和嘴角里面2个没有。
第三步:姿态初始估计:
基于上面对应的50个特征点求解R,S,t
基于黄金标准算法求相机仿射矩阵,然后基于SVD进行分解得到R,S,T,这里谈到 QR(正交三角)分解法也应该可以。
具体代码计算:旋转矩阵会转为四元数,进而得到一个3*4 的仿射矩阵;
第四步:表情拟合,更新参数b
因为脸的形状变化很大,取决于表情。(还是基于上面50对特征点)
因为表情是Blendshapes
fit_blendshapes_to_landmarks_nnls:morphablemodel::Blendshapes
fit_shape_to_landmarks_linear :morphablemodel::PcaModel
采用的非负数最小二乘法,不支持任何正则化;不是采用的pca向量基,而是采用 blendshape,也不是采用mean,而是当前的mean + a*shape_pca(但是其实好像还是mean)。感觉这了blendshape跟pca向量基没啥区别;
第五步: 更新当前形状和mesh
current_combined_shape = mean + a * shape_pca + b * exp_pca
current_mesh(current_combined_shape,uv坐标,三角形关系图)
第六步:迭代
6.1 计算偏航角yaw:示例-29度,向左;
6.2 确定没有遮挡的轮廓点点
6.2.1 确定可能的轮廓点
2D轮廓点有16个特征点,3D顶点提供了可能为轮廓点3D顶点序号34个。
寻找3D顶点中候选轮廓点,一共有左轮廓17个点,右轮廓17个点
根据阈值7.5度,当绝对值介于7.5,认为人脸朝正,34个轮廓点均被选中;
大于7.5,当脸部朝左,选中右边的17个轮廓点,反之选中左边的17个轮廓点;
6.2.2 配对2D轮廓点与3D候选顶点
例如示例为-29度,朝左,所以这一步只能确定右轮廓对应的3D顶点;
针对2D轮廓点右边每一个特征点,计算3D顶点中与之最近的顶点,构成关系对;
这样可以进一步确定8个3D顶点。
6.3 更新确定的2D特征点与3D顶点关系,增加右轮廓的8个顶点;
50 + 8
6.4 确定遮挡面轮廓点:进一步确定上面没有找到对应点的左轮廓点
确定了42个3D顶点;这步是很关键的,需要仔细看。
6.5 更新确定的2D特征点与3D顶点关系,增加左轮廓的42个顶点;
50 + 8 + 42 (2D顶点存在重复)
6.6 姿态估计:基于上面对应的100个特征点求解R,S,t
6.7 形状拟合:更新参数a
此时平均脸为mean + b * exp_pca
这里采用的拟合算法参考 Inverse Rendering of Faces with a 3D Morphable Model, PAMI 2013,它是一个线性的,封闭的解,有正则化;
6.8 表情拟合:更新参数b
此时平均脸为:mean + a * pca_shape
这里采用的拟合算法参考
6.9 整个算法注重得到参数a和b,并没有确定最终对应的68个3D顶点;
7 输出结果mesh
结论:
@1 难点还是在于遮挡面的轮廓点选择;trade off关键点;
eos采取了一种接近全局搜索的方法;
eos:基于法向量,计算相邻法向量是否同向;
顶点自检,发出射线是否射中三角形;
基于2D顶点构建kd树,距离在阈值以内的保留;
2 是否可优化:内部点选择都是直接基于映射表获得;
3 目前的fitting C++ 在选择遮挡轮廓点的时候比较简单,没有
考虑姿态的影响,应该是考虑到速度的平衡;
4 耗时情况:迭代一次,整体耗时254ms,其中寻找遮挡边轮廓点223ms。
@为什么先生2012