All

人脸 Mean+PCA 实验

 
 

实验完全基于COMA这份代码,原因是这里面有完整的整个人头的数据库,以及PCA相关的代码,因此只要在这个基础上尝试去实现自己的所想即可。

https://github.com/anuragranj/coma

 
 

首先我们要找到一份实现了读取和存储网格数据的代码,最好还包括实时展示。computeModels.py 是合适选择,做适当的修改即可实现其包含的意义,主要就是展示结果模型的比较。

 
 

代码分析:

 
 

首先是terminal数据输入的支持,这边要注意的是选择的数据,输入的格式如default所示。

 
 

然后是最重要的FaceData数据类型的初始化。

这边要输入的是训练和测试数据集,以及模板模型。我们深入去看facedata数据类型的构成你会发现,这个数据类型里面产生的数据 std, mean, pca 等等全部是根据train数据来生成的,模板模型唯一的作用就是提供face信息。这也就是为什么改动.obj文件对结果没有影响。

因此我们需要的是直接让template.obj成为FaceData数据类型的生成来源,这个改动就是如下:

 
 

再往下就是数据的使用,这里面我们要关注的就是pca。

每次数据乘上std再加上mean就是为了恢复模型顶点数据,因为用于计算的顶点数据是其局部坐标的,加上这个就是模型坐标下。

这里还要注意的是train数据里面是模型集合,不是单个模型,nTest表示的就是测试数据集的模型数量,相似的train的shape[0]表示的就是训练数据集的模型数量,在后续计算的时候要注意。

 
 

在后面就是显示模型和存储模型的代码,这边就不展示了,直接看代码。

 
 

 
 

 
 

 
 

替换实现:

我们这里要实现对PCA人脸表示的mean做替换,实现就如上面所示,直接将生成mean,std的数据类型改成模板模型,这样我们替换模板模型的时候,就实现了我们的期望做法。

这里就是完整的代码展示。

 
 

 
 

 
 

使用的基础模型(原始平均脸):

改变后的模型(改变的平均脸):

 
 

 
 

 
 

效果对比

从左至又分别是 OO, OC. CO, CC,第一个表示基于哪个基础模型提取PCA,第二个表示基于哪个平均人脸模型

这边采用的是基础模型作为提取PCA的基础,然后从左至右分别表示的是:使用基础模型平均人脸的某特殊人脸的原始表示;使用变化模型平均人脸的某特殊人脸原始表示;使用基础模型平均人脸的某特殊人脸的只保留PCA表示;使用变化模型平均人脸的某特殊人脸的只保留PCA表示;

这边采用的是变化模型作为提取PCA的基础,然后从左至右分别表示的是:使用基础模型平均人脸的某特殊人脸的原始表示;使用变化模型平均人脸的某特殊人脸原始表示;使用基础模型平均人脸的某特殊人脸的只保留PCA表示;使用变化模型平均人脸的某特殊人脸的只保留PCA表示;

 
 

 
 

 
 

按照一开始的逻辑:采用原始的平均人脸(基础模型)作为提取PCA的基础;然后在运用平均脸的时候采用改变后的模型,那么目标结果应该是上面12个图的第8个,也就是中间四个的最后一个。

 
 

 
 

 
 

上面结果的问题:上面结果其实是数据normalize的影响导致的,而不是PCA效果!!!

换句话说上面的结果是不对的。

 
 

原因如下,这边重新写了代码来支持使用P9数据:

 
 

这里你会发现,这边其实唯一做的工作就是数据的normalize,但是你会发现其最终结果也就是脸部拉长。

 
 

这时候就要思考,保留的到底是不是特征,早思考下你会发现不是,而仅仅是坐标的normalize偏移。

因为我们来看代码,这边将脸分解成mean和std,mean表示中间坐标,std表示的是各顶点对于mean位置的相对位置。normalize使得原来的长脸数据得到保留,因此最终结果脸部被拉升,这个和原来的公式没有半毛钱关系。

因此上面的实验结果是不对的。

 
 

 
 

我们真正要改的是PCA内部使用的mean,因此我们需要修改代码如下:

 
 

这边要注意的是对base.py文件的修改,这个文件默认不支持pca替换mean,这个文件也不属于coma工程,是coma的依赖工程。

修改如下:

 
 

得到的结果如下:

左边是原始模型,第二个是风格化模型,第三个是原始的PCA结果,第四个是风格化的PCA结果。

 
 

 
 

 
 

下面思考Coma本身的做法是不是也能支持风格转换?

貌似没发支持,做法中间没有平均脸的说法,而且没有意义。