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[6];

//打开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="350" Width="525">
        <Grid>
            <Grid>
                <Canvas x:Name="MainCanvas" Width="500" Height="500">
                    <Canvas.RenderTransform>
                        <TransformGroup>
                            <RotateTransform x:Name="CanvasRotate" CenterX="250" CenterY="250" />

                            <!--<TranslateTransform x:Name="CanvasTranslate" />-->
                        </TransformGroup>
                    </Canvas.RenderTransform>

                    <Ellipse Width="300" Height="300" x:Name="Face"  StrokeThickness="2" Stroke="Black" Canvas.Left="105" Canvas.Top="6" />
                    <Ellipse Width="30" Height="30" x:Name="LeftEye" Stroke="Black" StrokeThickness="2" Canvas.Left="289" Canvas.Top="102" />
                    <Ellipse Canvas.Left="194" Canvas.Top="102" x:Name="RightEye" Height="30" Stroke="Black" StrokeThickness="2" Width="30" />
                    <Ellipse Canvas.Left="224" Canvas.Top="239" Height="18" x:Name="Mouth" Stroke="Black" StrokeThickness="2" Width="64" >
                        <Ellipse.RenderTransform>
                            <ScaleTransform x:Name="MouthScaleTransform" CenterX="32" CenterY="9" ScaleX="1" ScaleY="1"/>
                        </Ellipse.RenderTransform>
                    </Ellipse>

                    <!--<Ellipse Canvas.Left="244" Canvas.Top="151" Height="53" x:Name="Nose" Stroke="Black" StrokeThickness="2" Width="22" />-->
                    <Rectangle Width="70" Stroke="Black" Fill="Black" StrokeThickness="10" Height="5" Canvas.Left="169" Canvas.Top="80">
                        <Rectangle.RenderTransform>
                            <TransformGroup>
                                <TranslateTransform x:Name="RightBrow" />
                                <RotateTransform x:Name="RightBrowRotate" CenterX="50" Angle="0" />
                            </TransformGroup>
                        </Rectangle.RenderTransform>
                    </Rectangle>

                    <Rectangle  Width="70" Stroke="Black" Fill="Black" StrokeThickness="10" Height="5" Canvas.Left="274" Canvas.Top="80" >
                        <Rectangle.RenderTransform>
                            <TransformGroup>
                                <TranslateTransform x:Name="LeftBrow" />
                                <RotateTransform x:Name="LeftBrowRotate" CenterX="20" Angle="0" />
                            </TransformGroup>
                        </Rectangle.RenderTransform>
                    </Rectangle>
                    <Rectangle Canvas.Left="207" Canvas.Top="148" Fill="Black" Height="5" Stroke="Black" StrokeThickness="10" Width="50">
                        <Rectangle.RenderTransform>
                            <TransformGroup>
                                <RotateTransform Angle="-70" CenterX="50" />
                            </TransformGroup>
                        </Rectangle.RenderTransform>
                    </Rectangle>
                    <Rectangle Canvas.Left="246" Canvas.Top="190" Fill="Black" Height="5" Stroke="Black" StrokeThickness="10" Width="15">
                        <Rectangle.RenderTransform>
                            <TransformGroup>
                                <RotateTransform Angle="0" CenterX="50" />
                            </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 < 0 ? 0 : jawLowerer;
    MouthScaleTransform.ScaleY = jawLowerer * 5 + 0.1;
    MouthScaleTransform.ScaleX = (AUCoeff[AnimationUnit.LipStretcher] + 1);

    LeftBrow.Y = RightBrow.Y = (AUCoeff[AnimationUnit.BrowLower]) * 40;

    RightBrowRotate.Angle = (AUCoeff[AnimationUnit.BrowRaiser] * 20);
    LeftBrowRotate.Angle = -RightBrowRotate.Angle;

    CanvasRotate.Angle = faceFrame.Rotation.Z;
 }

上面的动画参数的取值范围都是在-1和1之间。到这里一个简单的面部追踪小程序就完成了,您可以对着Kinect做一些表情试一试变化。下面是我做的一些截图:

Kinect 开发 —— 面部追踪

时间: 2024-10-11 21:36:04

Kinect 开发 —— 面部追踪的相关文章

Kinect 开发 &mdash;&mdash; 骨骼追踪

骨骼追踪技术通过处理景深数据来建立人体各个关节的坐标,骨骼追踪能够确定人体的各个部分,如那部分是手,头部,以及身体.骨骼追踪产生X,Y,Z数据来确定这些骨骼点.骨骼追踪系统采用的景深图像处理技术使用更复杂的算法如矩阵变换,机器学习及其他方式来确定骨骼点的坐标. 获取骨骼数据 彩色影像数据,景深数据分别来自ColorImageSteam和DepthImageStream,同样地,骨骼数据来自SkeletonStream.访问骨骼数据和访问彩色影像数据.景深数据一样,也有事件模式和 "拉"

Kinect 开发 &mdash;&mdash; 骨骼追踪(下)

Kinect 连线游戏 在纸上将一些列数字(用一个圆点表示)从小到大用线连起来.游戏逻辑很简单,只不过我们在这里要实现的是动动手将这些点连起来,而不是用笔或者鼠标. 在开始写代码之前,需要明确定义我们的游戏目标.连线游戏是一个智力游戏,游戏者需要将数字从小到大连起来.程序可以自定义游戏上面的数字和位置(合称一个关卡).每一个关卡包括一些列的数字(以点表示)及其位置.我们要创建一个DotPuzzle类来管理这些点对象的集合.可能一开始不需要这个类,仅仅需要一个集合就可以,但是为了以后方便添加其他功

Kinect 开发 &mdash;&mdash; 骨骼追踪 (下)

基于景深数据的用户交互 骨骼数据中关节点不仅有X,Y值,还有一个深度值 除了使用WPF的3D特性外,在布局系统中可以根据深度值来设定可视化元素的尺寸大小来达到某种程序的立体效果. 下面的例子使用Canvas.ZIndex属性来设置元素的层次,手动设置控件的大小并使用ScaleTransform来根据深度值的改变来进行缩放.用户界面包括一些圆形,每一个圆代表一定的深度.应用程序跟踪用户的手部关节点,以手形图标显示,图标会根据用户手部关节点的深度值来进行缩放,用户离Kinect越近,手形图表越大,反

【Kinect开发笔记之(二)】Kinect for windows发展历程

新版本SDK和旧版本的SDK完全兼容,如果您之前安装过旧版本的,可以直接安装新版本的SDK,但是如果您之前的开发版本是Beta版的,则需要卸载之后再安装新版本.在Kinect for Windows SDK 1.0版本中,SDK和示例文件是打包一起安装的.而在之后的版本,为了可以分别升级,微软把这两者分开独立为Kinect for Windows SDK和Kinect for Windows Developer Toolkit这两部分,所以需要分别下载安装, Kinect for Windows

Kinect 开发 &mdash;&mdash; 语音识别(下)

使用定向麦克风进行波束追踪 (Beam Tracking for a Directional Microphone) 可以使用这4个麦克风来模拟定向麦克风产生的效果,这个过程称之为波束追踪(beam tracking) 界面上的细长矩形用来指示某一时刻探测到的说话者的语音方向.矩形有一个旋转变换,在垂直轴上左右摆动,以表示声音的不同来源方向. <Rectangle Fill="#1BA78B" HorizontalAlignment="Left" Margin

Kinect 开发 &mdash;&mdash; 姿势识别

姿势和手势通常会混淆,但是他们是两个不同的概念.当一个人摆一个姿势时,他会保持身体的位置和样子一段时间.但是手势包含有动作,例如用户通过手势在触摸屏上,放大图片等操作. 通常,游戏者很容易模仿指定姿势并且比较容易编写算法来识别指定的姿势.例如,如果开发一个用户在天上飞的游戏. 一种控制游戏的方式是,游戏者像鸟一样挥动手臂.挥动的频率越快游戏角色飞的越快,这是一个手势.还有一种方法是,展开双臂,双臂张得越快开,飞的越快.双臂离身体越近,飞的越慢. 身体以及各个关节点的位置定义了一个姿势.更具体的来

Kinect 开发 &mdash;&mdash; 引言

自然人机交互设计技术 (全息三维投影,手势肢体识别,眼动跟踪 ...) 符合人类心理的交互方式 自然用户界面 -- Natural User Interface 有机用户界面 -- Organic User Interface   第六感设备 -- 手势识别,摄像头,投影,云计算 通过对熟知的技术的组合,产生一种NB 的应用               http://www.pranavmistry.com/ 追影技术 -- 用普通摄像头结合运动跟踪算法,实现体感 微软的 CamBot 技术,G

Kinect 开发 &mdash;&mdash; ColorBasic

创建一个Kincet项目通常需要: 1. 创建一个VS项目,一般为了展示通常创建一个wpf项目. 2. 添加Microsoft.Kinect.dll引用,如果是早期版本的SDK,这个名称可能不同. 3. 引入Kinect命名空间. Kinect支持3中类型的托管应用程序,分别是:控制台应用程序,WPF以及Windows Form应用程序. 首先来创建一个Windows 控制台应用程序,然后在Main函数所在的代码中引入Kinect命名控件,代码如下: using Microsoft.Kinect

Kinect 开发 &mdash;&mdash; 杂一

Kinect 提供了非托管(C++)和托管(.NET)两种开发方式的SDK,如果您用C++开发的话,需要安装Speech Runtime(V11),Kinect for Windows Runtime和驱动的,如果您使用C#和VB.NET的话,需要Microsoft.Kinect.dll和Mirosoft.Speech.dll两个dll,这两个其实是对前C++里面的两个dll的.NET封装,不论何种开发,您都需要安装driver,所有这些都包含在Kinect SDK安装包中,安装方法您可以参考之