Kinect人脸跟踪KinectFaceTrackingSDK
Kinect人脸跟踪Kinect Face Tracking SDK相关资料免积分下载目录:1.前言2.人脸跟踪概念(1)软件硬件配置(2)face tracking参数(3)具体技术(4)函数和结构(5)人脸跟踪简易流程3.更多人脸跟踪细节介绍(1)线程问题(2)人脸特征点(3)人脸旋转4.程序配置与说明5.参考资源6.程序源代码-----------------------------------------------------------------------------------1.前言自上篇Kinect SDK 1.5 Face Tracking文章出现后(2012-5-27),许多人阅读到了(CSDN,博客园,百度文库),相关代码也被上百次下载(百度文库、csdn)。
之所以Kinect中的Face Tracking没有得到很多的关注,我想主要原因还是这个方法必须使用Kinect硬件(真不便宜啊,普通摄像头几十块ok了),只适合开发Kinect室内应用。
其次这个Face Tracking也是很耗CPU的,一般的双核电脑一旦运行经常会占用90%多的CPU。
题外话,微软有许多强大的算法,比如人脸跟踪(基于普通彩色摄像头),但是他们只给了Windows Phone下的API,却不给出PC下的。
我也去天津参加过Kinect的会议,遇到一些微软的产品,确实做得很强大很稳健,人脸检测用改进的特征进行Adaboost,之后用AAM进行面部特征点跟踪,十分稳健。
去年参加了不少面试,国内的很多公司都在做人脸识别,但真正有实力的只有大公司弄的好。
但如果说你想靠这个Kinect的人脸识别混饭吃,有点困难,除非你研究AAM人脸跟踪算法再去研究人脸识别、表情识别、三维建模等算法才会有饭吃。
鉴于之前没有对Kinect的Face Tracking进行详细描述和探讨,直接暴力的给出相关代码,有必要给出更详细的文章和更好的代码。
------------------------------------------------------------------------------------2.人脸跟踪概念首先现在大部分开发都针对Kinect for windows(目前1900RMB,还是有点贵的)了,但这个face tracking SDK在xbox版的Kinect依旧可以运行,自然精度会不好。
Kinect for windows的深度数据是640*480的,而xbox的是320*240。
而彩色的RGB摄像头也清晰不少,这点官方没有具体介绍,但实际效果好很多。
如果要做研究,自然使用贵很多的Kinect for windows了(这样也导致了个人一般不会去玩这个传感器),不过对于学校、公司这点钱不多。
下面默认使用Kinect for windows,但代码稍加修改在xbox的kinect上也能运作。
--------------------------------------------------(1)软件硬件配置Kinect for Windows有如下要求:采用下列操作系统的一种:Windows 7嵌入式Windows 标准7嵌入式Windows POSReady 7Windows 8硬件要求32位(x86)或64位(x64) 处理器双核2.66-GHz 或更快的处理器(建议使用i7)专用USB 2.0总线2 GB内存从Kinect SDK 1.5开始的Kinect for windows开发工具包中含有人脸追踪模块,当前最新的是SDK1.6。
在近几个星期里,将会有新的SDK会更新。
新的SDK将会带来简单的动作识别(手握拳和张开)和Kinect Fusion三维实时建模。
--------------------------------------------------(2)face tracking参数依赖于你PC的CPU能力,人脸跟踪引擎使用4~8ms对一帧图像进行人脸跟踪,仅仅只依赖于CPU(没有使用GPU)。
将会影响跟踪准确率的因素:A.光照:光线应该充足,没有太多阴影或者太强的侧光。
也就是光照要均匀,并且足够。
B.距离:距离Kinect的距离,距离体感越近则跟踪效果越好,当小于1.5m时,跟踪的效果是最好的,因为越近深度数据越精确。
当然也不能太近了,如果小于0.5m,深度数据都无法获取,或者人脸遮住摄像头了,也无法跟踪。
C.遮挡:戴厚眼镜或者Lincoln那样的胡子,人脸跟踪会有问题,这点还是需要改善的方面。
使用了Active Apperance Model作为二维特征跟踪器,然后我们把计算模型扩展到我们的Kinect深度数据上,然后它可以跟踪三维的人脸,这样使得它比二维特征点跟踪器稳健。
AAM算法对于真实世界的情况不是很稳健。
一些算法:算法AAM、AAM人脸跟踪,算法3.--------------------------------------------------(3)具体技术坐标系统:使用了Kinect的坐标系统来输出三维跟踪结果(x,y,z)。
Z轴是传感器到用户的距离,Y轴是上下指向。
数据都是以米为计量单位(这样一般会读出2.xxx,1.xxx之类的浮点数值),角度都是旋转角度(不是弧度)。
上图是输出的三维面具在kinect的坐标下情况。
输入图像:彩色图像和深度图像。
其实还需要一个人头和脖子的三维坐标。
--------------------------------------------------(4)函数和结构人脸追踪的SDK是免注册的COM对象。
主要有4个COM接口IFTFaceTracker:人脸追踪主要接口。
IFTResult:人脸追踪运算的结果。
IFTImage:图像缓冲区,类似OpenCV的Mat。
IFTModel:三维人脸模型还有一些结构:FT_SENSOR_DATA:包含用于人脸追踪所有所需的输入数据。
FT_CAMERA_CONFIG:包含彩色或者深度传感器的信息。
FT_VECTOR2D:二维向量。
也就是(x,y),(x,y)…FT_VECTOR3D:三维向量。
FT_TRIANGLE:三维模型人脸角度。
FT_WEIGHTED_RECT:权重矩阵。
--------------------------------------------------(5)人脸跟踪简易流程不论是1个人的还是2个人的追踪,都差不多。
一般追踪距离摄像头比较近的人,骨骼数据可能有时无法获取(那就使用上一帧的就是,经验之谈,因为很随机)。
-----------------------------------------------------------------------------------3.更多人脸跟踪细节介绍这里介绍一些实际开发时遇到的问题。
(1)线程问题一般至少2个线程,微软给的例子(FaceTrackingVisualization)一个是获取彩色、深度、骨骼的线程,另一个线程直接调用使用这三个数据,把数据传给人脸跟踪模块,都没进行线程同步。
我有点疑问,不同步会不会有问题,但怎么运行测试都木有问题。
每次跟踪后它都Sleep(16)一下,这个数值自己可以修改,我在win32应用里使用Sleep(30)运行结果不错,而在MFC中也使用Sleep(16)。
这里还需要特别说明的是,千万小心对于原始数据的操作,也就是彩色、深度数据的操作。
如果你想显示数据,请拷贝数据后另行处理,不要直接在数据上进行处理,否则会出现很麻烦的问题。
你以为把数据传给跟踪模块后,就可以直接在彩色数据(IFTImage)上进行更改了,但在你更改后,人脸跟踪模块由于设置的是16ms,马上又调用人脸跟踪,丢失了人脸模型!这样会出现一种结果:人脸跟踪十分不稳定,面具随机在人脸附近跳动,人脸一旦运动快点,跟踪会发生失效。
所以之后我学乖了,要对数据处理或者显示,另外拷贝一份,其实拷贝图像数据是瞬间的事情。
(2)人脸特征点微软在face tracking介绍给了一张的人脸图像,这里我就不给图像了,因为那张人脸特征点图像不论是位置还是下标都是不符的。
这里我给出我得到的图像:上图有121个特征点(有些点重复,有些不存在)微软的面部特征点符合Candide-3标准,我们可以在文献(Candide-3_-_an_updated_parameterised_face)中阅读到一张表Appendix A: The CANDIDE -3 Vertices and the Corresponding MPEG -4 Facial Feature Points。
它列出了113个顶点(下标从0开始),这些顶点的定义和程序中获取的数组一一对应,还多出来的部分可以无视掉。
这张图像是使用OpenCV显示人脸跟踪数组中的顶点结果,我们可以自己修改程序画出来,需要注意的就是把图像画大一些,否则字符串会重叠在一起。
之所以我用线连起来,主要为了看上去更方便,如果一百多个数字显示在图片上,肯定没人想去研究。
我把数字按顺序一次连接,发现某些点可以连接出如图所示的线段图。
至于每个点到底什么意思,还是要对照表中定义。
显然这么多点,我们只取需要的点即可。
这个仁者见仁智者见智吧。
下图是顶点定义的那张表:(3)人脸旋转获取人脸跟踪结果后,我们除了得到面部关键顶点还可以直接获取人脸朝向(Get3DPose函数)。
下图是人脸朝向的定义:自然如果你做简单的人头旋转头部动作识别,肯定得用到这块。
如果你做人脸标表情、动作或者三维建模,也少不了使用这个旋转角度对人脸进行一些仿射变换。
很显然,Roll 方向上的人脸旋转可以消除掉(我在我的人脸识别中就这样)。
如果你使用OpenCV进行放射旋转,要熟悉矩阵旋转公式,一旦人脸旋转,那么所有的顶点坐标都要跟着旋转,如果扣除人脸区域,那么相应的人脸顶点坐标也要减去x轴和y轴的数值。
还有需要考虑一些临界情况,比如人脸从左侧移除,人脸从上方、下方走出,会不会导致程序崩溃?此时的人脸数据不可以使用。
之后还有动画单元等概念,也是可以通过函数直接获取结果,这部分我未进行研究,如果做表情或者人脸动画,则需要深入研究下。
----------------------------------------------------------------------------------4.程序配置与说明对于Win32程序。
如果只想看效果,不想研究代码,安装好Kinect驱动后,可以直接点击Debug下的exe应用程序进行运行即可。
如果想研究代码,需要配置OpenCV环境(文章链接),随便你使用OpenCV2.x某个版本,建议使用目前最新的OpenCV2.4.4。
基于Kinect的人体姿态识别与跟踪系统设计
基于Kinect的人体姿态识别与跟踪系统设计人体姿态识别与跟踪系统在计算机视觉领域具有广泛的应用前景。
基于Kinect的人体姿态识别与跟踪系统设计是一项复杂而有挑战性的任务。
本文将讨论该系统的设计原理、关键技术和实现方法。
首先,基于Kinect的人体姿态识别与跟踪系统的设计是基于深度图像和彩色图像的融合。
Kinect传感器能够同时获取人体的深度信息和彩色图像,这为人体姿态的识别和跟踪提供了更加可靠的数据来源。
其次,关键技术之一是深度图像的处理和分析。
深度图像是基于红外线技术获取的,能够准确地测量物体和人体的距离信息。
通过对深度图像进行处理和分析,可以得到人体的关节位置和姿态信息。
常用的技术包括深度图像的滤波、分割、几何特征提取和关节位置计算等。
另一个关键技术是彩色图像的处理和分析。
彩色图像可以提供更多的纹理和细节信息,对于人体姿态的识别和跟踪也起到重要的作用。
通过对彩色图像进行处理和分析,可以得到人体的皮肤检测、形状分析、纹理特征提取等信息,以辅助人体姿态的识别和跟踪。
在人体姿态的识别和跟踪中,关节的检测和定位是一个关键的步骤。
Kinect的传感器可以获取人体的关节位置信息,但由于深度图像的噪声和模糊,导致关节位置的准确度有限。
因此,需要采用一些算法和方法来提高关节位置的精度。
例如,通过滤波算法可以降低噪声,而通过模型拟合算法可以提高关节的准确度。
此外,为了实现实时的人体姿态识别和跟踪,需要考虑系统的性能和效率。
Kinect的传感器可以在较快的频率下获取图像和深度信息,但在实际应用中,需要通过优化算法和并行计算等技术来提高系统的运行速度和效率。
例如,可以通过多线程编程和GPU加速等技术来实现并行计算,从而提高系统的实时性。
最后,基于Kinect的人体姿态识别与跟踪系统的设计还需要考虑用户交互的问题。
传统的人机交互方式主要通过键盘、鼠标等输入设备实现,而基于Kinect的人体姿态识别与跟踪系统可以通过识别和跟踪用户的动作和姿态来实现更自然、直观的交互方式。
基于Kinect深度图像的人脸识别方法研究
基于Kinect深度图像的人脸识别方法研究
施丽红
【期刊名称】《信息技术与信息化》
【年(卷),期】2022()4
【摘要】随着识别场合及识别数量越来越多,对人脸识别方法及技术的准确性和稳定性要求也逐渐提高,由于传统方法在对人脸识别中具有较低的查全率,为此提出基于Kinect深度图像的人脸识别方法研究。
首先运用Kinect技术采集到人脸深度图像数据,为人脸识别提供数据依据;然后运用模糊数学原则对采集到的深度图像数据进行灰度值转换及滤波处理;通过CNN网络算法将提取到的人脸特征与数据库中原有数据进行对比识别,以此实现基于Kinect深度图像的人脸识别方法设计。
经实验证明,设计方法查全率高于传统方法。
【总页数】4页(P177-180)
【作者】施丽红
【作者单位】江苏商贸职业学院电商与物流学院
【正文语种】中文
【中图分类】TP3
【相关文献】
1.基于Kinect深度图像的腕部及手指活动度测量方法
2.基于kinect深度图像的联合双边滤波算法的研究
3.基于改进双边滤波的Kinect深度图像空洞修复算法研究
4.基于Kinect深度数据的移动机器人障碍检测方法研究
因版权原因,仅展示原文概要,查看原文内容请购买。
基于Kinect的3D人脸识别(1)
基于kinect的3D人脸识别技术摘要在2D人脸识别技术不断发展的今天,深度学习的出现让2D人脸识别技术的准确率已经达到了97.54%,2D技术的发展空间越来越小。
而随着3D技术也越来越成熟,将3D技术融合到人脸识别技术中是一种新的发展方向。
而现阶段,kinect这种体积轻巧,价格便宜,捕获3D数据效率高而且分辨率不低的设备成了许多研究人员的研究对象。
在本文中我们也利用了kinect设备完成了一个基于kinect的3D人脸识别研究的过程。
首先通过kinect设备采集了一批数据,接着实现了一种基于熵图和显著性图,利用HOG特征算子,和随机森林分类器和SVM分类器进行识别的算法系统。
通过我们的实验,利用随机森林分类器实现的分类器准确率只有73%,而利用SVM分类器达到的准确率有83.19%。
但是因为采集数据的范围小,以及算法的不完善性,我们的系统还有很大的提升空间。
关键词:kinect,RGB-D,显著性,熵图,随机森林,SVM,人脸识别AbstractWith the fast development of the face recognition based 2D data, the deep learning technology makes the accuracy of the face recognition based 2D data have reached in 97.54% and the development of the 2D technology in face recognition has reached the bottleneck. However, with the 3D technology becoming more and more mature, it is a new development direction to fuse the 3D technology into face recognitiontechnology. In the meanwhile, the Kinect which is portable, inexpensive and has high capturing rate and moderate definition becomes the research object of many researchers.In our paper, we used the Kinect equipment to finish a project which is about face recognition based 3D data. First of all, we collected enough RGB-D data using Kinect. Then we implemented the algorithm system which is based the entropy map and the visual saliency map, gets the feature vector using the HOG descriptor and using random decision forest and support vector machine to classify the data.The result of our experiment is not very well. The accuracy of the recognition with random decision forest classifier reaches only 73%. However, the accuracy of the recognition with support vector machine reaches 83.19%. Because of the small scale in the database and the imperfect algorithm, our system can still make great progress.Key words:Kinect, RGB-D, salience, entropy, RDF, SVM, face recognition1,绪论1.1研究背景随着人们对人工智能,机器学习算法的研究的不断深入,其分支领域中的计算机视觉中的人脸识别技术也得到了充分的发展和巨大的进步。
Kinect for Windows SDK开发入门(十五):进阶指引 下
[译]Kinect for Windows SDK开发入门(十五):进阶指引下上一篇文章介绍了Kinect for Windows SDK进阶开发需要了解的一些内容,包括影像处理Coding4Fun Kinect工具类库以及如何建立自己的扩展方法类库来方便开发,接下来介绍了利用Kinect进行近距离探测的一些方法,限于篇幅原因,仅仅介绍了近距离探测的三种方式。
本文接上文将继续介绍近距离探测中如何探测运动,如何获取并保存产生的影像数据;然后将会介绍如何进行脸部识别,以及介绍全息图(Holograme)的一些知识,最后介绍了一些值得关注的类库和项目。
2.4 运动识别目前,利用运动识别(motion detection)来进行近景识别是最有意思的一种方式。
实现运动识别的基本原理是设置一个起始的基准RGB图像,然后将从摄像头获取的每一帧影像和这个基准图像进行比较。
如果发现了差异,我们可以认为有东西进入到了摄像头的视野范围。
不难看出这种策略是有缺陷的。
在现实生活中,物体是运动的。
在一个房间里,某个人可能会轻微移动家具。
在户外,一辆汽车可能会启动,风可能会将一些小树吹的摇摇晃晃。
在这些场景中,尽然没有连续的移动动作,但是物体的状态还是发生了变化,依据之前的策略,系统会判断错误。
因此,在这些情况下,我们需要间歇性的更改基准图像才能解决这一问题。
与我们之前遇到的问题相比,完成这些任务看起来需要更强大的图像分析处理工具。
幸好,之前介绍的开源OpenCV库提供了某种复杂的实时图像处理操作的能力。
OpenCV是Intel公司在1999年发起的一个项目,它将一些高级的视觉研究成果加入到OpenCV库中并开源贡献给了全世界。
2008年,一个名为Willow Garage的科技孵化公司负责对该项目的更新和维护。
几乎同时EmguCV项目开始发起,他提供了对OpenCV的.Net包装,使得我们在.Net环境下能够使用OpenCV库中的函数。
基于Kinect的人脸表情捕捉及动画模拟系统研究
基于Kinect的人脸表情捕捉及动画模拟系统研究何钦政;王运巧【摘要】The technical of 3D human facial expression animation is a subject which has potential application and fatal research significance. This paper proposes a facial expression animation solution based on Microsoft Kinect device after the research of existing facial expression capture technology and animation synthesis technology. First, Kinect device is used to capture the face data and relevant expression parameters are extracted, at the same time, a three-dimensional model of face is reconstructed with Autodesk Maya animation software. Then the model is imported to OGRE animation engine and the expression parameters transferred to OGRE in which real time facial expression animation is rendered at last. Experiment results show that the method can provide an acceptable and reliable real-time facial expression animation. Compared to other existing facial expression animation technologies, the system is easier to operate with rather inexpensive device.%三维人脸表情动画技术是一个具有巨大应用前景和研究意义的学科方向。
kinectSDK开发使用示例
Kinect Hardware
Setting Up Your Development Environment
• 硬件
– Kinect Hardware – AC Adapter/ Power Supply
Working with Depth Data
Runtime nui = new Runtime(); private void Window_Loaded(object sender, RoutedEventArgs e) { //UseDepthAndPlayerIndex and UseSkeletalTracking nui.Initialize(eDepthAndPlayerIndex | eSkeletalTrackin //register for event nui.DepthFrameReady += new EventHandler<ImageFrameReadyEventArgs>(nui_DepthFrame //DepthAndPlayerIndex ImageType nui.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution320x240, ImageType.DepthAndPlayerIndex); } void nui_DepthFrameReady(object sender, ImageFrameReadyEventArgs e) {}
What’s is Kinect?
• Kinect是XBox 360的外接体感设备
基于Kinect的面部表情获取与识别方法研究
基于Kinect的面部表情获取与识别方法研究作者:余冰,胡新荣,程露来源:《科技创业月刊》 2016年第8期余冰胡新荣程露(武汉纺织大学湖北武汉 430200)摘要:目前,部表情识别技术在智能监控、人机交互、虚拟现实、医疗等领域有着非常广阔的应用前景。
文章提出一种使用微软公司Kinect采集面部三维数据进行表情识别的方法。
通过Kinect采集的深度和彩色数据,生成人体骨骼,利用头部节点进行面部追踪。
对三维面部进行了归一化处理和PCS校正之后,用方法进行特征信息提取,结合FACS设计SVM分类器进行表情分类。
通过三组对比实验分析了此方法的优缺点。
关键词:Kinect感应器;KPCA;FACS;SVM中图分类号:TP391.4文献标识码:Adoi:10.3969/j.issn.1665-2272.2016.08.047 收稿日期:2016-02-190引言对一个人情感状态的判断最重要的是关注其面部表情。
将面部表情识别技术应用于服务机器人,使其具备识别人类情感甚至表达情感的能力,可以使人机交互过程变的更加简单便捷。
对面部表情的研究始于19世纪,Friesen和Ekman将常见表情分为高兴、悲伤、惊讶、恐惧、愤怒和厌恶六种,并整理建立了表情研究库。
时至今日,面部表情识别的方法越来越多,比较常见且效果不错的有基于局部特征的方法和基于几何特征的方法以及基于运动的方法等。
这些方法不是相互独立的,可以相互组合使用。
常见方法(见表1)。
文章提出利用Kinect进行表情识别,利用Kinect的骨骼追踪功能进行面部检测和定位,并通过获得的三维数据进行特征提取与表情分类。
相对于其他二维图像表情识别具有更好的鲁棒性和有效性。
1表情识别的主要过程面部表情的识别,就是根据面部的外表变化,计算判断对应的情感状态。
回顾判断他人情感状态的过程:判断别人的情感状态,首先,得先看到对方的脸,即要进行面部检测与追踪;其次,观察面部器官的变化,即寻找面部特征变化,所以第二步是对面部特征的提取;第三,根据各个器官的变化,通过思考判断出对方的情感状态,即进行表情的分类,所以最后一步是面部表情的识别分类。
(纪录片)现代生活的秘密规则:算法TheSecretRulesofModernLiving。。。
(纪录⽚)现代⽣活的秘密规则:算法TheSecretRulesofModernLiving。
简介:The Secret Rules of Modern Living: Algorithms (2015)导演:主演:类型: 纪录⽚官⽅⽹站:制⽚国家/地区: 英国语⾔: 英语上映⽇期: 24 Sep 2015⽚长: 1 hour主要内容:介绍算法在现代⽣活中的应⽤(极⼒推荐这部纪录⽚),有趣、直观、富有实际意义,主要包含以下⼏种算法:1、⼈脸检测 face detection2、数学游戏(必胜策略) a mathematical game with a jar full of chocolates and one red hot chilli3、欧⼏⾥得(辗转相除法)求最⼤公约数 Euclidean greatest common divisor4、⽹页排序 PageRank5、排序算法(冒泡、归并排序) sorting algorithm(bubble sort, merge sort)6、稳定匹配算法或Gale-Shapley算法 matching algorithm(2012获得诺贝尔经济学奖)7、启发性算法 heuristic approach:⼀些算法实时解决的问题(NP问题)如:棋牌游戏、数独游戏、旅⾏商问题(蜜蜂采蜜实验)、机场飞机调度等8、Kinect⾻骼跟踪算法 Kinect skeletal-tracking algorithm(机器学习)9、推荐算法 recommendation algorithm10、仓库商品调度 warehouse problem如:预测算法、系统调度算法、路径规划算法等。
基于Kinect的人脸图像识别
学校代号 分 类 号
10532 TP391
学 密
号 级
S1109W413 公开
工程硕士学位论文
基于 Kinect 的人脸图像识别
学位申请人姓名 培 养 单 位
戴梅 电气与信息工程学院 林翚 副教授 陈练兵 高级工程师 控制工程 模式识别 2013 年 4 月 15 日
导师姓名及职称 学 研 科 究 专 方 业 向
论文提交日期
学校代号: 105பைடு நூலகம்2 学 密 号: S1109W413 级: 公开
III
基于 Kinect 的人脸图像识别
目
录
学位论文原创性声明和学位论文版权使用授权书 .................................................. I 摘要 ......................................................................................................................... II Abstract .................................................................................................................. III 第 1 章 绪论 ............................................................................................................ 1 1.1 人脸识别的研究背景 .............................................................................. 1 1.2 人脸识别技术的研究现状 ....................................................................... 2 1.3 人脸识别技术存在的难点以及解决方法 ................................................ 3 1.4 Kinect 简介 .............................................................................................. 4 1.5 本文的主要研究工作及章节安排 ........................................................... 7 第 2 章 KINECT 2D 人脸检测与识别 ..................................................................... 8 2.1 前言 ......................................................................................................... 8 2.2 人脸图像预处理 ...................................................................................... 8 2.3 人脸检测 ................................................................................................. 9 2.3.1 Haar 特征 ....................................................................................... 10 2.3.2 积分图像 ........................................................................................ 11 2.3.3 AdaBoost 检测器 ............................................................................ 11 2.3.4 AdaBoost 人脸检测方法结果 ......................................................... 14 2.4 基于 LBP 的人脸识别 ........................................................................... 15 2.4.1 LBP 算子 ........................................................................................ 15 2.4.2 LBP 特征差异度量 ......................................................................... 17 2.4.3 基于 LBP 的人脸识别结果分析 ..................................................... 17 2.5 本章小结 ............................................................................................... 18 第 3 章 KINECT 3D 人脸检测与识别 ................................................................... 20 3.1 前言 ....................................................................................................... 20 3.2 人脸检测 ................................................................................................ 21 3.2.1 OpenNI 介绍 ................................................................................... 21 3.2.2 基于骨骼追踪技术的人脸检测 ...................................................... 22 3.3 三维人脸数据获取 ................................................................................ 24 3.3.1 三维人脸数据的三种形式 .............................................................. 24 3.3.2 基于区域生长法获取 3D 人脸信息 ............................................... 25 3.4 人脸点云预处理 . ............................................................................................... 27
Kinect SDK 1.5 Face Tracking --- 使用opencv显示后的超级简化版本
Kinect SDK 1.5 Face Tracking ---> 使用opencv显示后的超级简化版本VS2010+opencv2.3.1+Kinect SDK1.5驱动什么的,大家自己安装,木有基础的同学先学好基础先。
代码是基于我之前更新的SDK1.5基础之上的,如果不太懂,先看之前的文章~/guoming0000/article/details/7607473免积分下载VS2010项目源码地址~// win32_KinectFaceTracking.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"//----------------------------------------------------#define _WINDOWS#include <FaceTrackLib.h>HRESULT VisualizeFaceModel(IFTImage* pColorImg, IFTModel* pModel, FT_CAMERA_CONFIG const* pCameraConfig, FLOA T const* pSUCoef, FLOAT zoomFactor, POINT viewOffset, IFTResult* pAAMRlt, UINT32 color); //----------------------------------------------------#include <vector>#include <deque>#include <iomanip>#include <stdexcept>#include <string>#include <iostream>#include "opencv2\opencv.hpp"using namespace std;using namespace cv;#include <windows.h>#include <mmsystem.h>#include <assert.h>#include <strsafe.h>#include "NuiApi.h"#define COLOR_WIDTH 640#define COLOR_HIGHT 480#define DEPTH_WIDTH 320#define DEPTH_HIGHT 240#define SKELETON_WIDTH 640#define SKELETON_HIGHT 480#define CHANNEL 3BYTE buf[DEPTH_WIDTH*DEPTH_HIGHT*CHANNEL];int drawColor(HANDLE h);int drawDepth(HANDLE h);int drawSkeleton();//---face tracking------------------------------------------BYTE *colorBuffer,*depthBuffer;IFTImage* pColorFrame;IFTImage* pDepthFrame;FT_VECTOR3D m_hint3D[2];//----------------------------------------------------------------------------------- HANDLE h1;HANDLE h3;HANDLE h5;HANDLE h2;HANDLE h4;{// cout<<"video start!"<<endl;while(TRUE){if(WaitForSingleObject(h1,INFINITE)==WAIT_OBJECT_0){drawColor(h2);}// Sleep(10);// cout<<"video"<<endl;}}DWORD WINAPI DepthFunc(LPVOID pParam){// cout<<"depth start!"<<endl;while(TRUE){if(WaitForSingleObject(h3,INFINITE)==WAIT_OBJECT_0){drawDepth(h4);}// Sleep(10);// cout<<"depth"<<endl;}}{// HANDLE h = (HANDLE)pParam;// cout<<"skeleton start!"<<endl;while(TRUE){if(WaitForSingleObject(h3,INFINITE)==WAIT_OBJECT_0)drawSkeleton();// Sleep(10);// cout<<"skeleton"<<endl;}}DWORD WINAPI TrackFace(LPVOID pParam){cout<<"track face start !"<<endl;while(TRUE){//do somethingSleep(16);cout<<"track face"<<endl;}}//-----------------------------------------------------------------------------------int drawColor(HANDLE h){const NUI_IMAGE_FRAME * pImageFrame = NULL;HRESULT hr = NuiImageStreamGetNextFrame( h, 0, &pImageFrame );if( FAILED( hr ) ){cout<<"Get Color Image Frame Failed"<<endl;return -1;}INuiFrameTexture * pTexture = pImageFrame->pFrameTexture;NUI_LOCKED_RECT LockedRect;pTexture->LockRect( 0, &LockedRect, NULL, 0 );if( LockedRect.Pitch != 0 ){BYTE * pBuffer = (BYTE*) LockedRect.pBits;colorBuffer = pBuffer;memcpy(pColorFrame->GetBuffer(), PBYTE(LockedRect.pBits), min(pColorFrame->GetBufferSize(), UINT(pTexture->BufferLen())));Mat temp(COLOR_HIGHT,COLOR_WIDTH,CV_8UC4,pBuffer);imshow("b",temp);waitKey(1);}NuiImageStreamReleaseFrame( h, pImageFrame );return 0;}int drawDepth(HANDLE h){const NUI_IMAGE_FRAME * pImageFrame = NULL;HRESULT hr = NuiImageStreamGetNextFrame( h, 0, &pImageFrame );if( FAILED( hr ) ){cout<<"Get Depth Image Frame Failed"<<endl;return -1;}INuiFrameTexture * pTexture = pImageFrame->pFrameTexture;NUI_LOCKED_RECT LockedRect;pTexture->LockRect( 0, &LockedRect, NULL, 0 );if( LockedRect.Pitch != 0 ){USHORT * pBuff = (USHORT*) LockedRect.pBits;// depthBuffer = pBuff;memcpy(pDepthFrame->GetBuffer(), PBYTE(LockedRect.pBits), min(pDepthFrame->GetBufferSize(), UINT(pTexture->BufferLen())));for(int i=0;i<DEPTH_WIDTH*DEPTH_HIGHT;i++){BYTE index = pBuff[i]&0x07;USHORT realDepth = (pBuff[i]&0xFFF8)>>3;BYTE scale = 255 - (BYTE)(256*realDepth/0x0fff);buf[CHANNEL*i] = buf[CHANNEL*i+1] = buf[CHANNEL*i+2] = 0;switch( index ){case 0:buf[CHANNEL*i]=scale/2;buf[CHANNEL*i+1]=scale/2;buf[CHANNEL*i+2]=scale/2;break;case 1:buf[CHANNEL*i]=scale;break;case 2:buf[CHANNEL*i+1]=scale;break;case 3:buf[CHANNEL*i+2]=scale;break;case 4:buf[CHANNEL*i]=scale;buf[CHANNEL*i+1]=scale;break;case 5:buf[CHANNEL*i]=scale;buf[CHANNEL*i+2]=scale;break;case 6:buf[CHANNEL*i+1]=scale;buf[CHANNEL*i+2]=scale;break;case 7:buf[CHANNEL*i]=255-scale/2;buf[CHANNEL*i+1]=255-scale/2;buf[CHANNEL*i+2]=255-scale/2;break;}}Mat b(DEPTH_HIGHT,DEPTH_WIDTH,CV_8UC3,buf);imshow("depth",b);waitKey(1);}NuiImageStreamReleaseFrame( h, pImageFrame );return 0;}int drawSkeleton(){NUI_SKELETON_FRAME SkeletonFrame;cv::Point pt[20];MatskeletonMat=Mat(SKELETON_HIGHT,SKELETON_WIDTH,CV_8UC3,Scalar(0,0, 0));HRESULT hr = NuiSkeletonGetNextFrame( 0, &SkeletonFrame );if( FAILED( hr ) ){cout<<"Get Skeleton Image Frame Failed"<<endl;return -1;}bool bFoundSkeleton = false;for( int i = 0 ; i < NUI_SKELETON_COUNT ; i++ ){if( SkeletonFrame.SkeletonData[i].eTrackingState == NUI_SKELETON_TRACKED ){bFoundSkeleton = true;}}// Has skeletons!if( bFoundSkeleton ){NuiTransformSmooth(&SkeletonFrame,NULL);for( int i = 0 ; i < NUI_SKELETON_COUNT ; i++ ){if( SkeletonFrame.SkeletonData[i].eTrackingState ==NUI_SKELETON_TRACKED ){for (int j = 0; j < NUI_SKELETON_POSITION_COUNT; j++){float fx,fy;NuiTransformSkeletonToDepthImage( SkeletonFrame.SkeletonData[i].SkeletonP ositions[j], &fx, &fy );pt[j].x = (int) ( fx * SKELETON_WIDTH )/320;pt[j].y = (int) ( fy * SKELETON_HIGHT )/240;circle(skeletonMat,pt[j],5,CV_RGB(255,0,0));}cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_HEAD],pt[NUI_SKELE TON_POSITION_SHOULDER_CENTER],CV_RGB(0,255,0));cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_SHOULDER_CENTER] ,pt[NUI_SKELETON_POSITION_SPINE],CV_RGB(0,255,0));cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_SPINE],pt[NUI_SKELE TON_POSITION_HIP_CENTER],CV_RGB(0,255,0));cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_HAND_RIGHT],pt[NUI _SKELETON_POSITION_WRIST_RIGHT],CV_RGB(0,255,0));cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_WRIST_RIGHT],pt[NUI _SKELETON_POSITION_ELBOW_RIGHT],CV_RGB(0,255,0));cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_ELBOW_RIGHT],pt[NUI_SKELETON_POSITION_SHOULDER_RIGHT],CV_RGB(0,255,0));cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_SHOULDER_RIGHT],p t[NUI_SKELETON_POSITION_SHOULDER_CENTER],CV_RGB(0,255,0));cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_SHOULDER_CENTER] ,pt[NUI_SKELETON_POSITION_SHOULDER_LEFT],CV_RGB(0,255,0));cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_SHOULDER_LEFT],pt[ NUI_SKELETON_POSITION_ELBOW_LEFT],CV_RGB(0,255,0));cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_ELBOW_LEFT],pt[NUI _SKELETON_POSITION_WRIST_LEFT],CV_RGB(0,255,0));cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_WRIST_LEFT],pt[NUI_ SKELETON_POSITION_HAND_LEFT],CV_RGB(0,255,0));cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_HIP_CENTER],pt[NUI_ SKELETON_POSITION_HIP_RIGHT],CV_RGB(0,255,0));cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_HIP_RIGHT],pt[NUI_S KELETON_POSITION_KNEE_RIGHT],CV_RGB(0,255,0));cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_KNEE_RIGHT],pt[NUI_ SKELETON_POSITION_ANKLE_RIGHT],CV_RGB(0,255,0));cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_ANKLE_RIGHT],pt[NU I_SKELETON_POSITION_FOOT_RIGHT],CV_RGB(0,255,0));cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_HIP_CENTER],pt[NUI_ SKELETON_POSITION_HIP_LEFT],CV_RGB(0,255,0));cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_HIP_LEFT],pt[NUI_SK ELETON_POSITION_KNEE_LEFT],CV_RGB(0,255,0));cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_KNEE_LEFT],pt[NUI_S KELETON_POSITION_ANKLE_LEFT],CV_RGB(0,255,0));cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_ANKLE_LEFT],pt[NUI _SKELETON_POSITION_FOOT_LEFT],CV_RGB(0,255,0));m_hint3D[0].x=SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELE TON_POSITION_SHOULDER_CENTER].x;m_hint3D[0].y=SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELE TON_POSITION_SHOULDER_CENTER].y;m_hint3D[0].z=SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELET ON_POSITION_SHOULDER_CENTER].z;m_hint3D[1].x=SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELE TON_POSITION_HEAD].x;m_hint3D[1].y=SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELE TON_POSITION_HEAD].y;m_hint3D[1].z=SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELETON_POSITION_HEAD].z;}}}imshow("skeleton",skeletonMat);waitKey(1);return 0;}int main(int argc,char * argv[]){//初始化NUIHRESULT hr = NuiInitialize(NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX|N UI_INITIALIZE_FLAG_USES_COLOR|NUI_INITIALIZE_FLAG_USES_SKELE TON);if( hr != S_OK ){cout<<"NuiInitialize failed"<<endl;return hr;}//打开KINECT设备的彩色图信息通道h1 = CreateEvent( NULL, TRUE, FALSE, NULL );h2 = NULL;hr = NuiImageStreamOpen(NUI_IMAGE_TYPE_COLOR,NUI_IMAGE_RESOLUTION _640x480, 0, 2, h1, &h2);if( FAILED( hr ) ){cout<<"Could not open image stream video"<<endl;return hr;}h3 = CreateEvent( NULL, TRUE, FALSE, NULL );h4 = NULL;hr = NuiImageStreamOpen( NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX, NUI_IMAGE_RESOLUTION_320x240, 0, 2, h3, &h4);if( FAILED( hr ) ){cout<<"Could not open depth stream video"<<endl;return hr;}h5 = CreateEvent( NULL, TRUE, FALSE, NULL );hr = NuiSkeletonTrackingEnable( h5, 0 );if( FAILED( hr ) ){cout<<"Could not open skeleton stream video"<<endl;return hr;}HANDLE hThread1,hThread2,hThread3;hThread1 = CreateThread(NULL,0,VideoFunc,h2,0,NULL);hThread2 = CreateThread(NULL,0,DepthFunc,h4,0,NULL);hThread3 = CreateThread(NULL,0,SkeletonFunc,NULL,0,NULL);m_hint3D[0] = FT_VECTOR3D(0, 0, 0);m_hint3D[1] = FT_VECTOR3D(0, 0, 0);pColorFrame = FTCreateImage();pDepthFrame = FTCreateImage();IFTFaceTracker* pFT = FTCreateFaceTracker();if(!pFT){return -1;// Handle errors}FT_CAMERA_CONFIG myCameraConfig = {640, 480, NUI_CAMERA_COLOR_NOMINAL_FOCAL_LENGTH_IN_PIXELS}; // width, height, focal lengthFT_CAMERA_CONFIG depthConfig;depthConfig.FocalLength = NUI_CAMERA_DEPTH_NOMINAL_FOCAL_LENGTH_IN_PIXELS;depthConfig.Width = 320;depthConfig.Height = 240;//貌似这里一定要填,而且要填对才行!!hr = pFT->Initialize(&myCameraConfig, &depthConfig, NULL, NULL);if( FAILED(hr) ){return -2;// Handle errors}// Create IFTResult to hold a face tracking resultIFTResult* pFTResult = NULL;hr = pFT->CreateFTResult(&pFTResult);if(FAILED(hr)){return -11;}// prepare Image and SensorData for 640x480 RGB imagesif(!pColorFrame){return -12;// Handle errors}// Attach assumes that the camera code provided by the application// is filling the buffer cameraFrameBuffer// pColorFrame->Attach(640, 480, colorBuffer, FTIMAGEFORMAT_UINT8_B8G8R8X8, 640*3);hr = pColorFrame->Allocate(640, 480, FTIMAGEFORMAT_UINT8_B8G8R8X8);if (FAILED(hr)){return hr;}hr = pDepthFrame->Allocate(320, 240, FTIMAGEFORMA T_UINT16_D13P3);if (FAILED(hr)){return hr;}FT_SENSOR_DATA sensorData;sensorData.pVideoFrame = pColorFrame;sensorData.pDepthFrame = pDepthFrame;sensorData.ZoomFactor = 1.0f;POINT point;point.x=0;point.y=0;sensorData.ViewOffset = point;bool isTracked = false;int iFaceTrackTimeCount=0;// Track a facewhile ( true ){// Call your camera method to process IO and fill the camera buffer// cameraObj.ProcessIO(cameraFrameBuffer); // replace with your method if(!isTracked){hr = pFT->StartTracking(&sensorData, NULL, m_hint3D, pFTResult);if(SUCCEEDED(hr) && SUCCEEDED(pFTResult->GetStatus())){isTracked = true;}else{// Handle errorsisTracked = false;}}else{// Continue tracking. It uses a previously known face position,// so it is an inexpensive call.hr = pFT->ContinueTracking(&sensorData, m_hint3D, pFTResult);if(FAILED(hr) || FAILED (pFTResult->GetStatus())){// Handle errorsisTracked = false;}}if(isTracked){printf("被跟踪了!!!!!!!!!!!!!!!\n");IFTModel* ftModel;HRESULT hr = pFT->GetFaceModel(&ftModel);FLOAT* pSU = NULL;UINT numSU;BOOL suConverged;pFT->GetShapeUnits(NULL, &pSU, &numSU, &suConverged);POINT viewOffset = {0, 0};hr = VisualizeFaceModel(pColorFrame, ftModel, &myCameraConfig, pSU, 1.0, viewOffset, pFTResult, 0x00FFFF00);if(FAILED(hr))printf("显示失败!!\n");MattempMat(COLOR_HIGHT,COLOR_WIDTH,CV_8UC4,pColorFrame->GetBuffer()) ;imshow("faceTracking",tempMat);waitKey(1);}//printf("%d\n",pFTResult->GetStatus());// Do something with pFTResult.Sleep(16);iFaceTrackTimeCount++;if(iFaceTrackTimeCount>16*1000)break;// Terminate on some criteria.}// Clean up.pFTResult->Release();pColorFrame->Release();pFT->Release();CloseHandle(hThread1);CloseHandle(hThread2);CloseHandle(hThread3);Sleep(60000);NuiShutdown();return 0;}HRESULT VisualizeFaceModel(IFTImage* pColorImg, IFTModel* pModel, FT_CAMERA_CONFIG const* pCameraConfig, FLOA T const* pSUCoef, FLOAT zoomFactor, POINT viewOffset, IFTResult* pAAMRlt, UINT32 color) {if (!pColorImg || !pModel || !pCameraConfig || !pSUCoef || !pAAMRlt){return E_POINTER;}HRESULT hr = S_OK;UINT vertexCount = pModel->GetV ertexCount();FT_VECTOR2D* pPts2D = reinterpret_cast<FT_VECTOR2D*>(_malloca(sizeof(FT_VECTOR2D) * vertexCount));if (pPts2D){FLOAT *pAUs;UINT auCount;hr = pAAMRlt->GetAUCoefficients(&pAUs, &auCount);if (SUCCEEDED(hr)){FLOAT scale, rotationXYZ[3], translationXYZ[3];hr = pAAMRlt->Get3DPose(&scale, rotationXYZ, translationXYZ);if (SUCCEEDED(hr)){hr = pModel->GetProjectedShape(pCameraConfig, zoomFactor, viewOffset, pSUCoef, pModel->GetSUCount(), pAUs, auCount,scale, rotationXYZ, translationXYZ, pPts2D, vertexCount);if (SUCCEEDED(hr)){POINT* p3DMdl = reinterpret_cast<POINT*>(_malloca(sizeof(POINT) * vertexCount));if (p3DMdl){for (UINT i = 0; i < vertexCount; ++i){p3DMdl[i].x = LONG(pPts2D[i].x + 0.5f);p3DMdl[i].y = LONG(pPts2D[i].y + 0.5f);}FT_TRIANGLE* pTriangles;UINT triangleCount;hr = pModel->GetTriangles(&pTriangles, &triangleCount);if (SUCCEEDED(hr)){struct EdgeHashTable{UINT32* pEdges;UINT edgesAlloc;void Insert(int a, int b){UINT32 v = (min(a, b) << 16) | max(a, b);UINT32 index = (v + (v << 8)) * 49157, i;for (i = 0; i < edgesAlloc - 1 && pEdges[(index + i) & (edgesAlloc - 1)] && v != pEdges[(index + i) & (edgesAlloc - 1)]; ++i){}pEdges[(index + i) & (edgesAlloc - 1)] = v;}} eht;eht.edgesAlloc = 1 << UINT(log(2.f * (1 + vertexCount + triangleCount)) / log(2.f));eht.pEdges = reinterpret_cast<UINT32*>(_malloca(sizeof(UINT32) * eht.edgesAlloc));if (eht.pEdges){ZeroMemory(eht.pEdges, sizeof(UINT32) * eht.edgesAlloc);for (UINT i = 0; i < triangleCount; ++i){eht.Insert(pTriangles[i].i, pTriangles[i].j);eht.Insert(pTriangles[i].j, pTriangles[i].k);eht.Insert(pTriangles[i].k, pTriangles[i].i);}for (UINT i = 0; i < eht.edgesAlloc; ++i){if(eht.pEdges[i] != 0){pColorImg->DrawLine(p3DMdl[eht.pEdges[i] >> 16], p3DMdl[eht.pEdges[i] & 0xFFFF], color, 1);}}_freea(eht.pEdges);}// Render the face rect in magentaRECT rectFace;hr = pAAMRlt->GetFaceRect(&rectFace);if (SUCCEEDED(hr)){POINT leftTop = {rectFace.left, rectFace.top};POINT rightTop = {rectFace.right - 1, rectFace.top};POINT leftBottom = {rectFace.left, rectFace.bottom - 1};POINT rightBottom = {rectFace.right - 1, rectFace.bottom - 1};UINT32 nColor = 0xff00ff;SUCCEEDED(hr = pColorImg->DrawLine(leftTop, rightTop, nColor, 1)) &&SUCCEEDED(hr = pColorImg->DrawLine(rightTop, rightBottom, nColor, 1)) &&SUCCEEDED(hr = pColorImg->DrawLine(rightBottom, leftBottom, nColor, 1)) &&SUCCEEDED(hr = pColorImg->DrawLine(leftBottom, leftTop, nColor, 1));}}_freea(p3DMdl);}else{hr = E_OUTOFMEMORY;}}}}_freea(pPts2D);}else{hr = E_OUTOFMEMORY;}return hr;}。
