​单张图像三维人脸重建必备入门face3d—3DMM

作者:小灰灰 来源:投稿
编辑:学姐

本次的例子是将pipeline生成的图片作用于3DMM,重新拟合成新的图片。

load model

3DMM的表达式:

𝑆̅ ∈ 𝑅3𝑛是平均人脸形状,𝐴 脸扫描训练得到的身份基,是人脸的身份参数。𝐴𝑒𝑥𝑝是表情基,是人脸的表情参数。这个公式只要我们确定199维的形状参数和29维的表情参数就可以得到一张三维模型。

bfm = MorphabelModel('Data/BFM/Out/BFM.mat')

这里面是使用牙买加人脸,200个人脸,男生与女生个100个训练出来的。这个mode里面有:

'shapeMU': [3*nver, 1]. *  自然状态下的一个人脸
 'shapePC': [3*nver, n_shape_para]. *  s1,s2  有199 特征向量
 'shapeEV': [n_shape_para, 1]. ~   形状的特征值
 'expMU': [3*nver, 1]. ~       有平均的表情形状,有一个人脸
 'expPC': [3*nver, n_exp_para]. ~    有29个表情特征向量
 'expEV': [n_exp_para, 1]. ~          有29个特征值
 'texMU': [3*nver, 1]. ~           有平均形状的纹理
 'texPC': [3*nver, n_tex_para]. ~   有纹理199特征向量
 'texEV': [n_tex_para, 1]. ~           有 199纹理特征值
 'tri': [ntri, 3] (start from 1, should sub 1 in python and c++). *  105840行三角形
 'tri_mouth': [114, 3] (start from 1, as a supplement to mouth triangles). ~  嘴114
 'kpt_ind': [68,] (start from 1). ~    在53215中其中68个是关键点

可以看到我们将表情的与形状的值加起来得到新的。

model['shapeMU'] = (model['shapeMU'] + model['expMU']).astype(np.float32)
model['tri'] = model['tri'].T.copy(order = 'C').astype(np.int32) - 1 
#减一是从1开始,从零开始
model['tri_mouth'] = model['tri_mouth'].T.copy(order = 'C').astype(np.int32) - 1 
# 114,3 包含嘴的三角形 
# kpt ind
model['kpt_ind'] = (np.squeeze(model['kpt_ind']) - 1).astype(np.int32)
#原始的索引都是从1开始的,68个索引。

generate face mesh

根据3DMM我们知道就可以生成一张图片,我们将需要的参数进行随机数乘以一个非常大的数。

sp = bfm.get_shape_para('random')#形状
 ep = bfm.get_exp_para('random')#表情

(-1.5,1.5)之间,有可能增强表情,优肯削弱表情。

在根据sp, ep的参数,根据3DMM公式去生成人脸。

公式对应的的代码

vertices = self.model['shapeMU'] + self.model['shapePC'].dot(shape_para) + self.model['expPC'].dot(exp_para)
vertices = np.reshape(vertices, [int(3), int(len(vertices)/3)], 'F').T
colors = self.model['texMU'] + self.model['texPC'].dot(tex_para*self.model['texEV'])
colors = np.reshape(colors, [int(3), int(len(colors)/3)], 'F').T/255.

随机生成的三维人脸如下:

transform vertices to proper position

我们将随机生成的三维人脸经过👇

s = 8e-04
 angles = [10, 30, 20]
 t = [0, 0, 0]

pipepline中讲过,通过s,a,t可以直接生成下面的图片左图所示。对应的三维模型右图所示。这是通过代码生成的图片。

本节介绍怎样通过3DMM来拟合生成跟输入的上述图片近似一样。

代码中取出68个点进行比较。

x = projected_vertices[bfm.kpt_ind, :2]

接下来需要68个点x,68个点对应的索引。

fitted_sp, fitted_ep, fitted_s, fitted_angles, fitted_t = bfm.fit(x, X_ind, max_iter = 3)

x: (n, 2) 是二维图片的坐标,X_ind:代表的是68个点对应的索引的三维点。max_iter:是迭代的次数。

3.1 fit_points

进行优化

fitted_sp, fitted_ep, s, R, t = fit.fit_points(x, X_ind, self.model, n_sp = self.n_shape_para, n_ep = self.n_exp_para,max_iter = max_iter)

接下来看代码:

sp = np.zeros((n_sp, 1), dtype = np.float32)
 ep = np.zeros((n_ep, 1), dtype = np.float32)

shapeMU = model['shapeMU'][valid_ind, :]
 shapePC = model['shapePC'][valid_ind, :n_sp]
 expPC = model['expPC'][valid_ind, :n_ep]

上面的shapeMU是根据平均人脸,shapePC选出平均的199个包含68个关键点的人脸,expPC选出29个表情包含68个关键点的人脸。

上面的就是以前53215个点,现在变成68个点进行采集,204是68*3,3表示的是x,y,z

接下来进行迭代:

for i in range(max_iter):

我们根据3DMM公式:

对应的代码为:

X = shapeMU + shapePC.dot(sp) + expPC.dot(ep) #X.shape=(204, 1)

将(204,1)变成(3,68)

X = np.reshape(X, [int(len(X)/3), 3]).T

3.2 estimate_affine_matrix_3d22d

这个函数是我们要找一个变换将三维空间的点变换到一个二维空间的点。

X表示三维的点,x表示二维的点。

X = X.T; x = x.T
 assert(x.shape[1] == X.shape[1])
 n = x.shape[1]
 assert(n >= 4)

这里面我们要解方程组,八个未知数,所以n的大于等于4才能解出方程组。

求x的均值,求模长的平均

x = x - np.tile(mean[:, np.newaxis], [1, n])
average_norm = np.mean(np.sqrt(np.sum(x**2, 0)))
scale = np.sqrt(2) / average_norm #0.03789943607443278

为什么是np.sqrt(2),因为边长为1的等腰直角三角形的斜边就是np.sqrt(2)

三维的点同理可得:

我们需要求八个数,来得到二维坐标

A = np.zeros((n*2, 8), dtype = np.float32);
 X_homo = np.vstack((X, np.ones((1, n)))).T
 A[:n, :4] = X_homo
 A[n:, 4:] = X_homo
 b = np.reshape(x, [-1, 1])
X1=P1X1+P2X2+P3X3+P4
Y1=P1Y1+P2Y2+P3Y3+P4
X1=P1XZ1+P2YZ2+P3Z3+P4Z

可使用下面的代码可得

我们估计P矩阵,第一行是P8的前四个数,第二行是P8的后四个是,第三行是0 0 0 1

通过齐次坐标可以是x=PX实现二维点与三维点的转换。

这里面的UV是下面的这个图:

3.3 P2sRt(P)

  • 代码对应的意思就是将x,y,z旋转之后到x,y的坐标轴上。

  • 主要恢复S,R,T

3.4 matrix2angle(R)

主要用R矩阵恢复夹角。

x: pitch y: yaw z: roll

会把旋转的三个角度算出来,把算出来的三个角度与一开始生成图片的角度的图片10,30,20,匹配看是否相等,那么根据步骤(2 再固定αi,βi 优化s,R,t ) 我们已经把s,r,t估计出来了,那就会估计 αi,βi 形状参数和表情参数。

3.5 estimate shape

下面就是估计

3 固定s,R,t,先优化βi 。代码里面是estimate_expression.

4 固定s,R,t,在优化αi。代码里面是estimate_shape.

verify fitted parameters

接下来就是通过参数进行顶点的生成,通过s,r,t得到旋转的顶点,然后渲染回2D图片,具体可详看pipepline。

# verify fitted parameters
 fitted_vertices = bfm.generate_vertices(fitted_sp, fitted_ep)
 transformed_vertices = bfm.transform(fitted_vertices, fitted_s, fitted_angles, fitted_t)
 
 image_vertices = mesh.transform.to_image(transformed_vertices, h, w)
 fitted_image = mesh.render.render_colors(image_vertices, bfm.triangles, colors, h, w)

三维人脸重建经典论文解读👇👇👇点击卡片学起来

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在国外,基于单图像三维人脸重建是一个非常活跃的研究领域。许多研究人员致力于开发各种算法和模型,以从单个图像中恢复出准确和逼真的三维人脸形状。 以下是一些国外的研究现状: 1. 3DMM方法:3D Morphable Model(3DMM)是一种经典的方法,通过对大量人脸数据进行建模,将人脸的形状和纹理表示为低维参数空间。这些参数可以用来重建人脸三维形状。一些研究通过改进3DMM模型的生成过程,提高了重建的准确性和逼真度。 2. 深度学习方法:近年来,深度学习技术在单图像三维人脸重建中取得了显著进展。研究人员使用卷积神经网络(CNN)或生成对抗网络(GAN)等深度学习模型,通过从大规模数据集中学习人脸的特征表示和形状变化,实现了更准确和细致的三维人脸重建。 3. 结合几何和纹理信息:一些研究将几何信息和纹理信息相结合,以提高重建的精度和真实感。这些方法通常利用纹理图像中的细节信息来辅助形状重建,并使用几何约束来提高纹理贴图的对齐和一致性。 4. 多视角方法:除了单个图像,一些研究还利用多个视角的图像来进行三维人脸重建。这些方法通过结合多个视角的信息,可以更精确地恢复出人脸三维形状。 5. 实时重建:近年来,也有一些研究致力于实现实时的三维人脸重建。这些方法通常采用轻量级的网络结构和优化算法,以在实时性要求下实现准确的人脸重建。 总体而言,国外的研究者们在基于单图像三维人脸重建领域取得了显著进展。不断涌现的新算法和技术为实现更准确、高质量的三维人脸重建提供了可能,为面部分析、虚拟现实、增强现实等领域带来了许多应用机会。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值