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 开发 —— 面部追踪的更多相关文章

  1. Kinect 开发 —— 骨骼追踪进阶(上)

    Kinect传感器核心只是发射红外线,并探测红外光反射,从而可以计算出视场范围内每一个像素的深度值.从深度数据中最先提取出来的是物体主体和形状,以及每一个像素点的游戏者索引信息.然后用这些形状信息来匹 ...

  2. Kinect 开发 —— 骨骼追踪(下)

    Kinect 连线游戏 在纸上将一些列数字(用一个圆点表示)从小到大用线连起来.游戏逻辑很简单,只不过我们在这里要实现的是动动手将这些点连起来,而不是用笔或者鼠标. 在开始写代码之前,需要明确定义我们 ...

  3. Kinect 开发 —— 骨骼追踪

    骨骼追踪技术通过处理景深数据来建立人体各个关节的坐标,骨骼追踪能够确定人体的各个部分,如那部分是手,头部,以及身体.骨骼追踪产生X,Y,Z数据来确定这些骨骼点.骨骼追踪系统采用的景深图像处理技术使用更 ...

  4. Kinect 开发 —— 骨骼追踪 (下)

    基于景深数据的用户交互 骨骼数据中关节点不仅有X,Y值,还有一个深度值 除了使用WPF的3D特性外,在布局系统中可以根据深度值来设定可视化元素的尺寸大小来达到某种程序的立体效果. 下面的例子使用Can ...

  5. Kinect开发文章目录

    整理了一下去年为止到现在写的和翻译的Kinect的相关文章,方便大家查看.另外,最近京东上微软在搞活动, 微软 Kinect for Windows 京东十周年专供礼包 ,如果您想从事Kinect开发 ...

  6. Kinect开发笔记之二Kinect for Windows 2.0新功能

    这是本博客翻译文档的第一篇文章.笔者已经苦逼的竭尽全力的在翻译了.但无奈英语水平也是非常有限.不正确或者不妥当不准确的地方必定会有,还恳请大家留言或者邮件我以批评指正.我会虚心接受. 谢谢大家.   ...

  7. Kinect 开发 —— 杂一

    Kinect 提供了非托管(C++)和托管(.NET)两种开发方式的SDK,如果您用C++开发的话,需要安装Speech Runtime(V11),Kinect for Windows Runtime ...

  8. Kinect 开发 —— 全息图

    Kinect的另一个有趣的应用是伪全息图(pseudo-hologram).3D图像可以根据人物在Kinect前面的各种位置进行倾斜和移动.如果方法够好,可以营造出3D控件中3D图像的效果,这样可以用 ...

  9. Kinect 开发 —— ColorBasic

    创建一个Kincet项目通常需要: 1. 创建一个VS项目,一般为了展示通常创建一个wpf项目. 2. 添加Microsoft.Kinect.dll引用,如果是早期版本的SDK,这个名称可能不同. 3 ...

随机推荐

  1. NodeJS学习笔记 进阶 (2)Nodejs进阶:MD5加密算法(ok)

    个人总结:这篇文章讲解了Nodejs中自带模块的MD5加密算法的使用,读完这篇文章需要15分钟,其实还有一个叫utility的包在npm上,也非常好用. 摘选自网络 简介 MD5(Message-Di ...

  2. POJ-1182 食物链 并查集(互相关联的并查集写法)

    题目链接:https://cn.vjudge.net/problem/POJ-1182 题意 中文题目,就不写了哈哈 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃 ...

  3. 用Python定时爬取网站最新资源

    记录一下. 写做个网站,爬了另一个网站的内容来做自己网站的内容. 把脚本挂到服务器,每隔一个小时去爬一次资源,然后保存到一个HTML文件里. 用flask做web对接,当有请求的时候就返回那个HTML ...

  4. RC Immix

    目录 RC Immix 目的 合并型引用计数 伪代码 优点和缺点 合并型引用计数法和Immix的融合 新对象 被动的碎片整理 积极的碎片整理 优点和缺点 优点 缺点 RC Immix Rifat Sh ...

  5. 今日SGU 5.26

    #include<bits/stdc++.h> #define de(x) cout<<#x<<"="<<x<<endl ...

  6. C# http服务器

    Http 服务器搭建 1.新建一个C#控制台工程 2.复制以下代码 using System; using System.Collections.Generic; using System.Linq; ...

  7. 个人学习源码的 HBase误区的总结 与 架构图

    HDFS 的备份功能不是给 基于 HBase 等 基于HDFS 的项目做备份的.   如果 HBase 需要备份,那么久需要设置 备份(快照 )功能.   HMaster . kafka 等无主结构并 ...

  8. silverlight wcf mvvm

    近期工作比較忙.也没有时间发表新内容,今天有点时间,就顺便写点,说说近期开发的一套系统心得. 我刚去这个公司已经将前端确定要用Silverlight,我不知道为什么要选择这个,或许是为以后转C/S系统 ...

  9. easyui combobox 获取焦点

    easyui combobox 获取焦点 学习了:http://blog.csdn.net/foart/article/details/14446809 可以直接用: $('#spanZhudaoci ...

  10. HDU 5379 Mahjong tree dfs+组合数学

    题意:给你一棵树来分配号码,要求是兄弟节点连续并且每一棵子树连续. 思路:因为要求兄弟和子树都是连续的,所以自己打下草稿就可以发现如果一个节点有3个或3个以上的非叶子结点,那么就无论如何也不能达到目的 ...