论文部分:
一:创新点:
背景:大部分论文在进行人脸对齐重建的时候,大多数关注模型的精确性(模型的好坏,用NME来衡量),很大程度上忽略了模型的运行速度 ; 所以该论文针对这一问题,在提高模型精确性的前提下,同时提高模型的运行速度;于此,在视频上进行三维人脸重建的领域越来越重要,而在视频上进行人脸对齐的稳定性问题仍然滞留,基于该问题提出了在视频上进行三维人脸重建提高稳定性的方法;
1:采用轻量级的网络模型回归出3DMM的参数,然后为该网络设置了meta-joint optimization优化策略,动态的组合wpdc和vdc损失函数,从而加速了拟合的速度,也使得拟合的效果更加精确 ;
2:提出landmark-regression regularization(特征点回归正则化)来加速拟合的速度和精确度;
3:为了解决在video上的三维人脸对齐任务(相邻帧之间的三维重建更加稳定,快速,连续性),在基于video数据上训练的模型,但video视频数据库缺乏时,提出了3D aided short-video-synthesis(三维辅助短视频合成技术),将一个静止的图片在平面内还有平面外旋转变成一个短视频;
conclude:在支撑材料中可以看到作者提出的三个所有的创新方法具有很好的泛化扩展能力,即将这些创新的方法用在其他的模型上进行训练,也能很好的提高这些模型的能力!
二:3DMM
1:回归参数截取:
这篇论文利用神经网络回归出来的参数起初维度是 形状向量参数为199 表情向量参数是29 ,但是由于是采用PCA来进行建模3D人脸,后面的参数具有很少的影响性;同时下图也展示了采取不同的参数截取策略具有不同的NME,进一步证明参数截取的策略,即截取40个形状向量参数,10个表情向量参数 ;
2:参数的归一化处理:
为了消除形状向量,表情向量参数 α 与 矩阵T的影响,所以在得到3DMM参数后,归一化处理得到的参数 ;
3:3D人脸与2D人脸之间的公式只差一个正投影P参数!
三:损失函数的设计:
1:vdc与wpdc的说明:略
2:设计fwpdc(快速权重参数距离损失),只加速fwpdc损失函数的收敛时间,但不改变收敛时的值;fwpdc得算法设计计算如下:
3:vanilla-joint optimization:
Lvanilla-joint=βLf wpdc+ (1−β)|lf wpdc||lvdc|· Lvdc, β∈[0,1] ; 普通联合优化器按照固定的权重组合fwpdc和vdc损失函数,但效果不佳 ;
4:meta-joint optimization :
在使用fwpdc损失函数训练好模型后,然后保存此次模型的训练结果;之后开始进行下次训练,在训练前,将模型的参数初始化为上次保存的模型,然后在使用vdc损失函数继续对该模型进行训练!
基于这种发现,提出了meta-joint optimization ,即动态的组合fwpdc和vdc损失函数进行训练。
4-1接下来是关于元联合优化器的训练过程:
1:选取K个批次样本X_mtr 对于元训练,并且一个批次 X_mte 对于元测试;
2:用X_mtr数据集对网络进行分别在损失函数为fwpdc和vdc下进行训练模型,此时的网络参数有了两个新的值更新,假设参数值更新后,我们获得两个新的网络;
3:接下来用X_mte数据集对这两个新的网络参数更新进行测试,用vdc损失函数值来判断哪个模型的损失值最小,此时选取损失值小的网络模型的参数作为我们原模型的真实更新参数 ;
经过对比性实验可知,元联合选项的损失函数训练的模型具有很好的表现性;
4:meta-joint 策略中损失函数的时间段表现性如下图所示 :
通过该图可知,模型的参数在前期会选取以fwpdc作为损失函数训练的模型的参数作为更新,后期的时候,会选以vdc作为损失函数训练的模型的参数作为 真实的模型参数更新值!
四:3D Aided Short-video-synthesis(三维辅助短视频合成技术)
1:背景:为了解决视频中三维人脸对齐的问题,基于视频数据训练的模型,由于视频数据非常稀缺,所以在此基础上提出了三维辅助短视频合成技术;该技术主要将一个静止的图片,利用平面内和平面外的旋转,从而将其转换为短视频;
2:作用:经测试发现,该技术共有两个作用; 一是对模型的训练有促进作用(用NME来衡量模型是否优越,可用21,68,NK个三维特征点之间的距离损失来计算dist);二是促进了在视频上进行三维人脸重建时候的稳定性(用相邻帧之间的偏移差异来衡量视频中三维人脸重建的稳定性)
2:平面内旋转T(.):由Xt图片经过平面内旋转到Xt+1图片,等价于如下公式进行旋转,
其中∆s 参数是缩放扰动,∆θ参数是旋转扰动,∆t1 ∆t2是平移扰动;
3:平面外旋转F(.):利用偏航和俯仰两个属性对图片进行旋转,
4:将图片根据如下公式从而合成含有N个帧的短视频
{x0j | x0j = (M◦P) (xj) , xj = (T◦F)(xj−1) , 1≤ j ≤ n−1} ∪ {x0} ,其中T是平面内旋转,F是平面外旋转,M是motion blur , P是噪声参数 ;
如下图所示是一个完整的图片合成短视频过程:
从后往前推导:可知要形成帧x1j ,就要对图片x1进行模糊与噪声处理;至于x1图片的形成要对图片x0(此时x0照片已知)进行平面内T和平面外F的旋转(具体旋转参数图上已给); 要形成帧x2j, 就要对图片x2进行模糊M与噪声P处理,至于图片X2的形成,要用到x1图片,对x1图片进行固定参数下的平面内T和平面外F的旋转 ; 而x1图片,刚才已知 ; 所以此时便可从前往后逆着推,可以清楚明白三维辅助短视频合成技术如何生成短视频的步骤 ;
五:实验
1:训练数据集与测试数据集:
不同于3DDFA先前的工作,不仅评估了训练模型后的精确性,该论文也评估了在视频上三维人脸重建的稳定性,同时也评估了模型的速度,所以在使用AFLW,AFLW-2000 的数据集用来评估精确性外。同时也使用了Menpo-3D视频数据集来对模型展开测试来评估在视频上进行三维人脸对齐的稳定性(用相邻帧之间的偏移差来衡量在视频上三维人脸重建的稳定性)
代码部分:
此论文附属的代码并未提供测试与训练的代码,只提供了提前训练好的模型且存储在pth文件中;
1:接下来主要是关于定义204[3, 64]个点,为什么要定义u_base , w_sha_base , w_exp_base的说明 :
之所以在bfm模型数据库中计算这些_base的小批数据,就是在利用公式重建出三维人脸模型并用稀疏特征点表示该三维人脸模型时,计算公式中所用到的恰是这些小批_base数据 ; 最后的结果维度恰是【3 ,68】即68个特征点的三维坐标;
2: obj文件: 将人脸保存为obj文件 即保存了这个特征点的形状属性,又保存了这个点的纹理属性(r1, g1, b1) ;
ply文件:将人脸保存为ply文件, 只保存了这个特征点的形状属性(x1, y1, z1),不保存纹理属性;
3:关于Faceboxs边界框检测器的说明:
facebox检测器传入人脸照片,返回的是个列表,用来存储边界框bbox(是个列表,共有5个数据),有几个人脸就有几个边界框 ; 接下来可以利用bbox边界框获得roi_box参数,然后便可以利用roi_box参数画出边框或者精确的剪切出人脸照片;
当然,一共有两种方法可以获得roi_box参数,另外一种就是利用68landmarks获得roi_box参数; 注意和dlib人脸检测器之间的区分呢!
import sys
sys.path.append('..')
from FaceBoxes import FaceBoxes
import numpy as np
import cv2
from utiles.functions import parse_roi_box_from_bbox
RED = (0, 0, 255)
GREEN = (0, 255, 0)
BLUE = (255, 0, 0)
img = cv2.imread('D:\Python_code\\3DDFA_V2-master\examples\inputs\emma.jpg')
width = img.shape[1]
height = img.shape[0]
img = cv2.resize(img, (int(width*0.2), int(height*0.2)), interpolation=cv2.INTER_AREA)
face_detector = FaceBoxes()
boxes = face_detector(img) # 获得边界框bbox ; 有几个人脸就有几个bbox ;
roi_boxes = [] # 用来存储roi_box参数 ;
for box in boxes:
roi_box = parse_roi_box_from_bbox(box) # 利用bbox边界框获得roi_box参数 ;
roi_boxes.append(roi_box)
for box in roi_boxes:
left, top, right, bottom = np.round(box).astype(np.int32)
left_top = (left, top)
right_top = (right, top)
right_bottom = (right, bottom)
left_bottom = (left, bottom)
cv2.line(img, left_top, right_top, BLUE, 1, cv2.LINE_AA)
cv2.line(img, right_top, right_bottom, BLUE, 1, cv2.LINE_AA)
cv2.line(img, right_bottom, left_bottom, BLUE, 1, cv2.LINE_AA)
cv2.line(img, left_bottom, left_top, BLUE, 1, cv2.LINE_AA)
cv2.imshow("win", img)
cv2.waitKey()
运行结果如下: