单张图像三维人脸重建必备入门face3d--pipeline

news2025/1/9 14:35:42

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

上期传送门👉单张图像三维人脸重建必备入门face3d—3DMM

三维人脸的必备入门就要看Yao Feng写的https://github.com/YadiraF/face3d 这个代码主要介绍了3D人脸的一些功能,处理网格数据,生成3D人脸,从单张二维人脸图片重建三维图像,face3D是个非常轻量化的,而且都是用numpy写的。

下载代码:

git clone https://github.com/YadiraF/face3d
cd face3d

编译c++文件

cd face3d/mesh/cython
python setup.py build_ext -i

准备BFM文件:

https://github.com/YadiraF/face3d/blob/master/examples/Data/BFM/readme.md

接下来就可以运行下面8个例子。

运行python 1_pipeline.py

运行出结果

接下来对 1 pipeline的详细解读。

这个算法主要介绍了一些常用的技术,投影,旋转,平移,变换等,pipeline输入是一个三维人脸,投影到二维图片,对原始的三维人脸做一些光照,旋转,平移等一些操作,然后投影到二维图像中,并进行着色。1_pipeline做的就是这样的操作。上面的图片就是渲染出来的操作,输入就只有正脸,没有什么光照,就只有顶点和纹理的信息。这部分将会理解三维变换到二维是怎么做的。

导入三维模型

我们首先导入三维模型,看看三维模型里面存储的数据。

上面的代码就是导入三维模型,读取顶点信息vertices,顶点上的颜色信息colors,三角面片信息triangles。

根据debug结果可看到,vertices=-57269.51394714276 35239.70262979373 81402.35405980109(shape=(53215,3))表示它的三维顶点x,y,z的值,colors=0.6821081325185221 0.48736642660892804 0.39795203018737824(shape=53215,3) 表示顶点x,y,z的点所表示的颜色信息,r,g,b的值,triangles=0 130 1(shape=105840,3)表示顶点序列0,130,1三个顶点序列连接起来构成的三角面片。

上图默认序列是从0开始,按顺序向下数到0到53214总共53215个顶点。

可以看到,导入的模型库的可视化为:

modify vertices

s = 180/(np.max(vertices[:,1]) - np.min(vertices[:,1]))

是将x,y,z中的y的最大值减去最低值,求得比例系数,可得

输入的三维模型是一个正脸的模型,接下来我们对原始的正脸进行旋转,

这个是对人脸进行pitch, yaw, rol角度的设置,具体详情可看

https://www.cnblogs.com/xiaoxiaoqingyi/p/6932008.html

改变pitch, yaw, rol的不同角度可得。

angle2matrix

接下来看,旋转矩阵angle2matrix([0, 30, 0])进到函数可看到:

旋转的角度x,y,z假设绕x轴旋转,pitch代表抬头,点头,yaw摇头,z表示歪头。

x, y, z = np.deg2rad(angles[0]), np.deg2rad(angles[1]), np.deg2rad(angles[2])

表示将角度信息转换为弧度信息。

接下来绕x,y,z旋转矩阵可表示:

「可最终得到的旋转矩阵为:」

R=Rz.dot(Ry.dot(Rx))

平移t = [0, 0, 0] 那么s,r,t都有了,接下来对顶点做操作

similarity_transform

是根据s,r,t进行操作,先对顶点进行旋转矩阵相乘,在乘缩放因子,在加偏移,可得到

transformed_vertices(shape=53215,3)

「可视化为:」

左图为无颜色,右图为有颜色。

modify colors/texture(add light)

这个是颜色的信息,在已经有r,g,b的颜色信息上进行处理,为什么要进行处理,因为要进行颜色的渲染,需要使用到光照模型,将某些地方进行打光,首先要确定打光的位置点。

light_positions = np.array([[-128, -128, 300]])

这行代码是确定光照的位置放在-128, -128, 300点上。为什么要设置二维数组,是因为有可能有多个光点。

light_intensities = np.array([[1, 1, 1]])

是r,g,b三个光照的强度,也就是发的什么光,例如我们将[[1, 1, 1]] 变换成[[1, 0, 1]],可得下图:

add_light

传参为:transformed_vertices, triangles, colors, light_positions, light_intensities)

这个函数是对原始的颜色进行处理,我们需要用到转换后的顶点transformed_vertices,三角剖分triangles,原始的颜色colors,light_positions光的位置,light_intensities对光的强度。

第一步:我们求三维人脸顶点所对应的法向量normal,

normals = get_normal(vertices, triangles) # [nver, 3]

我们将三角形的第一列,第二列,第三列取出来,得到点的信息,得到向量,将图片中的向量进行X乘。得到垂直于三角平面的法向量。

但是我们要求点的法向量。将周围的三角形的法向量加起来求平均值就是点的法向量。

normal = np.zeros_like(vertices, dtype = np.float32).copy() # [nver, 3]
mesh_core_cython.get_normal_core(normal, tri_normal.astype(np.float32).c

opy(), triangles.copy(), triangles.shape[0])

「这段函数就是求取每个点的法向量。」

得到的法向量进行归一化。

normal = normal/np.sqrt(mag[:,np.newaxis])

将模长为0时,强制设置成1,

mag[zero_ind] = 1;

得到每一点的法向量

normals = get_normal(vertices, triangles) # [nver, 3]

「第二步我们将得到的法向量,根据光照模型,添加光照。」

就是对r,g,b点根据法向量求取夹角。

direction_to_lights = vertices[np.newaxis, :, :] - light_positions[:, np.newaxis, :] # [nlight, nver, 3]

nlight表示的是有几种光源,never表示一个光源到53215到的向量。

direction_to_lights_n =np.sqrt(np.sum(direction_to_lights**2, axis = 2)) # [nlight, nver]

将向量进行归一化,

direction_to_lights = direction_to_lights/direction_to_lights_n[:, :, np.newaxis]

除以模长,此时得到的就是真正的光照到点的向量。

我们有了每一个点的法向量normals ,光线入射的向量direction_to_lights,那么就可以求得每一个点的夹角。夹角越大,光线更弱,

normals_dot_lights = normals[np.newaxis, :, :]*direction_to_lights # [nlight, nver, 3]
normals_dot_lights = np.sum(normals_dot_lights, axis = 2) # [nlight, nver]

去做点积,然后求和就可以求得cos值。

然后将颜色值r,g,b跟cos相乘,再跟关照强度进行相乘。

diffuse_output = colors[np.newaxis, :, :]*normals_dot_lights[:, :, np.newaxis]*light_intensities[:, np.newaxis, :]

我们将几束光进行求和。

diffuse_output = np.sum(diffuse_output, axis = 0) # [nver, 3]

得到光线到点的颜色值。

接下来对小于0的取1,主要用来得到暗的。

lit_colors = diffuse_output # only diffuse part here.
 lit_colors = np.minimum(np.maximum(lit_colors, 0), 1)

最终我们得到光照的颜色值。可视化如图:

左边是原始图像,右边是添加光照之后的图像。

modify vertices(projection. change position of camera)

我们将顶点,颜色都进行变换了,那么接下来就是将三维模型渲染到二维图片。那么一般将现实世界进行拍照的时候,我们就要拿相机,进行拍照,所以首先的知道相机的位置。

camera_vertices = mesh.transform.lookat_camera(transformed_vertices, eye = [0, 0, 200], at =np.array([0, 0, 0]), up = None)

lookat_camera是照相机在看,需要变换的点transformed_vertices,eye表示照相机的位置,at是看哪个点[0, 0, 200],up是我的照相机向上看的方向。

将拼接成一个矩阵,将矩阵减去一个eye,然后去乘一个旋转矩阵,返回的就是人脸的位置回归到照相机的位置,接着我们做了一个正交投影。

render(to 2d image)

这个主要是将坐标进行做一个变换。下面的代码就是做坐标的平移。

得到的值就是x,y的坐标

可以看到我们得到的是53215,3个点,但是我们想要变换成图片,大小应该是256*256的尺寸,怎样将53215个点放在图像上,就得渲染图像。

rendering =  mesh.render.render_colors(image_vertices, triangles, lit_colors, h, w)

我们渲染图片需要点image_vertices,triangles, lit_colors, h, w

render_colors_core

主要是渲染图片,传入图片,点,三角面片。我们将三角形的三个点,得到三角形的内部的,进行三角剖分,得到每个三角形的索引.tri_p0_ind,tri_p1_ind,tri_p2_ind.

根据三角形的索引取得三个点的坐标,p0.x,p1.x,p2.x 算的横轴坐标的最大值最小值,x_min,x_max,y_min,y_max。用来求取三角形内部的像素值是多少。遍历矩阵里面三角形,求取的像素值。

p.x = x; p.y = y;默认为当前的点的像素值。通过isPointInTri c++函数来实现。

p0_color = colors[ctri_p0_ind + k];

p1_color = colors[ctri_p1_ind + k];

p2_color = colors[c*tri_p2_ind + k];

「通过三角面片的三个点求得colors值。」

「最终求得图像的点的像素」

p_color = weight[0]*p0_color + weight[1]*p1_color + weight[2]*p2_color;
 image[y*w*c + x*c + k] = p_color;

就可以求得。

最终取得的图片如下图

总结

整个流程就是将一个三维的人脸经过一系列的处理,旋转,平移,光照的流程。详细课程就请来深度之眼的三维重建paper专题来学习。

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

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

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

相关文章

Python -- 函数

目录 函数的介绍 1.函数定义和调用 2.函数的参数 2.1 定义、调用带有参数的函数 2.2 调用函数时参数的顺序 3.函数的返回值 3.1 返回值介绍: 3.2 带有返回值的函数 3.3 保存函数的返回值 4.文档注释 4.1 基本使用 4.2 高级使用 5.函数调用函数 6.函数高…

基于java的拼图游戏的设计与实现-计算机毕业设计

项目介绍 java版拼图游戏的功能有开始游戏,背景图片(可自己选择添加图片),难度选择(9格的初级,16格中级和以及25格的高级),成绩统计,分数排名等功能。游戏界面具有外观简洁美丽,操作…

Django学习Day4

1.静态文件 静态文件一般是指网页中的图片、js、css、音视频文件。是指不会随着用户的请求动态变更的文件信息和互联网资源。 关于静态文件的配置,需要在settings.py中进行指定。 (1)配置静态文件的访问路径。 (2)ST…

【NodeJs学习笔记】WebPack介绍

什么是WebPack WebPack主要用于模块打包。 它做的事情是,分析项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用。 官…

如何使用 Git 操控Gitee远程库?如何进行 团队内协作 与 跨团队协作 ?这一篇就够了~

目录 前言 一、创建别名 二、推送本地库到远程库 三、拉取远程库代码到本地库 四、 克隆远程库到本地 五、团队内协作 六、跨团队协作 前言 如何通过Git操作Gitee/GitHub远程库?在Gitee/GitHub上如何进行 团队协作 与 跨团队协作,看完本篇&#x…

关于游戏介绍的HTML网页设计 HTML5期末考核大作业 HTML静态游戏网页作业 web前端开发技术 web课程设计 网页规划与设计

🎉精彩专栏推荐👇🏻👇🏻👇🏻 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业…

LeetCode 热题 C++ 98. 验证二叉搜索树 101. 对称二叉树

力扣98 给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下: 节点的左子树只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。示例 1&#xff1a…

记一次 .NET 某工控MES程序 崩溃分析

一:背景 1.讲故事 前几天有位朋友找到我,说他的程序出现了偶发性崩溃,已经抓到了dump文件,Windows事件日志显示的崩溃点在 clr.dll 中,让我帮忙看下是怎么回事,那到底怎么回事呢? 上 WinDbg 说话。 二&…

Linux文件权限概念

目录 前言 1、Linux 文件属性 1.1、档案类型权限 1.2、连结数 1.3、档案拥有者 1.4、档案所属群组 1.5、档案容量 1.6、档案最后被修改的时间 1.7、档名(文件名) 2、如何改变文件属性和权限 2.1、改变所属群组, chgrp 2.2、改变档案拥有者, c…

Codeforces Round #838 (Div. 2) E. Tree Sum(组合数学 prufer序列 枚举边算贡献)

题目 n(n<5e5)个点的树&#xff0c;边只能选-1或1&#xff0c; 若对于每个点i来说&#xff0c;i相连的所有边的乘积值为-1&#xff0c;则称这棵树是「good tree」 根据Cayley公式&#xff0c;有种树形&#xff0c; 对于每一种树形&#xff0c;每条边都有2种选择&#xff…

什么是飞书机器人?如何定时发送飞书机器人消息?

什么是飞书机器人&#xff1f; 机器人是飞书应用的一种能力类型。基于飞书的机器人能力&#xff0c;开发者能够以较低的开发成本&#xff08;只需在服务端开发&#xff09;&#xff0c;实现在飞书单聊或群组中的消息推送和简单互动&#xff0c;完成企业系统数据与飞书的互联互通…

42_CAN列表模式接收中断实验

目录 CAN结构体 CAN_InitTypeDef初始化结构体详解 发送及接收结构体: CanTxMsg及CanRxMsg详解 CAN_FilterlnitTypeDef筛选器结构体讲解 硬件连接图 实验源码 CAN结构体 从STM32的CAN外设我们了解到它的功能非常多,控制涉及的寄存器也非常丰富,而使用STM32标准库提供的各…

pandas数据分析总结

Pandas 是 Python 语言的一个扩展程序库&#xff0c;用于数据分析。其中DataFrame&#xff0c;Json&#xff0c;数据筛选的使用频次很高&#xff0c;值得重点将基本用法学习并总结。 版本信息&#xff1a;python 3.7 pandas 1.3.5 一、DataFrame DataFrame 是一个表格型的数…

【持续更新】计算机类PDF整理

计算机相关的书籍太多太多了&#xff0c;整理太多反而很乱&#xff0c;这边我根据自己的经验和理解选了一些典型的书籍&#xff0c;大部分是自己看过觉得很有用的&#xff0c;有些是听说很nice的&#xff0c;有些是经典的&#xff0c;大家可以自行下载。 持续更新中&#xff0…

Kaggle竞赛——Titanic泰坦尼克之灾(0.76315==>0.79186)

Kaggle竞赛网址&#xff1a;https://www.kaggle.com/c/titanic 上一章&#xff1a;Kaggle竞赛——Titanic泰坦尼克之灾&#xff08;保姆级基础版&#xff09; 本次Kaggle泰坦尼克之灾分析过程大致分为&#xff1a; 第1步&#xff1a;了解数据&#xff08;上一章&#xff09; …

19_SpringBoot拓展注解@SpringBootApplication和@Configuration

文章目录Spring Boot拓展注解SpringBootApplication和Configuration0x01_SpringBootApplicationSpringBootConfigurationEnableAutoConfigurationComponentScan0x02_ConfigurationFull 全模式&#xff0c;Lite 轻量级模式Spring Boot拓展注解SpringBootApplication和Configurat…

计算机网络原理 课后习题(作业)持续更新ing

【1-03 】试从多个方面比较电路交换、报文交换和分组交换的主要优缺点 &#xff08;1&#xff09;电路交换的主要特点: ①电路交换三个阶段&#xff1a;建立连接、通信、释放连接&#xff1b; ②在整个通信过程中&#xff0c;通信的双方自始至终占用着所使用的物理信道。 由…

多线程知识笔记(五)_单例模式

文章目录1、什么是单例模式2、饿汉模式3、懒汉模式1、什么是单例模式 单例模式是一种设计模式。 什么是设计模式呢&#xff1f;设计模式就是一种模板&#xff0c;就像做饭的时候&#xff0c;新手做饭什么调料都是一把放进锅里&#xff0c;有的菜就讲究调料的先后顺序&#xff…

Java web 2022跟学尚硅谷(十一) Vue基础和Axios基础和json基础

Java web 2022跟学尚硅谷十一后端基础 书城Vue在js中定义对象的2种方式方式一方式二简单的Vue代码绑定元素的属性方式一 v-bind:value方式二 :value双向数据绑定 v-model:方式一方式二 :value可以省略&#xff0c;trim去除首尾空格条件渲染 v-if条件渲染 v-else条件渲染 特别注…

[附源码]Python计算机毕业设计高校医务管理系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…