上一篇博文讲了如何在人脸图像中获得面部特征。这篇博文主要介绍面部的几何模型。
在人脸跟踪系统中,几何形状是指在人脸图像上预先定义的一组点的空间结构,这组点与真实人脸上某些几何形状(如眼角、鼻尖和眉毛边缘)保持一一对应关系。
面部几何参数变化通常有两个因素组成:全局(刚性)变化和局部(非刚性)形变。全局变化考虑人脸在图像中的整体位置,允许人脸随意变化。局部形变考虑的是不同人面部形状以及同一个人面部表情的差异。换句话说,全局变化是二维坐标的常规处理,可用于任意类型的对象。局部形变针对的是具体对象,需要从训练集中学习。
定义一个形状模型描述面部的几何模型:
class shape_model //2d linear shape model
{
public:
Mat p; // parameter vector (kx1) CV_32F
Mat V; // linear subspace (2nxk) CV_32F
Mat e; // parameter variance (kx2) CV_32F
Mat C; // connectivity (cx2) CV_32S
int npts() { return V.rows / 2;} //number of points in shape model
void calc_param(const vector <Point2f> &pts, //points to compute paramters from
const Mat weight = Mat(), //weight of each point (nx1) CV_32F
const float c_factor = 3.0); //clamping factor
vector<Point2f> calc_shape(); //shape described by parameters @p
void set_identity_params(); //set @p to identity
Mat rot_scale_align(const Mat &src, //scalede rotation mat (2*2) CV_32F, src: source points
const Mat &dst); //destination points
Mat center_shape(const Mat &pts); //centered shape, shape to center
void train(const vector<vector <Point2f> > &p, //N_example shape
const vector<Vec2i> &con = vector<Vec2i>(), // point-connectivity
const float frac = 0.95, //fraction of variation to retain
const int kmax = 10); //maximum number of modes to retain
void write(FileStorage &fs) const; //file storage object to write to
void read(const FileNode &node); //file storage node to read from
protected:
void clamp(const float c = 3.0); //clamping factor (or standard dev)
Mat pts2mat(const vector<vector<Point2f>> &p); //points to vectorise
//procrustes aligned shapes/colimn
Mat procrustes(const Mat &X, //shapes to align
const int itol = 100, //maximum number of iterations
const float ftol = 1e-6); //convergence tolerance
//rigid basis (2n*4) CV_32F
Mat calc_rigid_basis(const Mat &X); //procrustes algned shapes/column
};
表示人脸形状变化的模型被编码在子空间V和方差向量e中。参数向量p保存着一个关于该模型形状的编码。连通矩阵C用于可视化面部形状的实例中。
calc_params函数将一个点集投影到貌似脸形(face space)的空间中,对每个投影的点有选择地给出置信权重。
calc_shape函数通过解码用在人脸模型的参数向量p(通过V和e编码)来生成点集。
train函数从脸形数据集中学习编码模型,这些脸形有相同的点数。frac、 kmax是训练过程的参数,根据数据来设置。
下面看看shape_model类的实现:
- Procrustes 分析
为了建立脸形的形变模型,首先必须删除原始标注数据中适用于全局性运行的部分。在二维几何模型中,常用相似变换来表示刚性运动,相似变换包括伸缩、平面内旋转、变换。从点集删除全局刚性运动的过程叫做Procrustes分析。
在数学上,Procrustes分析的目的是要同时找到一个标准形状和每个数据实例的相似变换,并让这些数据实例与标准形状对齐。对齐程度的度量使用最小平方距离。
Procrustes分析的实现:
#define