Kinect 开发 —— 面部追踪
SDK1.5中新增了人脸识别类库:Microsoft.Kinect.Toolkit.FaceTracking使得在Kinect中进行人脸识别变得简单,该类库的源代码也在Developer Toolkit中。在Developer Toolkit中也自带人脸识别的例子,您也可以打开运行或者查看源代码。

开发前准备
要使用面部追踪功能,Kinect SDK版本应该至少是1.5,最新版本为1.6,您可以参考之前的那篇文章下载安装,Kinect SDK 和 Kinect Developer Toolkit要一起安装,我的机器上装的是最新的SDK1.6版本。
安装Kinect Developer Toolkit会安装Kinect Studio、一些C#/VB.Net/C++的应用程序示例、源码以及两个用于面部追踪的类库FaceTrackData.dll ,FaceTrackLib.dll包括32位和64位版本,安装好了之后,这些dll应该都在该目录下面 :
如果用C++开发的话,可以直接在项目中使用着两个dll,否则,如果使用.NET开发的话,还需要将这些dll包装成托管代码。
幸运的是, Developer Toolkit中提供了两个使用.NET来实现面部追踪的代码,我们可以直接使用其替我们包装好了dll,该类库的源码也可以看到。 打开Developer Toolkit Browser 找到Component示例,然后安装,之后浏览所在目录,应该能够找到下面两个dll,不安装也可以,您也可以直接到SDK目录中查找这两个dll,在我的及其上目录为C:\Program Files\Microsoft SDKs\Kinect\Developer Toolkit v1.6.0\Samples\bin:
- Microsoft.Kinect.Toolkit
- Microsoft.Kinect.Toolkit.FaceTracking
这两个dll的源码可以在示例中找到,引用了这两个dll之后,还需要将FaceTrackData.dll和FaceTrackLib.dll拷贝到项目中,并保证他和exe在同一个目录下面。
创建WPF项目
新建一个名为KinectFaceTracking的WPF项目,然后引用Microsoft.Kinect ,Microsoft.Kinect.Toolkit.FaceTracking 和Microsoft.Kinect.Toolkit这三个dll
要使用面部追踪,在开启KinectSensor之后需要启用ColorImageStream, DepthImageStream 和SkeletonStream这三个Stream,部分代码如下:
//启用必要的三个Stream
kinectSensor.ColorStream.Enable();
kinectSensor.DepthStream.Enable(DepthImageFormat.Resolution80x60Fps30); kinectSensor.SkeletonStream.TrackingMode = SkeletonTrackingMode.Seated;
kinectSensor.SkeletonStream.Enable(new TransformSmoothParameters() { Correction = 0.5f, JitterRadius = 0.05f, MaxDeviationRadius = 0.05f, Prediction = 0.5f, Smoothing = 0.5f }); // 监听流事件.
kinectSensor.AllFramesReady +=kinectSensor_AllFramesReady; // 初始化数据
colorPixelData = new byte[kinectSensor.ColorStream.FramePixelDataLength];
depthPixelData = new short[kinectSensor.DepthStream.FramePixelDataLength];
skeletonData = new Skeleton[]; //打开Kinect
kinectSensor.Start(); //初始化人脸识别
faceTracker = new FaceTracker(kinectSensor);
前面的代码应该都好懂,值得一提的是最后一句,初始化FaceTracker 对象。在初始化景深数据流时,我们使用最低分辨率的景深影像数据流,这样fps会更高,使得结果更加流畅. 最后,我们注册了AllFramesReady事件。
获取面部数据
在Developer Toolkit中,脸部数据帧使用FaceTrackFrame表示。 为了获取数据,我们需要调用FaceTracker对象的Track方法并传入我们从Kinect中获取的数据,然后FaceTracker对象会对这些数据进行处理来进行面部追踪,部分代码如下:
// 获取每一帧数据,然后存储到变量中来
using (ColorImageFrame colorImageFrame = e.OpenColorImageFrame())
{
if (colorImageFrame == null)
return;
colorImageFrame.CopyPixelDataTo(colorPixelData);
} using (DepthImageFrame depthImageFrame = e.OpenDepthImageFrame())
{
if (depthImageFrame == null)
return;
depthImageFrame.CopyPixelDataTo(depthPixelData);
} using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
{
if (skeletonFrame == null)
return;
skeletonFrame.CopySkeletonDataTo(skeletonData);
} //获取处于跟踪状态的骨骼数据对象,如果没有,则返回.
var skeleton = skeletonData.FirstOrDefault(s => s.TrackingState == SkeletonTrackingState.Tracked);
if (skeleton == null)
return;
前面的都是数据准备阶段,一旦数据都获取了之后,我们使用FaceTracker对象来对这些数据进行识别,提取面部信息。
// 面部追踪
FaceTrackFrame faceFrame = faceTracker.Track(kinectSensor.ColorStream.Format,
colorPixelData,
kinectSensor.DepthStream.Format,
depthPixelData,
skeleton);
faceFrame是一个FaceTrackFrame类型的变量,代表面部追踪的处理结果,该对象的更详细信息,您可以查看 MSDN,下面是该对象的OMD图
首先,TrackSuccessful 属性只是是否识别出了面部,FaceRect是面部所在的矩形区域,最重要的是下面的几个方法:这些方法可以提供最多87个点来表示面部信息,这些点可以以二维或者三维的形式提供。我们可以提取一些用户的面部表情信息:
- Get3DShape() 方法返回三维表示的121个点集合.
- GetProjected3DShape() 方法返回同样数目的以二维形式展现的点的集合,这些点映射到640×480像素的图像上.
- GetAnimationUnitCoefficients() 返回面部表情的描述值,在下面我们会用到这个值来绘制人物图像.更多的信息,您可以查看 Animation Units on MSDN.
- GetTriangles() 该方法可以 和Get3DShape 方法一起使用. 他返回一个三角形集合,集合中的每个三角形的顶点都是由Get3DShape 中的点组成。这些三角形可以用来进行3D建模,就像Developer Toolkit自带例子中的那样,我们可以用它来对整个面部进行动态建模。
绘制面部
有了数据之后,我们可以在WPF中用XAML来绘制一个简单的人脸了。在绘制过程中,我们会使用一些变换Transformations (Translations, Rotations, Scales, …) 来表示人的表情的变化,比如说RenderTransform对象可以用来改变对象的渲染方式,我们使用一个Ellipse 对象来代表嘴巴 (Ellipse with x:Name=”Mouth”) :他有一个 ScaleTransform属性,我们可以使用它来改变X轴和Y轴上的缩放,来模拟口型的变化,眉头的模拟也是如此。
<Window x:Class="KinectFaceTracking.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="" Width="">
<Grid>
<Grid>
<Canvas x:Name="MainCanvas" Width="" Height="">
<Canvas.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="CanvasRotate" CenterX="" CenterY="" /> <!--<TranslateTransform x:Name="CanvasTranslate" />-->
</TransformGroup>
</Canvas.RenderTransform> <Ellipse Width="" Height="" x:Name="Face" StrokeThickness="" Stroke="Black" Canvas.Left="" Canvas.Top="" />
<Ellipse Width="" Height="" x:Name="LeftEye" Stroke="Black" StrokeThickness="" Canvas.Left="" Canvas.Top="" />
<Ellipse Canvas.Left="" Canvas.Top="" x:Name="RightEye" Height="" Stroke="Black" StrokeThickness="" Width="" />
<Ellipse Canvas.Left="" Canvas.Top="" Height="" x:Name="Mouth" Stroke="Black" StrokeThickness="" Width="" >
<Ellipse.RenderTransform>
<ScaleTransform x:Name="MouthScaleTransform" CenterX="" CenterY="" ScaleX="" ScaleY=""/>
</Ellipse.RenderTransform>
</Ellipse> <!--<Ellipse Canvas.Left="" Canvas.Top="" Height="" x:Name="Nose" Stroke="Black" StrokeThickness="" Width="" />-->
<Rectangle Width="" Stroke="Black" Fill="Black" StrokeThickness="" Height="" Canvas.Left="" Canvas.Top="">
<Rectangle.RenderTransform>
<TransformGroup>
<TranslateTransform x:Name="RightBrow" />
<RotateTransform x:Name="RightBrowRotate" CenterX="" Angle="" />
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle> <Rectangle Width="" Stroke="Black" Fill="Black" StrokeThickness="" Height="" Canvas.Left="" Canvas.Top="" >
<Rectangle.RenderTransform>
<TransformGroup>
<TranslateTransform x:Name="LeftBrow" />
<RotateTransform x:Name="LeftBrowRotate" CenterX="" Angle="" />
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Left="" Canvas.Top="" Fill="Black" Height="" Stroke="Black" StrokeThickness="" Width="">
<Rectangle.RenderTransform>
<TransformGroup>
<RotateTransform Angle="-70" CenterX="" />
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Left="" Canvas.Top="" Fill="Black" Height="" Stroke="Black" StrokeThickness="" Width="">
<Rectangle.RenderTransform>
<TransformGroup>
<RotateTransform Angle="" CenterX="" />
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
</Canvas>
</Grid>
</Grid>
</Window>
完成之后,一个简单的人脸就绘制完成了,如下:

将数据和表情绑定
现在表情绘制完成,我们只需要使用面部追踪的数据来改变各部分的动画参数就可以模拟脸部表情了。
获取数据之前,我们需要检查是否识别出来了脸部。如果识别出来人脸,我们就接着获取动画单位系数(Animation Units coefficients). 这个参数可以告诉哦我们被追踪对象嘴巴是张开还是合拢,还是在笑,眉头紧锁还是笑颜逐开等等…
//如果识别出来,进行进一步处理
if (faceFrame.TrackSuccessful)
{
// 获取动画单位系数 Animation Units coeffs.
var AUCoeff = faceFrame.GetAnimationUnitCoefficients(); var jawLowerer = AUCoeff[AnimationUnit.JawLower];
jawLowerer = jawLowerer < ? : jawLowerer;
MouthScaleTransform.ScaleY = jawLowerer * + 0.1;
MouthScaleTransform.ScaleX = (AUCoeff[AnimationUnit.LipStretcher] + ); LeftBrow.Y = RightBrow.Y = (AUCoeff[AnimationUnit.BrowLower]) * ; RightBrowRotate.Angle = (AUCoeff[AnimationUnit.BrowRaiser] * );
LeftBrowRotate.Angle = -RightBrowRotate.Angle; CanvasRotate.Angle = faceFrame.Rotation.Z;
}
上面的动画参数的取值范围都是在-1和1之间。到这里一个简单的面部追踪小程序就完成了,您可以对着Kinect做一些表情试一试变化。下面是我做的一些截图:

Kinect 开发 —— 面部追踪的更多相关文章
- Kinect 开发 —— 骨骼追踪进阶(上)
Kinect传感器核心只是发射红外线,并探测红外光反射,从而可以计算出视场范围内每一个像素的深度值.从深度数据中最先提取出来的是物体主体和形状,以及每一个像素点的游戏者索引信息.然后用这些形状信息来匹 ...
- Kinect 开发 —— 骨骼追踪(下)
Kinect 连线游戏 在纸上将一些列数字(用一个圆点表示)从小到大用线连起来.游戏逻辑很简单,只不过我们在这里要实现的是动动手将这些点连起来,而不是用笔或者鼠标. 在开始写代码之前,需要明确定义我们 ...
- Kinect 开发 —— 骨骼追踪
骨骼追踪技术通过处理景深数据来建立人体各个关节的坐标,骨骼追踪能够确定人体的各个部分,如那部分是手,头部,以及身体.骨骼追踪产生X,Y,Z数据来确定这些骨骼点.骨骼追踪系统采用的景深图像处理技术使用更 ...
- Kinect 开发 —— 骨骼追踪 (下)
基于景深数据的用户交互 骨骼数据中关节点不仅有X,Y值,还有一个深度值 除了使用WPF的3D特性外,在布局系统中可以根据深度值来设定可视化元素的尺寸大小来达到某种程序的立体效果. 下面的例子使用Can ...
- Kinect开发文章目录
整理了一下去年为止到现在写的和翻译的Kinect的相关文章,方便大家查看.另外,最近京东上微软在搞活动, 微软 Kinect for Windows 京东十周年专供礼包 ,如果您想从事Kinect开发 ...
- Kinect开发笔记之二Kinect for Windows 2.0新功能
这是本博客翻译文档的第一篇文章.笔者已经苦逼的竭尽全力的在翻译了.但无奈英语水平也是非常有限.不正确或者不妥当不准确的地方必定会有,还恳请大家留言或者邮件我以批评指正.我会虚心接受. 谢谢大家. ...
- Kinect 开发 —— 杂一
Kinect 提供了非托管(C++)和托管(.NET)两种开发方式的SDK,如果您用C++开发的话,需要安装Speech Runtime(V11),Kinect for Windows Runtime ...
- Kinect 开发 —— 全息图
Kinect的另一个有趣的应用是伪全息图(pseudo-hologram).3D图像可以根据人物在Kinect前面的各种位置进行倾斜和移动.如果方法够好,可以营造出3D控件中3D图像的效果,这样可以用 ...
- Kinect 开发 —— ColorBasic
创建一个Kincet项目通常需要: 1. 创建一个VS项目,一般为了展示通常创建一个wpf项目. 2. 添加Microsoft.Kinect.dll引用,如果是早期版本的SDK,这个名称可能不同. 3 ...
随机推荐
- 认识javascript的引擎之--1
前言: 一:每一款浏览器里面都能执行js脚本,那是因为制造商在浏览器里面加入了js引擎.也就是说js引擎在浏览器里面占有一席之地. 1.开始的时候js处于沉睡状态,直到运行页面遇到 <scrip ...
- angularjs 学习理解
1AngularJS 是一个 JavaScript 框架.它是一个以 JavaScript 编写的库. 2 ng-app 指令定义一个 AngularJS 应用程序.ng-model 指令把元素值(比 ...
- hive parquet table 配置使用压缩
创建parquet table : create table mytable(a int,b int) STORED AS PARQUET; 创建带压缩的parquet table: create t ...
- bzoj 3408 热浪 最短路
一道最短路的模板题,就当练习一下SPFA和dijkstra了 SPFA #include<bits/stdc++.h> using namespace std; struct edge{ ...
- 常用模块(hashlib、suprocess、configparser)
hashlib模块 hash是一种接受不了内容的算法,(3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法),该算 ...
- 参考《深度学习之PyTorch实战计算机视觉》PDF
计算机视觉.自然语言处理和语音识别是目前深度学习领域很热门的三大应用方向. 计算机视觉学习,推荐阅读<深度学习之PyTorch实战计算机视觉>.学到人工智能的基础概念及Python 编程技 ...
- HDU 4906 Our happy ending
题意: Given a sequence a_1,a_2,...,a_n, if we can take some of them(each a_i can only be used once), a ...
- 【Codeforces Round #462 (Div. 1) A】 A Twisty Movement
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] ans初值值为a[1..n]中1的个数. 接下来考虑以2为结尾的最长上升子序列的个数. 枚举中间点i. 计算1..i-1中1的个数c ...
- cxf 实例解读
1.sample 实例之一---java_first_pojo 服务端发布服务的方法: 1 HelloWorldImpl helloworldImpl = new HelloWorldImpl(); ...
- 设计模式之Flyweight模式(笔记)
享元模式:运用共享技术有效地支持大量细粒度的对象. 适用场合:假设一个应用程序适用了大量的对象.而大量的这些对象造成了非常大的存储开销时就应该考虑使用. 首先定义一个IFlyweight接口 publ ...


