版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、:非刚性(n xn)人脸跟踪非刚性人脸跟踪,是视频流的每一帧的面部特征的准密度的估计,也是一个困难的问题,因为(yn wi)现代方法从很多相关领域借鉴了思想,相关领域包括:计算机视觉,计算几何学,机器学习,和图像处理。这里的非刚性涉及到面部特征在面部表情交叉式的变化的相关距离。并且区别于人脸检测和跟踪,人机检测和跟踪的目的仅是在每一帧图像中找到人脸的位置,而不是面部特征的结构。非刚性人脸跟踪是一个流行的研究热点,已经进行了20年之久,但是仅在不久之前,各种各样的方法开始变的足够的鲁棒性,并且处理足够快,这奠定了可能商业化应用的基础。尽管商业级人脸跟踪可能高度复杂并且甚至对经验丰富的计算机视觉科
2、学家提出了一个挑战。在这一章我们将看到一个人脸跟踪器,在约束(yush)的环境下运行的相当的好,该环境的设计使用了适中的数学工具和OpenCV大量的功能,例如线性代数,图像处理和可视化。这是特征的情况下,当被跟踪的人事先已知并且用图像作为训练数据,标记注释是可用的。今后描述的技术将作为一个有用的起点和进一步追求更复杂人脸跟踪系统的向导。本章概要如下:复习:这个部分涉及到简短的人脸跟踪历史。有用的东西:这部分概述了本章使用的普通结构和规矩。它包括面向对象设计,数据存储和表示以及数据收集和注释的工具。几何限制:这一部分描述表面几何和它的变化是如何从学习训练数据和在跟踪中如何利用来限制解决的。这涉及
3、到把人脸模型作为一个线性形状模型和全面的转换是如何统一到它的表现的。人脸特征检测器:这部分描述怎样学习面部特征的外观,以用来在将要跟踪的人脸图像中检测他们。人脸检测和初始化:这一步讲述如何使用人脸建仓期来初始化跟踪过程。人脸跟踪:这一部分通过图像队列的处理来组合先前描述的所有成分到一个跟踪系统。讨论了一个好的系统能够运行的环境。下面的块状图表阐述了系统不同成分之间的关系:注释(zhsh):注意本章使用的方法遵循一个数据驱动的范例,所用使用的模型都是从数据学得,而不是基于一定的规则环境而手工设计的。本身,系统的每个成分将要包含两个要素:训练(xnlin)和测试。训练是从数据中建立模型,测试将这些
4、模型应用到未知的数据。回顾(hug):非刚性人脸跟踪首先流行于的90年代中期,伴随着 Cootes 和 Taylor的ASM的出现。从那时起,大量的研究投身于解决基于ASM提出的原始方法的改进的类人脸跟踪的困难问题。第一个里程碑是在2001年,Coote和Taylor将ASM扩展到AAM。这个方法后来被正式化了,虽然在世纪中叶Baker和学院进行了图像扭曲的原则性处理。沿着这些方向的另外一向工作是Blanz和Vetter进行的3DMM。不光模拟图像纹理,反对像ASM中的沿着轮廓的边缘,而且进一步通过使用从激光扫描人脸学习的高密度3D数据来表示模型。从中期到20世纪末,人脸跟踪研究的焦点从如何人
5、脸参数化转向了如何跟踪算法任务的提出和最优化。来至机器学习社区的各种各种的技术以不同的成功程度被应用到。自从世纪交替时,焦点再一次转移,这次转向了联合参数和目标设计策略,即保证全局的解决。尽管不断的强烈的研究进入到人脸跟踪,然而相比较有很少的商业应用使用到它。尽管对于许多一般方法有许多可以免费利用源代码包,对嗜好者和热情者举起(发扬)仍然是一个滞后。尽管如此,在过去的两年,在公众领域的人脸跟踪的潜在使用兴趣的复兴,并且商业级的产品也开始出现。有用(yu yn)的东西在投入人脸跟踪这个复杂的事物之前,许多标记任务和约定(yudng)通常所有的人脸跟踪方法必须首先被介绍。这部分剩下的是处理这些问题
6、。一个感兴趣的读者可能希望首先跳过这个部分的阅读并且直接到几何限制部分。面向对象设计(shj)正如人脸检测和人脸识别,计划性地,人脸跟踪有两个要素组成:数据和算法。算法通常通过参考存储数据(即离线)作向导来对输入的数据(即在线)执行某中操作。例如,一个将算法和他们依靠的数据连接在一起的面向对象设计是一个方便的设计选择。在OpenCV v2.x,一个方便的XML/YAML文件存储类被引进,极大的简化了为算法使用组织离线数据的任务。为了利用特征,本章描述的所有类将实现读、写序列化功能。用一个假象的类foo作为一个例子,如下:#include using namesapce cv;class foo
7、 public: Mat a;type_b b;void write(FileStorgae &fs) const assert(fs.isOpened();fs”“”a”a”b”ba,node“b”b;这里,Mat是OpenCV的矩阵类,type_b是一个用户定义的类,对它同样定义了序列化的功能。I/O函数read和writer现实序列化。FileStorage类支持两个类型数据结构的序列化。为了简化,本章所有的类将只利用映射,即每一个存储变量创造一个类型为FileNode:Map类型的FileNode对象。这里需要唯一的键分配到每一个元素。尽管这个键的选择是随意的,因为前后一致,我们将使用
8、变量的名字作为标签。像先前阐述的代码小片段,read和write功能呈现一个特别简单的形式,通过使用流操作符()来插入数据到FileStorage对象和从FileStorage对象中提取数据。大部分OpenCV类有read和write功能的实现,允许他们轻松的处理包含的存储的数据。除定义序列化功能之外,我们还必须在FileStorage类中为序列化定义两个附加的功能来工作,如下:void writer(FileStorage &fs,const string &,const foo&x) x.wirter(fs);void read(const FileNode &node,foo& x,co
9、nst foo&default) if(node.empty() x=d;else x.read(node);同时本部分描述的所有类中,这两个函数的功能是保持一样的,他们模版化和定义在ft.hpp头文件内,可以在附属于本章的源代码中找到。最后,为了简单地保存(bocn)和导入用户定义的类,利用序列化功能,模版化的函数同样在头文件中实现,如下:template T load_ft(const char *fname)T x;FileStorage f(fname,FileStorage:READ);f“ft object”x,f.release();return x;template void
10、save_ft(const char *fname,const T&x) FileStorage f(fname,FileStorage:WRITE);f”ft object”x;f.release();注意和对象一起的标签总是一样的(即,ft object)。采用这些定义(dngy)的函数,保存和导入对象数据是一个轻松的过程。通过下面的例子展示:#include “opencv_hotshots/ft/ft.hpp”#incldue “foo.hpp”int main().foo A;save_ft(“fool.xml”,A);foo B=load_ft(“foo.xml”);.注意(zh
11、y).xm扩展名表示采用XML_格式化数据文件,对于任何其他的扩展名默认采用YAML格式。数据收集:图像(t xin)和视频的注释现在的人脸跟踪技术几乎完全是数据驱动的,即,算法通常依靠人脸面部特征外观和从一系列例子得到的他们的相对位置的几何依赖性形成的模型,来检测图像中面部特征的位置。更大的样本集,算法表现更好的鲁棒性,因为他们能够更好的意识到人脸可以表现的变化性的全局性。因此,建立人脸跟踪算法的第一步是创建一个图像/视频(shpn)注释工具,用户可以通过该工具指定每一个样本图像中希望得到的面部特征的位置。训练(xnlin)数据类型用来训练人脸跟踪算法的数据一般由四个成分组成:图像:这个成分
12、是一个包含全部人脸的图像集(静的图像或者视频帧)。为了得到最好的效果,这个集应当详细说明环境的类型(即,统一性,光照,到相机的距离,捕捉设备,以及其他),跟踪器过会在该环境中展开进行。集合中的人脸呈现我们应用所期望的头部姿势和面部表情也是重要的。注释:这个成分调整每一个图像的手动标记,以使相应的每一个人脸特征被跟踪。更多的人脸特征经常导致更好的鲁棒性的跟踪器,因为跟踪算法可以是使用这些度量来加固彼此。普通的跟踪算法在计算上的花费典型地与人脸特征的数量成线性关系。3、对称目录:这个成分有每个面部特征点的索引,这个成分定义 了它的双边地对称特征。这可以用来镜像训练图像,有效的双倍训练集大小和使数据
13、沿着y轴对称。4、连通性目录:这个成分包含一个注释对的索引集,用来定义面部特征的语义的解释。这些连接多可视化跟踪结果是有用的。下面的图像是四个成分可视化的一个展示,从左到右分别是,原始图像,面部特征注释,彩色编码双边对称点,镜像图像,和注释和人脸特征联通。为了更方便地使用这些数据,用一个类来实现存储和访问的功能是非常有用的。OpenCV的ml模块中的CvMLData类处理一般数据的功能,通常用于机器学习问题。然而,它缺少访问人脸跟踪数据的功能。同样地,在这章,我们将使用ft_data类,该类声明在ft_data.hpp头文件中,专门为记住人脸跟踪数据的特性而设计的。所有的数据成员定义为类的pu
14、blic成员,如下:class ft_datapublic:vector symmetry;vector connections;vector imnames;vectorvector points;Vec2i和Point2f类型是OpenCV的类,分别为两个整形的容器和2D浮点型坐标。对称的容器拥有和人脸特征点(同样地是用户定义)一样多的成分。每一个connections定义为连通的面部表情(bioqng)的基于0的索引对(以0开始)。因为训练集可能很大,而不是直接的存储图像,这个类通过imnames成员变量来存储每一个图像的文件名(注意为了是文件名有效,我们需要将图像放在同样的相对位置)。
15、最终,对于每一个训练的图像,面部特征位置的集合被作为一个浮点型坐标的容器存储,用points成员变量表示。ft_data类实现了很多便利的方法用来访问(fngwn)数据。为了在数据集中访问每一个图像,get_image函数通过指定的索引idx导入图像,并且可选择地围绕y轴进行镜像图像。如下:Mat ft_data:get_image(const int idx,const int flag) /const int idx;/图像(t xin)的索引用来从文件导入 /const int flag;/0=gray,1=gray+flip,2=rgb,3=rgb+flip;/flip镜像翻转 Mat
16、 img,im;if(flag2) img=imread(imnamesidx,0);esle img=imread(imnamesidx,1);if(flag%2!=0) flip(img,im,1);else im=img;return im;将(0,1)标志传递给OpenCV的imread函数用来指按3通道彩色图像的形式的导入还是按单通道灰色图像导入。标志位传递给OpenCV的flip函数用来指定绕在y轴进行镜像。为了用特殊的索引访问对应与图像的点集,get_points函数一个存储浮点型坐标的容器,带有可选的镜像索引,如下:ft_data:get_points(cosnt int id
17、x,const bool flipped) /const int idx相应点的图像索引 /const bool flipped;是否将图像绕在Y轴进行旋转 if(idx=(int)imnames.size()return vector();/如果访问的图像不存在,返回空的容器vector p=pontsidx;if(flipped)Mat im=this-get_image(idx,0);int n=p.size();vector q(n);/初始化N个空的对象for(int i=0;in;i+)qi.x=im.cols-1-psymmertyi.x;/n为点的个数。qi.y=psymmet
18、ryi.y;return q;return p;注意当指定了镜像标记时,这个函数调用get_image函数。这需要判断图像的宽度,以用来纠正镜像人脸特征(tzhng)坐标。一个更有效的设计是传递图像的宽度作为一般变量。最后,在这个函数中symmerty成员变量的用法被阐述。一个特殊索引的镜像特征位置仅仅是symmetry变量的索引指定的位置和它的x坐标的翻转和偏移。如果指定的索引在数据集中不存在,get_image和get_points函数均返回空的结构体。同样可能的是,并不是集合中的所有图像都被注释。人脸跟踪算法可以设计来处理缺失的数据,然而,这些实现通常相当的复杂(fz)并且超出了本章的范
19、围。ft_data函数实现了从集合中移除哪些没有相应注释的样本的功能,如下:void ft_data:rm_incomplete_samples()/rm =rremove int n=ponts0.size(),N=ponts.size();for(int i=0;iN;i+) n=max(n,int (pointsi.size();/n取图像(t xin)集中点集最大的for(int i=0;iint(points.size();i+) if(int(pointsi.size()!=n) points.erase(points.begin()+i);imnames.erase(imname
20、s.begin()+i);i-;else int j=0;for(;jn;j+) if(pointsij.x=0|(pointsij.y=0) break;if(jn)points.erase(points.begin()+i);imnames.erase(imnames.begin()+i);i-;简单的例子是,大多数量的注释(zhsh)被假定为是权威的样本。拥有点集少于许多数量的点的数据实例将采用容器的erase函数将其从集合中移除。同时也注意到带有(x,y)坐标小于0的点被认为在其相应的图像上缺失(可能是由于遮挡,差的可见度,或者模糊性)。ft_data类实现序列化函数read和writ
21、e,并且因此(ync)可以简单地存储和导入。例如,保存一个数据集的简单做法如下:ft_data D;/示例(shl)数据结构./填充数据save_ft(“mydata.xml”,D);/保存数据为了可视化数据集,ft_data函数实现了一些画图功能。他们的用法在visualize_annotations.cpp文件中阐述。这个程序导入用命令行指定的文件中的注释数据,移除不完全的样本,并且显示带有相应注释的、对称,连接叠加的训练图像。OpenCv的highgui模块的一些显著的特征在这里示范。尽管相当基本并且不适合复杂用户接口。OpenCV的highgui模块的功能在计算机视觉应用中对于导入和可
22、视化数据和算法输出非常有用。与其他的计算机视觉库相比,这可能是Opencv的品质。注释工具:为了用本章的代码产生注释,一个基本的注释工具可以在annotate.cpp文件中找到。这工具用视频流或者文件或者相机作为输入。使用这个工具的程序的四个步骤如下列出:捕捉图像:在这第一步中,图像流显示在屏幕上,用户通过按S键选择图像用来注释。用来注释的最好的特征集是哪些最大的跨度面部行为的范围,这些面部行为是人脸跟踪系统需要跟踪的。注释第一个图像:在第二步中,将第一阶段捕获,选择的图像提供给用户。然后用户接着点击图像上需要跟踪的附属于面部特征的位置。注释连通性:在第三步,为了更好的可视化一个模型,需要定义
23、点的连通性结构。这里,提供给用户先前阶段同样的图像,现在的任务是点击一些点对集,一个接一个的,用来为人脸模型建立连通结构。注释对称性:在这一步,任然使用同样的图像,用户选择展现双边对称性的点对。注释剩下的图像:在最后一步,这里的过程类似与步骤2,除此之外用户可以浏览图像集和异步地注释他们。有兴趣的读者可能想通过改善他们的有用性来改善这些工具,或者甚至整合一个增加的学习过程,凭借一个跟踪模型的更新,该更新通过每个增加的注释的图像和随后的用来初始化的这些点来减少注释的负担。尽管一些公开地可以利用的数据(shj)集可以为本章开发的代码利用。(例如接下来的描述)。注释工具可以被用来建立指定人脸跟踪模型
24、,通常该模型比一般的,单独的人,相对应的人执行更好的结果。预注释(zhsh)数据(MUCT数据集)开发人脸跟踪系统的一个障碍因素是乏味的和易于出错的手动地注释大量图片集的过程,这些图像带有大量的点。为了为本章接下来的工作的目的减轻这个过程,公开地可以利用(lyng)的MUCT数据集可以通过下面的连接下载: HYPERLINK http:/www/muct. http:/www/muct.数据集由3755个注有67个特征点人脸图像组成。数据集的主题在年龄和种族,和许多不同光照环境和头的姿势情况下捕捉中变化。为了用本章的代码使用MUCT数据集,执行下面的步骤:下载数据集。在这一步,数据集中所用的图
25、像可以通过下载文件muct-a-jpg-v1.tar.gz到muct-e-jpg-v1.tar.ga,并且解压他们来获得。这将产生包含所有图像的新的文件夹。下载注释:在这一步,下载文件包含注释muct-landmarks-v1.tar.gz保存。解压到和先图片的同样的文件夹呀。利用注释工具定义连接和对称:在这一步,来至命令行,发布命令 ./annotate -m $mdir -d $odir,这里$mdir指示MUCT数据集保存的路径文件夹,$ofir指示annotaion.yaml文件夹,包含数据以ft_data对象的形式被写入存储。注释:MUCT数据的使用促进在本章对人脸跟踪代码功能描述有
26、一个快速的入门。几何约束在人脸跟踪,几何引用了预定义点集的空间配置,这些点集对应于人脸上物理连续位置。(例如眼角,鼻尖和眼毛边缘)。这些点的特殊选择是应用依赖的,一些应用需要超过100个点的稠密集,并且其他仅需要一个稀疏选择。然而人脸跟踪算法的的鲁棒性通常伴随着点数目的更加而改善,因为他们分开的测量值可以通过他们相关空间依赖性来增强彼此。例如,知道一个眼角的位置是对于期待鼻子在哪里定位是一个好的指示。然而通过增加点的数目来获得鲁棒性的改善是有限制的,典型地100个点之后性能停滞。而且,增加用来描述人脸的点集带有计算复杂度的线性增加。因此,带有计算负载严格限制的应用可能带有更少的点集进展的更好。
27、同样也有这样的情况,在在线环境下更快的跟踪经常导致更精确的跟踪。这是因为,当帧被抛弃时,两帧之间的增加察觉到的运动,以及用来在每一帧图像上寻找人脸配置的最优算法必须搜索可能的特征点配置的更大的空间。当两个帧之间的位移变大时,这个过程经常失败。总的来说,尽管怎样最好的设计面部特征带你的选择有一个一般的指导方针,为了得到最优的性能,这一章应当专业到应用领域。面部几何通常参数化为两个元素的组成:一个全局(刚性)转换和一般局部(非刚性)变形。全局转换解释为图像中人脸的整体布局,通常允许没有约束的改变(即,人脸可以在图像上的任何地方显示)。这包括每张图像人脸的x,y坐标,面内头部旋转,和图像中人脸的大小
28、(dxio)。另一方面,局部变形解释为面部形状交叉身份之间的不同和表情之间的不同。与全局转换相对照,这些局部变形通常有更多的限制,约束,主要是由于人脸特征的更高地结构化参数。全局转换(zhunhun)是2D坐标 的一般功能,适用于任何类型的对象,然而局部变形是特定对象并且必须从训练集中学习。在这一部分,我们描述面部结构几何模型的构造,因此成为形状模型。取决于应用,它可以捕捉单个个体的表情变化,和交叉不同的人脸形状或者两者的混合。这个模型用shape_model类实现,可以在shape_model.hpp和shape_mode.cpp文件中找到。下面的代码(di m)片段是shape_model
29、类的头的一部分,用来说明它的基本的功能。class shape_model/2d线性模型public:Mat p;/参数矢量k*1 CV_32FMat V;/线性子空间(2n*k) CV_32FMat e;/参数变化(k*1) CV_32FMat C;/连通性(c*2) CV_32S.void calc_params(const vector&pts;/用来计算参数的点const Mat &weight=Mat() /weight/point N*1 CV_32Fconst float c_factor=3.0)/clamping factor夹因素.vector /用参数描述的形状calc_
30、shape();.void train(const vectorvector &p,/N个样本形状const vector &con=vector()/连通性const float frac=0.95;/用来保留的变化的分数const int kmax=10)/用来保留的模型的最大数量.用人脸的形状代表变化的模型用子空间矩阵V和方差e进行编码。参数矢量P存储表示模型的形状的编码。连通性矩阵C同时也存储在这个类,因为它仅术语人脸形状的可视化示例。在这个类中基础兴趣的三个函数是calc_params,calc_shape,和train。calc_params函数投影一个点集到似乎可信的人脸形状的空
31、间。calc_shape函数通过使用人脸模型(用v和e编码)解码参数矢量p来产生一个点集。train函数用人脸形状数据集学习编码模型,每一个模型由同样数量的点组成。参数frac和kmax是训练过程的参数,可以为眼前的数据特化该参数。这个类的功能将在接下来的部分进行详细的描述,那里我们通过Procrustes分析开始,它是用来严格地登记一个点集的方法。接下来通过用通常代表局部变形的线性模型。train_shape_model.cpp和visulize_shape_model.cpp文件中的程序分别的训练和可视化模型。他们的使用(shyng)将在本部分的结束进行概括。Procrustes分析(fn
32、x)为了建立人脸形状的一个变化模型,我们首先必须处理为加工注释的数据(shj)来移除附属于全局刚性的运动的成分。当我们用2D模型化几何时,一个刚性的运动通常代表为一个类似的转换。这包括尺度,面内旋转和平移。下面的图像阐述了在一个类似的转换下的一套允许的动作类型。从一个点集中移除全局刚性运动的过程被成为Procrustes分析.数学上地,Procrusters分析的目的是同时找到一个权威的形状并且类似转换每一个数据实例,用这个权威的形状将他们对齐。这里,对齐的测量是用采用了权威形状的两个转换形状的最小二乘距离。为了完成这个目标,一个重复的过程在shape_model类中实现,如下:#define
33、 fl atMat shape_mode:procruster(交错未加工的数据,按列(作为列)const Mat &X;/const int itol ,/尝试迭代的最大次数const float ftol)/收敛公差 int N=X.cols,n=X.rows/2;Mat Co,P=X.clone();/复制for(int i=0;iN;i+)Mat p=P.col(i);/第i个形状float mx=0,my=0;/计算块的中心for(int j=0;jn;j+)/分别对x和ymx+=p.fl(2*j);my+=p.fl(2*j+1);mx/=n;my/=n;for(int j=0;jn
34、;j+)/移除块的中心(zhngxn) p.fl(2*j)-=mx;p.fl(2*j+1)-=my;for(int iter=0;iter0) if(norm(C,Co)ftol) break;/收敛?Co=C.clone();/记住当前的估计for(int i=0;irot_scale_align(P.col(i),C);for(int j=0;jn;j+)/应用类似的转换 float x=P.fl(2*j,i),y=P.fl(2*j+1,i); P.fl(2*j,i)=R.fl(0,0)*x+R.fl(0,1)*y; P.fl(2*j+1,i)=R.fl(1,0)*x+R.fl(1,1)*
35、y;return P;/返回procruste对齐的形状这个算法开始通过每一个形状示例块的中心,接着通过一个迭代处理,即交替的计算权威的形状,因为所有图像的归一化均值,并且旋转和尺度化到最佳匹配的权威形状。估计的权威形状的标准化步骤需要固定尺度问题和防止将所有的形状缩小到0.这个尺度的选择是随意的,这里精选来迫使权威形状矢量C的长度到1.0,因为这个OpenCV的normalize函数的默认行为。计算面内旋转和尺度,最好通过下面的rot_scale_align函数使每一个形状的示例和当前估计的权威形状相一致。:Mat shape_model:rot_scale_align(cosnt Mat
36、&src,/x1;y1;,xn;yn原形状示例const Mat &dst/目的形状/构造(guzo)线性系统int n=src.rows/2;float 1=0,b=0,d=0;for(int i=0;in;i+) d+=src.fl(2*i)*src.fl(2*i)+src.fl(2*i+1)*src.fl(2*i+1);a+= src.fl(2*i)*dst.fl(2*i )+src.fl(2*i+1)*dst.fl(2*i+1);b+= src.fl(2*i)*dst.fl(2*i+1)-src.fl(2*i+1)*dst.fl(2*i );a/=d;b/=d;/解决(jiju)线性系
37、统return (Mat_float(2,2)a,-b,b,a);这个函数最小化下面的旋转和权威形状的不同(b tn)的最小二乘。数学上可以表示如下:这里最小二乘问题的解决采用闭合形式的解决,在下面的图像等式的右手边。注意而不是用来解决尺度和面内旋转的,在尺度化2D选择矩阵中他们是非线性的关系(尺度和面内选择),我们解决变量(a,b)。这个变量与尺度和旋转矩阵相关,如下:Procureste对原始注释形状数据分析的可视化效果在下面的图像中阐述。每一个面部特征用唯一的颜色显示。转换标准化之后,人脸的结构开始显现出来,这里人脸特征簇的位置围绕他们均值的位置。迭代尺度和旋转标准化过程之后,特征簇变的
38、更加紧凑并且他们的分布变的由面部变形导致的变化更具有代表性。最后一点是重要的,因为这些变形我们将在接下来的部分尝试模型化。因此,Procruster分析的角色可以被认为是对原始数据的操作,这个操作将得到更好的人脸局部变形模型用来学习。线性形状(xngzhun)模型面部变形模型的目的是找到一个紧凑的参数化代表,即人脸的形状在交叉身份和表情之间是怎么样变化的。采用不同复杂度水平,有很多方法可以达到(d do)这个目的。这些方法中最简单的是使用一个面部几何的线性表示。尽管它简单,特别地,当数据集中的人脸大部分是前向姿势时,它已经展示了精确地捕获面部变形的空间。它与它的非线性部分相比还有个优点是推断它
39、表示的参数是一个非常简单和廉价的操作。这在跟踪期间,通过配置它来约束搜索过程是很重要的。线性地模型化面部形状的主要思想在下面的图像阐述。这里,一个人脸形状,它有N个人脸特征组成,在2N维空间模型化为一个单点。线性模型化的目标是找到嵌入在这个2N维空间的低维超平面,所有人脸形状的点都位于2N维空间(即图像中绿色的点)。因为这个超平面仅跨度完整2N维空间的一个子集,它通常被称为子空间。子空间维数越低,人脸表示更加紧凑并且约束 更加强(jiqing),这个约束强加于跟踪过程。这经常导致鲁棒性更高的跟踪。然而,子空间维度的选择上要注意,以使有足够的容量张成所有人脸空间,但在张成的空间里又没有太多的非人
40、脸形状(即图像中红色的点)。当从单个人模型化数据时,这应当被标识。获得人脸变化性的子空间通常比模式化多个身份有更高的紧凑性。这就是为什么指定人跟踪器的执行效果要比一般人好。寻找最低维子空间(张成一个数据(shj)集)的过程成为主成份分析(PCA)。OpenCV实现了计算PCA的类,然而,它需要预先指定保留的子空间维数。因为这往往(wngwng)是很难确定的先验,常见的启发式是基于它所占的总的变化的分数比例来选择它。在shape_model:train函数中,PCA的实现如下:SVD svd(dY*dY.t();int m=min(min(kmax,N-1),n-1);float vsum=0;
41、for(int i=0;im;i+)vsum+=svd.w.fl(i);float v=0;int k=0;for(k=0;k=frac)k+;break;if(km) k=m;Mat D=svd.u(Rect(0,0,k,2*n);这里,dy变量的每一列表示减去均值的Procrustes对齐形状。因此,奇异值分解SVD有效的应用到形状数据的协方差矩阵(即,dY.t()*dY)。OpenCV的SVD类的w成员存储着数据变化性的主要方向的变量,从最大到最小排序。一个选择子空间维数的普通方法是选择保存数据总能量分数frac的方向最小集(即占总能量的比例为frac),这是通过svd.w.记录表示的,
42、因为这些(zhxi)记录是从最大的到最小的排序的,它充分地用来评估子空间,通过用变化性方向的最大值k来评估能量。他们自己的方向存储在SVD类的u成员内。svd.w和svd.u成分一般分别被成为特征谱和特征矢量。这两个成分的可视化如下图表:注释(zhsh):注意(zh y)特征谱的迅速下降表明,包含在数据中的主要变化可以用低维子空间进行模型化。局部(jb)全局的组合表示图像帧中形状是通过局部变形和全局转换组合产生的。数学上,这个参数化是不确定的,因为这种转变的组成导致一个非线性的函数,该函数没有闭合形式的解。绕过这个问题的一个普通的方法是把全局转换模型为一个线性子空间并且把它添加到变形子空间。为
43、了得到一个固定的形状,可以用一个子空间模式化一个类似的转换。如下:在shape_model类中,这个子空间的 通过calc_rigid_basis函数产生,来至产生这个子空间的形状(即前面等式中x和y成分)是Procuses对齐形状值(即,权威的形状)。另外用前面提到的形式构造子空间,矩阵的每一列归一化为单位长度。在shape_model:train函数中,先前部分描述的dy是通过映射附属于刚性运动数据成分计算得到的。如下:Mat R=this-calc_rigid_basis(Y);/计算刚性子(xng zi)空间Mat P=R.t()*Y;Mat dy=Y-R*P/产生(chnshng)出
44、的刚性注意这个投影是通过(tnggu)简单的矩阵乘法实现的。这可能是因为刚性子空间列已经进行了长度归一化。这并没有改变模型张开的空间,并且仅意味着R.t()*R等价与单位矩阵。因为源于刚性转换的变化性的方向已经从先前先前学习变形模型的数据中去掉,作为结果变形的子空间将正交与刚性转换的子空间。因此,连接两个子空间将导致一个组合局部-全局线性面部形状的表示,这同样也正交。这里联合可以利ROI抽取机制,排列两个矩阵到混合子空间矩阵的子矩阵来现实。ROI的抽取可以用OpenCV的Mat类来实现。如下:V.create(2*n,4+k,CV_32F);/组合子空间Mat Vr=V(Rect(0,0,4,
45、2*n);R.copyTo(Vr);/刚性子空间Mat vd=V(Rect(4,0,k,2*n);D.copyTo(Vd);/非刚性子空间结构模型的正交性意味着描述一个形状的参数可以简单地被计算,就像shape_model:calc_param函数做的:p=V.t()*s;这里的s是一个矢量化的人脸形状,并且p存储着表示它的人脸子空间的坐标。最后一点注意的是线性化模型人脸形状是怎样约束子空间的坐标,例如使用它产生的形状任然有效。在下面的图像中,位于子空间的人脸形状示例被展示,用来表现坐标的一个增加值,用变量的一个方向值和4个标准差的增加。注意对于小的值,结果形状保持的像人脸,但是随着值变大开始
46、恶化。阻止这种变化的一个简单的方法是固定住子空间坐标的值,使当用子空间的数据决定时位于允许的区域。对于这个一个普遍的选择是用+-3数据标准差约束的框,这占数据变化的99.7比例。这些固定的值通过shape_model:train函数,在找到子空间后,计算得到的。如下:Mat Q=Vt()*X;/将原始数据投影到子空间for(int i=0;iN;i+)/归一化坐标尺度 float v=Q.fl(0,i); Mat q=Q.col(i);q/=v;e.create(4+k,1,CV_32F);multiply(Q,Q,Q);for(int i=0;i4+k;i+)if(i4) e.fl(i)=-
47、1;/对于刚性稀疏(xsh)不固定else e.fl(i)=Q.row(i).dot(Mat:ones(1,N,CV_32F)/(N-1);注意方差是在子空间标准化后的坐标上计算的,标准化是关于第一维的坐标(即尺度)。这样可以阻止相对大尺度的样本数据主导估计。也注意到一个负值被分配到刚性子空间坐标的方差(即V的前四列)。用来固定的函数shape_model:clamp来检测是否一个特殊方向的方差是负值,如果不是负值则应用(yngyng)固定,如下:void shape_model:clamp(const float c)/固定作为(zuwi)标准方差的分数 double scale=p.fl(
48、0);/提取尺度for(int i=0;ie.rows;i+) if(e.fl(i)v)/保存坐标符号if(p.fl(i)0) p.fl(i)=v*scale;/正阈值else p.fl(i)=-v*scale;/负阈值这样做的理由是训练数据通常是在人为的环境下获取的,在这种环境下,人脸是竖直的并且以一个特殊的尺度位于图像的中心。依赖于训练集中的配置的形状模型的刚性成分是非常受限制的。最终,随着每一个可变形坐标的方差在尺度化的帧中被计算,在固定时,同样的尺度化必须应用于坐标。训练和可视化用标记的数据训练一个形状模型的例程可以在train_shape_model.cpp中找到。带有包含标记数据路
49、径的命令行参数argv1,训练通过导入数据到内存开始,并且移除不完全的样本,如下:ft_data data=load_ft(argv1);data.rm_imcomlete_samples();对于每个例子的标记和可选的他们的镜像部分,在传输到训练函数之前被存储在一个容器中,如下:vetctorvector pointsfor(int i=0;iint(data.points.size();i+) points.push_back(data.get_points(i,false);if(mirro) points.push_back(data.get_points(i,true);然后形状(x
50、ngzhun)模型通过调用一个函数shape_model:train()来训练,如下:shape_model smodel ;smodel.train(points,data.connections,frac,kmax);这里frac(即用来保留的变化分数)和kmax(即用来保持的最大特征矢量的数目)通过命令行选项可以有选择的设置,默认设置为0.95和20,分别(fnbi)地,(这两个参数)在大部分情况下趋向于工作好。最后采用包含保存训练形状模型路径的命令行参数argv2,保存可以通过调用一个函数来执行,如下:save_ft(argv2,smodel);这部的简单性是由于为shape_mode
51、l类定义(dngy)了read和write序列化函数。为了可视化训练模型,visualize_shape_model.cpp程序生动化地轮流显示每个方向的非刚性变形。通过导入形状模型到存储器开始,如下:shape_model smodel=load_ft(argv1);用来置于显示窗口的中心的模型的刚性参数的计算如下:int n=smodel.V.rows/2;float scale=calc_scale(smodel.V.col(0),200);float tranx=n*150.0/smodel.V.col(2).dot(Mat:onews(2*n,1,CV_32F);float trai
52、ny=n*150.0/smodel.V.col(2).dot(Mat:onews(2*n,1,CV_32F);这里calc_scale函数寻找尺度化系数,该系数可以产生带有200像素宽的人脸形状。平移成分通过找到系数(用来产生150像素的平移)来计算(即,这里的模型均值中心化并且用大小为300*300的窗口显示)。注释注意shape_model:V的第一列对应于尺度并且第三列和第四列分别对应于x和y的平移。然后参数值的轨道被产生,该轨道从0开始,移动到正的极端,移动到负的极端,然后回到0,如下:vector val;for(int i=0;i50;i+)val.push_back(float(
53、i)/50);for(int i=0;i50;i+)val.push_back(float(50-i)/50);for(int i=0;i50;i+)val.push_back(-float(i)/50);for(int i=0;i50;i+)val.push_back(-float(50-i)/50);这里,每一个动画的相位由50个增值组成。然后这个轨道被用于在显示窗口上动画人脸模型和给于(渲染)结果。如下:Mat img(300,300,CV_8UC3); namedWindow(“shape model”);while(1) for(int k=4;ksmodel.V.cols;k+)
54、for(int j = 0; j int(val.size(); j+)Mat p = Mat:zeros(smodel.V.cols,1,CV_32F);p.at(0) = scale;p.at(2) = tranx;p.at(3) = trany;p.at(k) = scale*valj*3.0*sqrt(smodel.e.at(k); p.copyTo(smodel.p); img = Scalar:all(255);vector q = smodel.calc_shape();draw_shape(img,q,smodel.C);imshow(shape model,img);if(w
55、aitKey(10) = q)return 0;注释(zhsh)注意刚性系数(即,这些对应于shape_model:V的前四列)通常设置为先前(xinqin)计算得到的值,用来将人脸显示在屏幕的中心。面部(min b)特征检测器检测图像中的面部特征和一般目标检测很相似。OpenCV有一组精细的函数来建立一般目标检测,其中最知名就是基于Haar特征级联检测器,它采用的是著名的Viola-Jones人脸检测器实现的。然而,有些可以可区分的因素,这些因素使得(sh de)面部检测唯一,他们如下:精度对鲁棒性:在一般的目标(mbio)检测,目的是为了寻找图像中目标的大致位置。面部检测器需要得到特征位置
56、的高精度的估计。一种错误是:在目标检测中少量像素被认为不重要,但是在通过特征检测进行人脸表情估计时它可能意味着微笑和皱眉的之间的差异。来至有限空间支持的歧义:一个很常见的假设是用一般目标检测器检测感兴趣的目标表现出充分的图像结构,这样,它可以可靠的区分不包含目标的图像区域。对于面部特征来说这不是常见的情况,它典型地限制了空间支持。这是因为不包含目标的图像区域通常表现出和面部特征非常相似的结构。例如,人脸边缘的一个特征,从中心位于该特征点的小边界框来看,很容易和任何其他的包含有明显边缘的图像块混淆。计算的复杂度:一般目标检测的目的是寻找图像中所有目标的实体。另一方面,人脸跟踪需要得到所有面部特征
57、的位置,这通常包含有大约20到100个特征。因此,有效地评估每一个特征检测器性能,最主要的在于能够建立一个实时的人脸跟踪器。由于这些的差异,用于人脸跟踪的面部特征检测器通常专门的设计。当然,在人脸跟踪中,有很多一般目标检测器技术应用到面部特征人脸器。然而,在关于谁表现的更能适合解决面部特征跟踪问题上,没有一个一致的说法。在这一部分,我们将使用被认为是最简单的模型线性图像块来建立面部特征检测。尽管它简单,在设计它的学习过程时应关注一下,我们将看到事实上用在人脸跟踪算法上,它可以给出面部特征位置的合理估计。而且,他们的简单些使得估计速度非常快,使实时的人脸跟踪成为可能。由于他们表现的像一个图像块,
58、因此,面部特征检测器称为块模型。这个模型通过patch_model类来实现,该类可以在patch_model.hpp和patch_model.cpp文件中找到。下面(xi mian)的代码片段给出了path_model类的头部分,强调该类 的基本功能:class patch_modelpublic:Mat P; /normalized patch/归一化的块.Mat /response map /映射(yngsh)calc_response(const Mat &im, /image patch of search region/搜索区域(qy)的图像块const bool sum2one =
59、 false); /normalize to sum-to-one?.voidtrain(const vector &images, /training image patches/训练图像块const Size psize, /patch size/块大小const float var = 1.0, /ideal response variance /实响应方差const float lambda = 1e-6, /regularization weight/规则化权重const float mu_init = 1e-3, /initial step size/初始化的步长大小const i
60、nt nsamples = 1000, /number of samples/样本的数量const bool visi = false); /visualize process?/是否可视化过程.;用来检测面部特征的块模型存储在矩阵P中。在这个类中两个基本的函数是:calc_response和train。calc_response函数用来计算每一个搜索区域im的整体替代部分的块模型响应。train函数学习psize大小的块模型,平均而言,在训练集上产生的响应很接近于理想的响应。var,lambda,mu_init和nsamples是训练过程的参数,可以随时调整到最佳性能。这个类的功能将在这一部
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 企业销售个人的工作总结
- 乡村医生先进事迹500字(10篇)
- DB12T 598.17-2015 天津市建设项目用地控制指标 第17部分:墓葬项目
- 中秋节的慰问信(5篇)
- 团支部书记竞选演讲稿四篇
- 新学期学习计划范本锦集8篇
- 业务员的实习报告范文4篇
- 高等数学教程 上册 第4版 习题及答案 P177 第7章 多元微积分
- 天然气公司股东协议书-企业管理
- 3D立体风立体商务汇报
- 蓝色简约风中国空军成立75周年纪念日
- 2024年全国企业员工全面质量管理知识竞赛题库(含答案)(共132题)
- 知识创业思维与方法智慧树知到答案2024年湖南师范大学
- 无人机全行业保险
- 2023年广东省建筑设计研究院校园招聘笔试参考题库附带答案详解
- 员工人事档案目录
- 迅达SWE30-100K自动扶梯电路分析_图文
- 二年级上册数学计算能力测试题73375
- 气体流量和流速及与压力的关系
- 混凝搅拌实验操作方法
- 拌混凝土拌合站管理办法
评论
0/150
提交评论