源地址:http://www.thinkface.cn/thread-3704-1-6.html
人脸对齐包括两个部分,分别为训练部分和测试部分。所有的代码基于opencv2.0.
(一)训练阶段
Step1:样本的准备:
本文采用了IMM人脸数据库作为训练集,样本大小为640x480大小的彩色人脸图片,并手工对每个样本进行手工特征点标注。
Step2:样本预处理:(包括光照、尺度归一化等)
先进行尺度归一化操作,步骤如下:
1)从训练样本中选取一个比较正的人脸最为参考人脸。
2)将所有的训练样本对齐参考人脸,采用opencv中的 函数进行仿射变换(包括人脸图片和人脸形状的变换),最终扣取人脸区域并保存为100x100的灰度人脸图像。
然后进行光照处理:
对训练样本进行直方图均衡化操作,减少光照对人脸图片的影响。
计算平均人脸形状:
对所有训练样本的人类形状进行累加,计算平均人脸形状。
Step3:进行二级形状回归训练
ESR算法封装在CESRMethod类中,提供了训练接口void ESRMethod::train(****),如下。
void ESRMethod::train(****){
1> 一些基础的变量赋值与处理。
2> 赋值多个初始人脸形状。(用于正确算法的稳定性。例如现在有10个样本,对每个样本赋值10个初始人脸形状,则变成了100个样本)。 对每个训练样本赋值50个初始人脸形状。初始形状是通过平均人脸进行旋转、收缩、平移的方式的到的。
3> 进行一级形状回归,一级形状回归包含在FernCasade类中train函数中。
}
void FernCascade::train(****){
1>特征索引的建立
在人脸区域随机参数P个点,以平均人脸作为参考,将全局坐标转换成局部坐标,形成特征索引。
2>根据训练样本当前形状还原人脸形状的真实坐标(即68个特征点的坐标),通过remap函数获取68个特征点的像素值。
3>进行二级形状回归,封装在Fern类的train函数中。
4>更新每个训练样本的人脸形状。
}
void Fern::train(****){
1> 采用随机特征选择方法,从P个坐标点中选择出F对坐标点。根据选出的F对特征点,计算所有训练样本的F对特征点的像素差值,并将其作为一个特征。
2> 然后计算平均特征。
3> 根据平均特征,对样本进行归类,总共分为2^F类,计算没类中所有样本的平均人脸调整量,
4> 循环1>-3> N次,选择收敛最快的那一次保存其人脸调整量。
}
通过二级形状回归后,得到T个弱回归量 ,并将其保存在文件中。
(二)测试阶段
Step1:加载模型文件。
Step2:图片预处理阶段
打开目标人脸图像,将其转换成灰度图片。采用opencv自带的人脸检测函数找出图片中的人脸区域,并将其扣取出来,然后进行直方图均衡化操作,减少光照的影响。同时,将平均人脸形状作为目标图片的初始人脸形状。
Step3:人脸对齐阶段
采用如下三个函数进行人脸对齐
ESRMethod::test(const cv::Mat1b &image,const cv::Mat1f &shape,int t);
FernCascade::test(const cv::Mat1b &image,const cv::Mat1f &shape);
包括如下功能:
根据当前的人脸形状和形状特征索引,获取人脸特征。
更新人脸形状。
Fern::test(const cv::Mat1b &image,const cv::Mat1f &shape,const cv::Mat1f &xyloc,cv::Mat1f &dshape);
包括如下功能:
根据当前的特征,将其进行归类,并提前类中的形状调整量。
进行多次迭代后,输出对齐的人脸形状。