论文题目:Joint 3D Face Reconstruction and Dense Alignment with Position Map Regression Network
论文链接:https://openaccess.thecvf.com/content_ECCV_2018/papers/Yao_Feng_Joint_3D_Face_ECCV_2018_paper.pdf
代码链接:GitHub - YadiraF/PRNet: Joint 3D Face Reconstruction and Dense Alignment with Position Map Regression Network (ECCV 2018)
(1)第一次以端到端的方式一起解决了人脸对齐和 3D 人脸重建的问题,而不受低维解空间的限制
(2)为直接回归 3D 面部结构和密集对齐,开发了一种新的表示形式,称为 UV 位置图,它记录 3D 面部的位置信息,并提供与 UV 空间上每个点的语义含义的密集对应
(3)提出了一个用于模型训练的权重掩码,它为位置图上的每个点分配不同的权重并计算加权损失,这种设计有助于提高网络的性能
(4)提供了一个运行速度超过 100 FPS 的轻量级框架,可以直接从 2D 人脸图像中输出 3D 人脸重建和对齐结果
PRNet 的目标是从 2D 图像中回归 3D 面部几何及其密集的对应信息。因此,需要一个可以通过深度网络直接预测的合适表示。一个简单且常用的想法是将 3D 人脸中所有点的坐标连接为一个向量,并使用网络进行预测。然而,这种从 3D 空间到 1D 向量的映射,丢弃了点与点之间的空间相邻信息,增加了网络训练的难度。
为了解决上述问题,作者提出 UV 位置图作为具有对齐信息的全 3D 面部结构的表示。UV 位置图为记录了 UV 空间中所有点的 3D 位置的 2D 图像。作者使用 UV 空间来存储来自 3D 人脸模型的点的 3D 位置,与对应的 2D 人脸图像对齐。如下图所示,假设从 3D 模型到 2D 图像的投影是弱透视投影,3D 空间的原点与输入图像的左上角重叠,正 x 轴指向图像的右侧,最小 z 位于原点。当投影到 x-y 平面时,GT 3D 面部形状与 2D 图像中的面部完全匹配。因此位置图可以表示为 ,其中 表示第 i 个点在人脸表面的 UV 坐标, 表示人脸结构对应的 3D 位置。
PRNet 的位置图记录了 3D 面部的一组密集点及其语义信息,通过 CNN 直接从无约束的 2D 图像回归位置图,同时获得 3D 面部结构和密集对齐结果。值得注意的是,位置图包含整个面部的信息,因此可以预测完整的 3D 人脸。
由于网络将 RGB 图转换为位置图,因此作者采用编码器-解码器结构来学习传递函数,网络架构如下图所示。网络的编码器部分从一个卷积层开始,然后是 10 个残差块,将 256 × 256 × 3 的输入图像缩减为 8 × 8 × 512 的特征图,解码器部分包含 17 个反卷积层以生成预测的 256 × 256 × 3 位置图。所有卷积和反卷积层的 kernel 均为4,并使用 ReLU 层进行激活。
为了学习网络的参数,作者构建了一个损失函数来衡量 GT 真实位置图和网络输出之间的差异。均方误差 (MSE) 是此类学习任务的常用损失,但是,MSE 对所有点一视同仁,因此并不完全适合学习位置图。由于人脸的中心区域比其他区域具有更多的判别特征,因此使用权重掩码来构建损失函数。如下图所示,权重掩码是一个灰度图像,记录了位置图上每个点的权重。作者将点分为四类,每类在损失函数中都有自己的权重。68 个面部关键点的位置权重最高,以保证网络学习到这些点的准确位置。颈部区域通常较少受到关注,并且在不受约束的图像中经常被头发或衣服遮挡。因此为颈部区域的点分配 0 权重以减少训练过程中的干扰。
损失函数如下:
作者选择 300W-LP 作为训练集,因为它包含不同角度的人脸图像,并带有估计的 3DMM 系数的注释,可以很容易地从中生成 3D 点云。具体来说,首先根据 GT 边界框裁剪图像并将它们重新缩放为 256×256 大小。然后利用它们标注的 3DMM 参数生成对应的 3D 位置,并将它们映射到 UV 空间中得到真实位置图。随后通过在 2D 图像平面中随机旋转和平移目标人脸来扰乱训练集。具体来说,旋转是从 -45 到 45 度角,平移变化的比例是从 0.9 到 1.2,概率为 10%。此外,还通过缩放颜色通道 (比例范围从 0.6 到 1.4) 来扩充训练数据。为了处理有遮挡的图像,通过在原始图像中添加噪声纹理来合成遮挡。优化器为 Adam,学习率从 0.0001 开始,每 5 个 epoch 后衰减为原来的一半,batch size 为 16。
作者使用归一化平均误差 (Normalized Mean Error,NME) 作为评价指标。下图为不同偏航角的 NME,
下图表明在某些情况下,PRNet 的预测比 GT 更准确 (绿色的点为预测结果,红色的点为 GT)。
创建虚拟环境并激活:
conda create -n prnet python=3.6
conda activate prnet
需要注意的是 python 版本应该小于等于 3.7,否则安装不了 1.x 版本的 tensorflow,导致如下错误:
ModuleNotFoundError: No module named 'tensorflow.contrib'
安装项目要求的库:
pip install numpy
pip install scikit-image
pip install opencv-python
pip install tensorflow==1.14.0
Cmake 安装链接:
Download | CMake
继续安装库:
pip install cmake
pip install dilb
如果还是安装失败,建议直接去 pypi 官网下载 dilb 的 whl 文件,链接为:
Links for dlib
由于我的 python 版本为 3.6,所以我选择以下版本:
然后 cd 到该文件的目录并输入以下指令:
pip install dlib-19.8.1-cp36-cp36m-win_amd64.whl
安装完成后,下载预训练模型到 data\net_data 目录下。然后根据 parser 里面的 inputDir 与outputDir 的定义,新建对应文件夹,如:
则需要在 results 文件夹下面新建一个名为TestImages的文件夹,用于存放.obj文件。
接下来就可以跑 demo.py 了,终端输入:
python demo.py -i -o --isDlib True --isDepth True
结果展示 (原图 + pseudo depth map):