65.9K
CodeProject 正在变化。 阅读更多。
Home

如何使用Kinect面部追踪SDK

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.69/5 (6投票s)

2012 年 5 月 31 日

CPOL

7分钟阅读

viewsIcon

144551

本文介绍如何在Windows应用程序中使用Kinect的面部追踪SDK

引言

本文演示了如何在Kinect for Windows中使用面部追踪SDK来追踪人脸。文章提供了代码示例以及有关如何调用其API以充分利用面部追踪引擎的实用技巧。

背景

面部追踪SDK是Kinect for Windows开发者工具包的一部分,可以从此网站安装。它可以与连接到PC的Kinect摄像头一起,对人脸进行无标记追踪。面部追踪引擎会计算语义面部特征点的3D位置以及3D头部姿态。面部追踪SDK可用于驱动虚拟化身、识别面部表情、自然用户界面和其他与面部相关的计算机视觉任务。

完整的API参考可在MSDN网站上找到,作为Kinect for Windows SDK帮助的一部分。我曾参与面部追踪引擎及其API的开发,因此可以提供对其使用情况的良好概述。您也可以在我网站的这篇帖子中找到通用概述和一些使用技巧。

在代码中使用面部追踪SDK

如果您安装了Kinect for Windows开发者工具包1.5,就可以在程序中使用面部追踪SDK。安装后,请转到提供的示例,并运行/构建“Face Tracking Visualization”C++示例或“Face Tracking Basics-WPF”C#示例。您需要将Kinect摄像头连接到PC。面部追踪引擎每帧追踪面部的时间为4-8毫秒,具体取决于您的PC资源。它在CPU上进行计算(不使用GPU)。

这张图片展示了面部追踪的结果。黄色蒙版是拟合到RGB帧中的人脸的3D蒙版。

此视频展示了面部追踪功能、支持的运动范围以及一些限制。

为了使用面部追踪引擎,请在您的代码中包含以下头文件

// Include the main Kinect SDK .h file
#include "NuiAPI.h"

// Include the Face Tracking SDK .h file
#include "FaceTrackLib.h"

您还需要链接提供的FaceTrackLib.lib库,该库将在运行时加载FaceTrackLib.dllFaceTrackData.dll。这些DLL必须位于可执行文件的当前工作目录或全局可搜索路径中。

面部追踪引擎API与DirectX API及其COM接口类似。要创建一个面部追踪器实例,请执行以下操作:

// Create an instance of a face tracker
IFTFaceTracker* pFT = FTCreateFaceTracker();
if(!pFT)
{
    // Handle errors
}

FTCreateFaceTracker()方法创建一个面部追踪器实例并返回其IFTFaceTracker COM接口。

接下来,您需要使用Kinect摄像头配置参数来初始化创建的面部追踪器。Kinect有两个摄像头 - 视频摄像头和深度/红外摄像头,因此需要将两个摄像头的配置都传递给面部追踪器的Initialize()方法。面部追踪器使用这两个摄像头来提高面部追踪的准确性。摄像头配置参数必须精确,因此最好使用NuiAPI.h Kinect头文件中定义的常量。您可以将Kinect摄像头与外部高清摄像头结合使用以提高精度和范围。在这种情况下,您需要在摄像头配置结构中传递正确的焦距和分辨率参数。此外,如果您使用外部摄像头,则需要提供一个深度帧到视频帧的映射函数,因为默认的Kinect函数仅适用于Kinect摄像头。

要初始化面部追踪器实例,请执行以下操作:

// Video camera config with width, height, focal length in pixels
// NUI_CAMERA_COLOR_NOMINAL_FOCAL_LENGTH_IN_PIXELS focal length is computed for 640x480 resolution
// If you use different resolutions, multiply this focal length by the scaling factor
FT_CAMERA_CONFIG videoCameraConfig = {640, 480, NUI_CAMERA_COLOR_NOMINAL_FOCAL_LENGTH_IN_PIXELS};

// Depth camera config with width, height, focal length in pixels
// NUI_CAMERA_COLOR_NOMINAL_FOCAL_LENGTH_IN_PIXELS focal length is computed for 320x240 resolution
// If you use different resolutions, multiply this focal length by the scaling factor
FT_CAMERA_CONFIG depthCameraConfig = {320, 240, NUI_CAMERA_DEPTH_NOMINAL_FOCAL_LENGTH_IN_PIXELS};

// Initialize the face tracker
HRESULT hr = pFT->Initialize(&videoCameraConfig, &depthCameraConfig, NULL, NULL);
if( FAILED(hr) )
{
    // Handle errors
}

此外,您还需要创建一个面部追踪结果对象实例,该对象用于接收3D追踪结果,如下所示:

// Create a face tracking result interface
IFTResult* pFTResult = NULL;
hr = pFT->CreateFTResult(&pFTResult);
if(FAILED(hr))
{
    // Handle errors
}

面部追踪SDK提供了一个IFTImage接口,它可以包装现有的RGB/深度数据缓冲区,也可以管理自己的内存。如果您包装了缓冲区,则需要用Kinect摄像头的RGB和深度数据填充它们。如果您让IFTImage拥有自己的内存,则需要用相应Kinect摄像头的视频和深度帧数据填充其内存。面部追踪SDK要求您同时传递视频和深度帧来追踪面部。两个帧必须同步,即在大致相同的时间从Kinect API读取。

以下是如何将IFTImage接口“附加”到现有的视频和深度缓冲区,然后将它们传递给FT_SENSOR_DATA结构,该结构稍后用作追踪函数的输入参数:

// Prepare image interfaces that hold RGB and depth data
IFTImage* pColorFrame = FTCreateImage();
IFTImage* pDepthFrame = FTCreateImage();
if(!pColorFrame || !pDepthFrame)
{
    // Handle errors
}

// Attach created interfaces to the RGB and depth buffers that are filled with
// corresponding RGB and depth frame data from Kinect cameras
pColorFrame->Attach(640, 480, colorCameraFrameBuffer, FTIMAGEFORMAT_UINT8_R8G8B8, 640*3);
pDepthFrame->Attach(320, 240, depthCameraFrameBuffer, FTIMAGEFORMAT_UINT16_D13P3, 320*2);
// You can also use Allocate() method in which case IFTImage interfaces own their memory.
// In this case use CopyTo() method to copy buffers

FT_SENSOR_DATA sensorData;
sensorData.pVideoFrame = &colorFrame;
sensorData.pDepthFrame = &depthFrame;
sensorData.ZoomFactor = 1.0f;       // Not used must be 1.0
sensorData.ViewOffset = POINT(0,0); // Not used must be (0,0)

请注意,您需要在Attach()中传递正确的视频和深度数据的图像格式以及帧分辨率。当前版本的Kinect for Windows支持多种分辨率,但对于面部追踪SDK来说,最佳分辨率是640x480视频和320x240深度,因为它为该任务提供了帧率和质量的最佳组合。

接下来,您可以调用StartTracking()ContinueTracking()方法来对给定的视频和深度帧组合执行实际的面部追踪。StartTracking()会启动一个追踪会话,并且必须首先调用。由于它会在传递的RGB帧中搜索人脸,因此这是一个耗时的函数。如果StartTracking()调用成功,则可以调用ContinueTracking()以在连续帧上继续追踪已识别的人脸。如果在输入帧之间存在大的时间间隔,ContinueTracking()可能会失败(面部位置之间的距离太大)。在这种情况下,您只能调用StartTracking(),因为它不使用之前的人脸位置。这在摄像头帧率较低时可能很有用。

以下是如何组织主追踪循环的示例:

bool isFaceTracked = false;

// Track a face
while ( true )
{
    // Call Kinect API to fill 
    // videoCameraFrameBuffer and depthFrameBuffer 
    // with RGB and depth data
    ProcessKinectIO();

    // Check if we are already tracking a face
    if(!isFaceTracked)
    {
        // Initiate face tracking.
        // This call is more expensive and searches over the input RGB frame for a face.
        hr = pFT->StartTracking(&sensorData, NULL, NULL, pFTResult);
        if(SUCCEEDED(hr) && SUCCEEDED(pFTResult->Status))
        {
            isFaceTracked = true;
        }
        else
        {
            // No faces found
            isFaceTracked = false;
        }
    }
    else
    {
        // Continue tracking. It uses a previously known face position.
        // This call is less expensive than StartTracking()
        hr = pFT->ContinueTracking(&sensorData, NULL, pFTResult);
        if(FAILED(hr) || FAILED (pFTResult->Status))
        {
            // Lost the face
            isFaceTracked = false;
        }
    }

    // Do something with pFTResult like visualize the mask, drive your 3D avatar,
    // recognize facial expressions
}

此循环包括:

  • 从Kinect摄像头API读取输入帧
  • 将输入帧传递给面部追踪引擎
  • 检查结果

所有面部追踪API都是同步的,因此您需要相应地安排工作。

最后,您需要释放所有面部追踪接口。这将释放其所有分配的内存。

// Clean up
pFTResult->Release();
pColorFrame->Release();
pDepthFrame->Release();
pFT->Release();

关于面部追踪API的一些重要注意事项:

面部追踪器有两种操作模式:一种是带有关节信息,另一种是不带。第一种模式下,您将一个包含两个头部点的数组传递给StartTracking/ContinueTracking方法。这些头部点是Kinect API返回的NUI_SKELETON_DATA结构中包含的头部骨骼的末端。此头部骨骼由NUI_SKELETON_POSITION_INDEX枚举的NUI_SKELETON_POSITION_HEAD成员索引。第一个头部点是颈部位置,第二个头部点是头部位置。这些点可以使面部追踪器更快、更容易地找到人脸,因此这种模式在计算资源方面更经济(有时在头部大幅旋转时更可靠)。第二种模式只需要传递彩色帧+深度帧,并可选择传递一个感兴趣区域参数,该参数告诉面部追踪器在RGB帧中搜索用户面部的区域。如果未传递感兴趣区域(传递为NULL),则面部追踪器将尝试在整个RGB帧中查找人脸,这是StartTracking()方法最慢的操作模式。ContinueTracking()将使用之前找到的人脸,因此速度要快得多。

摄像头配置结构 - 在其中传递正确的参数(如帧宽度、高度以及相应的像素焦距)非常重要。API不会自动从Kinect摄像头API读取这些信息,以赋予更高级用户更大的灵活性。如果您未将其初始化为正确的值(Kinect SDK头文件为Kinect摄像头提供了默认值),追踪精度将受到影响,或者追踪将完全失败。

3D结果的参考系 - 面部追踪SDK同时使用深度和彩色数据,因此3D面部追踪结果的参考系是视频摄像头空间(由于某些优势)。这是一个右手坐标系,Z轴指向被追踪者,Y轴指向上方。测量单位是米。Kinect的骨骼参考系相同,但其原点和轴方向与深度摄像头空间对齐!在线文档中有一个示例描述了如何从彩色摄像头空间转换为深度摄像头空间。

几件可能影响追踪准确性的事情::

  1. 光照 - 人脸应光照良好,没有过多的阴影。明亮的背光或侧光可能会导致追踪效果变差。
  2. 与Kinect摄像头的距离 - 离摄像头越近,追踪效果越好。当您离摄像头小于1.5米(4.9英尺)时,追踪质量最佳。在近距离,Kinect的深度数据更精确,因此面部追踪引擎可以更准确地计算人脸的3D点。
  3. 遮挡 - 如果您戴着厚眼镜或留着像林肯一样的胡子,可能会在面部追踪时遇到问题。这仍然是一个有待改进的领域。人脸颜色不是问题,正如您可以在此视频中看到的。
  4. 祝您面部追踪SDK使用愉快!

历史

  • [2012年5月]:初始版本
© . All rights reserved.