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

news2024/11/22 6:53:32

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

本次的例子是将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)

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/90121.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

国产网关apisix安装

1、安装docker 参考:centos7安装docker_代码手艺人老羊的博客-CSDN博客 2、下载包(从github) # Download the Docker image of Apache APISIX git clone https://github.com/apache/apisix-docker.git 3、安装 # Switch the current di…

单点登录设计

01 单系统登录机制 1、http无状态协议 web应用采用browser/server架构,http作为通信协议。http是无状态协议,浏览器的每一次请求,服务器会独立处理,不与之前或之后的请求产生关联,这个过程用下图说明,三…

JavaScript高级 |彻底搞懂原型对象

本文已收录于专栏⭐️ 《JavaScript》⭐️ 学习指南:对象的原型函数的原型new操作符将方法放原型里constructor总结梳理原型对象内存表现完结散花参考文献对象的原型 JavaScript 当中每个对象都有一个特殊的内置属性[[prototype ]] ,这个特殊的对象可以指向另外一个…

科技云报道:畅想无人化运维的AIOps,还有多远的路要走?

科技云报道原创。 在IT行业,运维人常常自我调侃“赚着5k的月薪,操着5千万的心,名下挂着5亿的资产”。 机房的暖通、网络、综合布线,系统的监控告警、故障响应等一大堆繁杂琐碎的工作,充斥着运维人的日常。 与开发和产…

自定义Feign的配置

SpringBoot虽然帮我们实现了自动装配,但是也是支持自定义配置的。 Feign运行自定义配置来覆盖默认配置,可以修改的默认配置如下: 配置Feign日志有两种方式 方式一:配置文件方式 1)全局生效 feign:client:config:defa…

【愚公系列】2022年12月 Elasticsearch数据库-ELK添加SQL插件和浏览器插件(二)

文章目录前言一、ELK添加SQL插件和浏览器插件1.配置插件2.浏览器插件3.Elasticsearch术语介绍4.测试SQL插件和浏览器插件前言 下载SQL插件地址:https://github.com/NLPchina/elasticsearch-sql 我们选择7.15.2版本,ES页选择7.15.2版本把最后面的下载链…

车间调度|基于遗传算法的柔性车间调度(Matlab代码实现)

目录 1 概述 2 遗传优化算法 3 车间调度 4 运行结果 5 参考文献 6 Matlab代码实现 1 概述 调度通过合理安排生产资源,以缩短生产时间和提高资源利用率为目的,在生产系统中扮演着重要的角色。作业车间调度问题(Job-shop Schedu-ling Problem,JSP)是一类经典…

1996-2020年全国31省农村电力和农田水利建设相关数据

1996-2020年全国31省农村电力和农田水利建设相关数据 1、1996-2020年 2、范围:31省 3、指标包括: 乡村办水电站、装机容量、发电量、农村用电量、有效灌溉面积、旱涝保收面积、机电排灌面积、实际耕地灌溉面积、新增耕地灌溉面积、节水灌溉面积、新增…

2023年第六届先进控制,自动化与机器人国际会议(ICACAR 2023)

2023年第五届先进控制,自动化与机器人国际会议(ICACAR 2023) 重要信息 会议网址:www.icacar.org 会议时间:2023年4月14-16日 召开地点:中国北京 截稿时间:2023年2月28日 录用通知&#xf…

排序子序列

1 题目来源: 牛客网:排序子序列 2 题目描述  牛牛定义排序子序列为一个数组中一段连续的子序列,并且这段子序列是非递增或者非递减排序。牛牛有一个长度为n的整数数组A,他现在有一个任务是把数组A分为若干段排序子序列,牛牛想知道他最少可以把这个数组分…

Ashampoo Burning Studio创建可启动磁盘

Ashampoo Burning Studio创建可启动磁盘 Ashampoo的产品通常适合质量,但在其中,它是世界上最好的软件之一,名为Ashampoo Burning Studio。与著名的Nero程序相比,该软件几乎一无是处,所有用于制作、写入和复制光盘的软件…

Python Tutorial——模块

如果你从Python解释器中退出,并且再次进入,你会发现你以前定义的函数和变量都已经丢失了。所以,如果你想写一个在某种程度上更长的程序,使用一个文本编辑器来准备解释器的输入会使情况有所好转,并且使用文件代替输入来…

最简单的方式实现Zotero文件同步+坚果云在多台电脑设备之间

应用场景: 放假回家,只带了笔记本搞科研的好童靴,发现实验室台式机的zotero中的PDF没办法在笔记本上读取。于是探索了一下午如何不重新在网页上保存下载台式机中的PDF,轻松获取异地的文献。 方式一: 氪金付费zotero…

参数估计与假设检验

推断统计:研究如何利用样本数据来推断总体特征 描述统计:描述一组数据的特征 参数估计:利用样本信息估计总体特征 假设检验:利用样本信息判断对总体的假设是否成立 一.参数估计 就是对于总体指标的估计 估计:根据…

免费l2接口有多少种类型?

免费l2接口是一个预先定义的函数,它的目的是让开发人员和开发人员无需访问源代码,也无需访问源代码,也无需理解其内部工作。免费l2接口有多少种类型? 有四种类型的股票l2接口: RPC:通过处理(或任务)共享的数据缓冲区…

SpringBoot整合RabbitMQ实现死信队列

文章目录概念介绍什么是死信死信队列应用工程搭建环境说明搭建步骤实现死信准备Exchange&Queue监听死信队列方式一——消费者拒绝&否认方式二——超过消息TTL方式三——超过队列长度限制代码仓库前面一文通过 Java整合RabbitMQ实现生产消费(7种通讯方式&…

Spark的运行模式介绍

Spark的运行模式 本地模式(Local) 一般用做测试,测试代码的逻辑是否正确 本地模式,只启动一个Driver进程,没有Executor进程的,所有Task都运行在Driver进程中 集群模式 (Cluster) 一…

医疗挂号网站

开发工具(eclipse/idea/vscode等): 数据库(sqlite/mysql/sqlserver等): 功能模块(请用文字描述,至少200字): 管理员功能: 1、管理挂号须知、帮助信息 2、增删改查资讯类型、健康资讯信息 3、增删改查医生职称信息、医生…

装载问题 ——回溯法(Java)

装载问题 ——回溯法(Java) 文章目录装载问题 ——回溯法(Java)1、 问题描述1.1 装载问题1.2 转换问题2、算法设计2.1 可行性约束函数2.2 上界函数2.3 解空间树2.4 剪枝函数2.5 算法设计3、程序代码4、参考资料1、 问题描述 有一…

Hadoop安装准备

虚拟机的安装 配置了静态IP地址(192.168.1.100) 关闭与禁用了防火墙 安装了vim编辑器 虚拟机克隆 克隆出master虚拟机 以同样的步骤克隆出slave1和slave2 虚拟机配置 配置master虚拟机 启动虚拟机 设置主机名 命令:hostname…