非刚性人脸跟踪(6)

2019-09-01 18:37

const float var=1.0//标记误差的方差 const float lambda==1e-6;//正则化权重 const float mu_init=1e-3;//初始化步长大小 const int nsamples=1000;//样本的数量 const bool visi=false);//可视化训练过程。 vector//最高响应的位置/图像中特征 calc_peaks(

const Mat &im,//用来进行特征检测的图像

const vector&points,//当前形状的估计 const Size ssize=Size(21,21);//搜索窗口的大小 ...... };

reference形状以交错的(x,y)坐标的形式存储,通常归一化了训练图像的尺度和旋转,并且对随后的测试图像应用同样的操作。在patch_models::train函数中,首先对于给定的图像利用patch_model::calc_simil函数计算reference形状和标记形状的相似性,这个和在shape_model::procrustes函数中解决了类似的问题,尽管只是对于一对形状。因为旋转和尺度交叉出现在面部特征中是非常普遍的,所以图像的标准化过程仅需要调整这种相似变换来说明图像中每一个特征的中心和标准化图像块的中心。在patch_models::train函数中,实现如下:

Mat S=this->calc_simil(pt),A(2,3,CV_32F);

A.fl(0,0) = S.fl(0,0); A.fl(0,1) = S.fl(0,1); A.fl(1,0) = S.fl(1,0); A.fl(1,1) = S.fl(1,1);

A.fl(0,2) = pt.fl(2*i ) - (A.fl(0,0)*(wsize.width -1)/2 + A.fl(0,1)*(wsize.height-1)/2);

A.fl(1,2) = pt.fl(2*i+1) – (A.fl(1,0)*(wsize.width -1)/2 + A.fl(1,1)*(wsize.height-1)/2);

Mat I; warpAffine(im,I,A,wsize,INTER_LINEAR+WARP_INVERSE_MAP);

这里,wsize是标准化训练图像的总的大小,是块的大小和搜索区域大小的和。就像刚才提到的,从参考形状(reference)到标记形状(pt)的相似变换的左上2*2大小的块,他们相对于变换的尺度和旋转成分,存储在仿射变换中,传递给OpenCV的warpAffine函数。仿射变换矩阵A的最后一列是对第i个面部特征位置进行的调整(即标准化的平移)。最后,cv::warpAffine采用默认设置将图像转换到参考帧。因为对于转换参考形状到空间图像标记Pt,计算类似的转换,WARP_INVERSE_MAP标志位需要设置以确保函数在期望的方向上应用仿射变换。具体地类似的过程在patch_models::cal_peak函数中执行,该函数带有一个额外的步长,计算的在图像帧中,参考形状和当前形状之间的相似转换被重新应用到未标准化的检测到的人脸特征,在图像中置于他们合适的位置:

vector

patch_models::calc_peaks(const Mat &im, const vector&points,const Size ssize)

{

int n=points.size();assert(n==int(patches.size())); Mat pt=Mat(points).reshape(1,2*n); Mat S=this->calc_simil(pt); Mat Si=this->inv_simil(S);

vector pts=this->apply_simil(Si,points); for(int i = 0; i < n; i++){

Size wsize = ssize + patches[i].patch_size(); Mat A(2,3,CV_32F),I;

A.fl(0,0) = S.fl(0,0); A.fl(0,1) = S.fl(0,1); A.fl(1,0) = S.fl(1,0); A.fl(1,1) = S.fl(1,1);

A.fl(0,2) = pt.fl(2*i ) - (A.fl(0,0)*(wsize.width -1)/2 + A.fl(0,1)*(wsize.height-1)/2);

A.fl(1,2) = pt.fl(2*i+1) – (A.fl(1,0)*(wsize.width -1)/2 + A.fl(1,1)*(wsize.height-1)/2);

warpAffine(im,I,A,wsize,INTER_LINEAR+WARP_INVERSE_MAP); Mat R = patches[i].calc_response(I,false);

Point maxLoc; minMaxLoc(R,0,0,0,&maxLoc);

pts[i] = Point2f(pts[i].x + maxLoc.x - 0.5*ssize.width, pts[i].y + maxLoc.y - 0.5*ssize.height); }return this->apply_simil(S,pts);

在先前的代码中第一个要强调的代码片段是,前向和相反的类似转换被计算。这里需要反向转换的理由是对于每一个特征响应的峰值可以根据当前形状估计的标准化位置来调整。在应用类似的转换来将面部特征位置的新估计置于图像帧之前必须通过patch_models::apply_simil函数执行。

训练和可视化

用标记的数据训练块模型的例程可以在train_patch_model.cpp中找到,命令行参数argv[1]包含有标记数据的路径,训练通过导入数据到内存开始并且移除不完整的样本: ft_data data = load_ft(argv[1]); data.rm_incomplete_samples();

在patch_models类中用作参考形状最简单的选择是训练集的平均形状,尺度化到了期望的大小。假定形状模型先前已经训练,则参考模型首先通过导入存储在argv[2]中的形状模型来计算。

shape_model smodel = load_ft(argv[2]); 接下来计算尺度化和中心化的平均形状: smodel.p = Scalar::all(0.0);

smodel.p.fl(0) = calc_scale(smodel.V.col(0),width); vector r = smodel.calc_shape();

calc_scale函数计算尺度因子用来将平均形状转(即,shape_model::V的第一列)换到一个带有width宽度的形状。一但参考形状r被定义,训练一组块模型可以使用一个函数调用来完成:

patch_models pmodel; pmodel.train(data,r,Size(psize,psize),Size(ssize ,ssize));

参数width,psize和ssize的最佳选择依赖于应用。然而,一般分别的默认值:100,11,和11可以给出合理的结果。

尽管训练过程相当简单,但它任然要化一段时间来完成。在最优算法中,依赖于人脸特征的数量,块的大小,和随机样本的数量,训练过程可能要花费几分钟到超过一个小时。然而,因为每一个块的训练集可以独立于其他执行,这个过程本质上可以通过多核处理器或机器并行训练来加速处理。

一旦训练完成,visualize_patch_model.cpp中的程序可以用来可视化结果块模型。当使用visualize_shape_model.cpp程序时,这里的目的是可视化的观察来验证训练过程是否有错。程序产生由所有块模型组成的合成图像,patch_model::P,在参考形状中,每一个模型居中到他们各自的特征位置,patch_models::reference,并且在块(当前索引激活)的周围显示一个边界矩形。cv::waitKey()函数用来获取用户输入来选择激活块的索引并且终止程序。下面的图像展示了三个合成块图像的例子,用来块模型的学习,块模型带有变化空间支持。尽管使用同样的训练集,修改块模式的空间支持从本质上表现出块模型结构的变化。用这样的方式可视化观察结果,可以提供如果修改训练过程参数的直觉,或者甚至训练过程本身,为了对于特殊的应用得到最优化的结果。

人脸检测和初始化

迄今为止描述的人脸跟踪方法都是假定图像中的面部特征的位置是当前帧的一个合理的估计。尽管在人脸跟踪期间,当人脸运动在帧与帧之间变化较小时,这种假设是合理的,但是我们任然面对如何初始化序列的第一帧图像中的模型。对于这种情况,一个明显的选择是使用OpenCV内置的级联检测器来中找到人脸。然而,检测到的边界框中模型的替代将依赖于用来跟踪而选择的面部特征。迄今为止,在这一章我们一直遵循数据驱动的范例,一个简

单的解决方法是学习人脸检测的边界框和人脸特征之间的几何关系。

face_detector类的实现恰好解决这个问题。下面是该类声明片段,来强调它的基本功能:

class face_detector//用来初始化的人脸检测器 {

public:

string detector_fnmae;//包括级联分类器的文件 Vec3f detector_offset;//检测中心偏移 Mat reference detector;//参考形状

CascadeClassifier detector;//人脸检测器 vector//描述检测到的人脸的点集 detect(const Mat &im,//包含人脸图像 const float scaleFactor=1.1;//尺度增额 const int minNeigbbours=2;//最小相邻大小

const Size minSize=Size(30,30);//最小的窗口大小 .... }

这个类含有四个成员变量:detector_fname是cv:CascadeClassifier调用的目标类型的路径。 detector_offset是从检测边界框到人脸位置和尺度的偏移。reference是一个参考形状,它放置在边界框内。detector是一个人脸检测器。用于一个人脸跟踪系统的基本函数是face_dector::detest,该函数以一个图像作为输入,带有cv::CascadeClassifier类的标准可选项,并且返回一个图像中人脸位置的大约估计。它的实现如下:

Mat gray;//转换图像到灰度图像并且直方图均衡化 if(im.chanenes()==1) gray=im;

else cvtColor(im,gray,CV_RGB2GRAY);

Mat eqIm;

equalizeHist(gray,eqIm);

vectorfaces;//检测图像中最大的人脸

dector.detectMultiScale(eqIm,faces,scaleFactor,minNeignbours,0|CV_HAAR_FIND_BIGGEST_OBJECT|CV_HAAR_SCALE_IMAGE,minSize); if(face.size()<1){return vector();} Rect R=faces[0];

Vec3f scale=detector_offset*R.width; int n=reference.rows/2; vecotr p(n);

for(int i=0;i

p[i].x=scale[2]*reference.fl(2*i)+R.x+0.5*R.width+scale[0]; p[i].y=scale[2]*reference.fl(2*i+1)+R.y+0.5*R.height+scale[1]; }

return p;

用通常的方法检测图像中的人脸,只是设置了CV_HAAR_FIND_BIGGEST_OBJECT标志位为了能够在图像中跟踪最主要的人脸。要强调的代码是:参考形状根据检测到的人脸边界框置于图像中。detector_offset成员变量由三个成分组成:来至检测的边界框中心的人脸中心的(x,y)坐标偏移,和一个尺度化因子,该因子重置参考形状的大小以最好的适合图像中的人脸。这三个成分是边界框宽度的线性函数。

边界框的宽度和dectector_offset变量之间的线性关系通过学习标记数据集获得,实现与face_detector::train函数中。学习过程通过导入训练数据到内存器开始,并且同时指定参考形状:

dectector.load(fname.c_str()); detectir_fname=fname; reference=ref.clone();

与patch_models类中的参考形状一样,参考形状的一个方便的选择是归一化的数据集的平均人脸形状。那么cv::CascadeClassifier被应用到数据集中的每一个图像(并且可选的图像的镜像部分)并且检查结果检测来确保足够的标记点位于检测到的边界框的内部(参考本部分结尾的图形),以防止学习错误的检测。

if(this->enough_bounded_points(pt,faces[0],frace)) {

Point2f center=this->center_of_mass(pt); float w=faces[0].width;

xoffset.push_back((center.x-(faces[0].x+0.5*faces[0].width))/w); yoffset.push_back((center.y -(faces[0].y+0.5*faces[0].height))/w); zoffset.push_back(this->calc_scale(pt)/w); } }

如果位于边界框内的标记点超过标记点一个百分数值frac,那么对于那副图像的边界框和偏移参数之间的线性关系将作为一个新的条目添加到STL的vector类对象中。这里,face_detector::center_of_mass函数为那个图像计算标记点集块的中心并且face_detector::calc_scale函数计算从参考形状到中心化标记形状的变换的尺度因子。一旦处理完所有的图像,detector_offset变量被设置为所有指定图像偏移的中间值。 Mat X=Mat(xoffset),Xsort,Y=Mat(yoffset),Ysort,Z=Mat(zoffset),Zsort;

cv::sort(X,Xsort,CV_SORT_EVERY_COLUMN|CV_SORT_ASCENDING); int nx = Xsort.rows;

cv::sort(Y,Ysort,CV_SORT_EVERY_COLUMN|CV_SORT_ASCENDING); int ny = Ysort.rows;

cv::sort(Z,Zsort,CV_SORT_EVERY_COLUMN|CV_SORT_ASCENDING); int nz = Zsort.rows; detector_offset =

Vec3f(Xsort.fl(nx/2),Ysort.fl(ny/2),Zsort.fl(nz/2));


非刚性人脸跟踪(6).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:东北师范大学《算法分析与设计》18秋在线作业1

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: