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

使用 Orbbec Astra + Nuitrack(Kinect 替代品) 进行身体跟踪

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2019 年 1 月 28 日

CPOL

8分钟阅读

viewsIcon

18525

今天,我想向大家介绍 Orbbec Astra 传感器和 Nuitrack 身体追踪 SDK。这是一篇面向希望使用新的深度传感器和新的身体追踪 SDK 来开发出色的运动应用程序的软件开发者的深入教程。

引言

微软宣布(并非突然)Kinect 退出市场 后,我一直致力于为我的客户及其业务提供可行的替代方案。我的公司在过去七年里一直致力于开发运动分析应用程序,因此我深知此类项目是多么具有挑战性。

今天,我想向大家介绍 Orbbec Astra 传感器和 Nuitrack 身体追踪 SDK。这是一篇面向希望使用新的深度传感器和新的身体追踪 SDK 来开发出色的运动应用程序的软件开发者的深入教程。我们将开发一个简单的 Windows 应用程序,它将执行以下操作:

  • 可视化并显示深度流
  • 追踪最近的人的骨架
  • 在深度流上方显示人体关节

下面是它的样子

让我们来认识一下 Orbbec Astra 和 Nuitrack!

必备组件

传感器:Orbbec Astra

Orbbec Astra 是一款小巧但功能强大的深度摄像头。它配备了一个 1280×960 的 RGB 彩色摄像头和一个 640×480 的深度摄像头。它仅重 300 克(0.6 磅)。更重要的是,该摄像头只需要一个 USB 2 端口。无需单独供电。

忘掉那个笨重的 Kinect 适配器及其 USB 3 限制吧。Orbbec Astra 和你的笔记本电脑一样便携。

这是其硬件规格表

彩色分辨率 深度分辨率 Range 视场角 麦克风
1920×960 640×480 0.6 – 8.0m(2 – 26 英尺) 60°(水平)x 49.5°(垂直)x 73°(对角线) 2

现在,让我们来认识一下我们将用于检测和追踪人体关节的软件。

SDK:Nuitrack

Nuitrack 是一个跨平台框架,允许我们访问摄像头流并追踪人体。Nuitrack 提供以下流读取器:

Stream 描述
ColorSensor 提供对原始 RGB 颜色数据的访问。
DepthSensor 提供对原始深度数据的访问。
UserTracker 确定属于被追踪玩家的深度点。
SkeletonTracker 提供对人体关节的 3D 和 2D 坐标的访问。

Nuitrack 兼容台式电脑和移动设备。我将在下一篇文章中详细介绍其移动功能。

设置 Astra 和 Nuitrack

在深入开发工作之前,您首先需要在 Windows 计算机上安装正确的软件包。

步骤 1 – Orbbec 驱动程序

首先下载官方的 Orbbec Astra 驱动程序。下载链接可以在 Orbbec 的网站 上找到。如果跳过此步骤,您的摄像头将无法正常工作。

步骤 2 – Nuitrack

现在已安装好摄像头驱动程序,是时候从其官方网站下载 Nuitrack 了。前往 Nuitrack 下载 页面,选择 nuitrack-win32.zipnuitrack-win64.zip。在我的情况下,我使用的是 64 位机器,因此我选择了后者。

下载并解压该软件包到您的计算机上。选择一个容易记住的位置非常重要。您将在下面的第 3 步中使用 Nuitrack 文件夹的位置。在我的情况下,路径是:

C:\Users\Vangos\Desktop\Nuitrack\nuitrack

要开发使用 Nuitrack 的运动追踪应用程序,您还需要下载 Nuitrack SDK。SDK 可以存储在单独的文件夹中。

Nuitrack 是一个付费软件包,但是,您可以免费试用,时间不限。试用版有 3 分钟的时间限制。达到 3 分钟限制后,您需要重新启动应用程序。

Nuitrack 支持各种摄像头,但目前我们将专注于 Orbbec Astra。.

步骤 3 – OpenNI

还记得 OpenNI 吗?OpenNI 是最早用于访问深度摄像头流的开源软件套件之一。Nuitrack 也使用 OpenNI,因此您应该安装附带的 OpenNI 包:

OpenNI-Win64-1.5.7-Dev.msi

步骤 4 – 环境变量

我们快完成了……您的项目将通过我们在第 2 步中指定的路径引用 Nuitrack。该路径应存储在两个环境变量中。

点击 **开始** 按钮,搜索“**环境变量**”。

此时会打开“系统属性”窗口。点击“**环境变量**”按钮,然后导航到 **系统变量** 面板。

添加一个名为 NUITRACK_HOME 的新属性。将其值设置为 Nuitrack SDK 的安装文件夹。

最后,搜索 **Path** 环境变量,然后点击 **编辑**。添加带有“bin”扩展名的 Nuitrack 文件夹。

步骤 5 – 测试!

如果一切操作正确,您应该能够运行一个 Nuitrack 示例。

将 Orbbec Astra 连接到 USB 端口,然后导航到 Nuitrack 安装文件夹。打开“bin”目录(例如,“C:\Users\Vangos\Desktop\Nuitrack\nuitrack\bin”)。然后,双击 nuitrack_c11_sample.exe 来测试摄像头。如果您看到类似这样的内容,恭喜您!

您的摄像头和 SDK 工作正常!

开发身体追踪应用程序

现在让我们进入激动人心的部分。我们将使用 NuitrackUnity3D 来开发我们的第一个身体追踪应用程序。我假设您已经下载了 Nuitrack SDK

启动 Unity 并打开 VicoVRSDK.unitypackage 示例。这将自动启动 Unity3D 并提示您创建一个新项目。

Unity 随后会提示您导入包。您只需要 NuitrackPlugins 文件夹中的内容,但也可以导入所有内容,这样您就可以尝试内置的演示。

要开始,我们将添加一个新的 Unity 场景,其中包含以下组件:

  • 一个 Canvas 元素;这将包含应用程序的用户界面。
  • 一个 RawImage 元素;这将显示深度流的可视化。
  • 17 个 RawImage 元素;每个元素对应一个人体关节。

另外,添加一个 NuitrackSample.cs 脚本,您可以在其中引用以上所有内容。要使用 Nuitrack,您首先需要导入其命名空间:

using nuitrack;

要访问深度和骨骼信息,您需要创建一个 DepthSensor 和一个 SkeletonTracker 对象。

DepthSensor 对象将使我们能够访问原始深度流。原始深度流是一个距离值数组。

SkeletonTracker 对象将允许我们访问身体数据的更高级别表示。

private DepthSensor depthSensor;
private SkeletonTracker skeletonTracker;

在您的 Start() 方法中,初始化 Nuitrack,创建 DepthSensorSkeletonTracker 对象的实例,并订阅它们各自的事件:

private void Start()
{
    Nuitrack.Init();

    depthSensor = DepthSensor.Create();
    depthSensor.OnUpdateEvent += DepthSensor_OnUpdateEvent;

    skeletonTracker = SkeletonTracker.Create();
    skeletonTracker.OnSkeletonUpdateEvent += SkeletonTracker_OnSkeletonUpdateEvent;

    Nuitrack.Run();
}

最后但同样重要的是,调用 Run() 方法。

在您的 OnApplicationQuit() 方法中,请记住释放非托管资源并取消订阅事件:

private void OnApplicationQuit()
{
    if (depthSensor != null)
    {
        depthSensor.OnUpdateEvent -= DepthSensor_OnUpdateEvent;
    }

    if (skeletonTracker != null)
    {
        skeletonTracker.OnSkeletonUpdateEvent -= SkeletonTracker_OnSkeletonUpdateEvent;
    }

    Nuitrack.Release();
}

在您的 Unity Update() 方法中,只需调用 Nuitrack.Update()

private void Update()
{
    Nuitrack.Update();
}

显示深度流

要显示深度流,我们需要对 RawImage 组件的引用。我们还需要一个 Texture2D 对象,它将在每次有新帧可用时更新。原始帧数据将存储在一个简单的字节数组中。为了检查当前帧是否是新帧,我们将保存对其时间戳的引用。

[SerializeField]
private RawImage image;
private Texture2D texture;
private byte[] colorData;
private ulong previousTimestamp;
private readonly ushort MaxDepth = 8000;

将所有内容整合在一起,这是创建深度帧可视化的一种方式:

private void DepthSensor_OnUpdateEvent(ColorFrame frame)
{
    if (frame != null)
    {
        if (frame.Timestamp != previousTimestamp)
        {
            previousTimestamp = frame.Timestamp;

            if (texture == null)
            {
                texture = new Texture2D(frame.Cols, frame.Rows, TextureFormat.RGBA32, false);
                colorData = new byte[frame.Cols * frame.Rows * 4];
                image.texture = texture;
            }

            int index = 0;

            for (int i = 0; i < frame.Rows; i++)
            {
                for (int j = 0; j < frame.Cols; j++)
                {
                    ushort depth = frame[i, j];

                    byte color = (byte)(depth * 255 / MaxDepth);

                    colorData[index + 0] = (byte)(255 * color);
                    colorData[index + 1] = (byte)(255 * color);
                    colorData[index + 2] = 0;
                    colorData[index + 3] = 255;

                    index += 4;
                }
            }

            texture.LoadRawTextureData(colorData);
            texture.Apply();
        }
    }
}

您可以尝试修改字节数组来创建不同颜色的可视化。我选择创建一种蓝色可视化。MaxDepth 值是允许的最大深度(即 8000 毫米;即 8 米;即 26 英尺)。

所有深度值均以 **毫米** 为单位。一毫米约等于 0.039 英寸。Nuitrack 使用公制系统。

追踪用户身体/骨架

到目前为止,我们的应用程序可以显示深度可视化,但无法检测到任何人。让我们转到 SkeletonTracker 的事件处理程序。以下代码片段显示了如何获取被追踪身体的 3D 和 2D 坐标。请记住,Nuitrack 最多可以追踪 6 个人。

private void SkeletonTracker_OnSkeletonUpdateEvent(SkeletonData skeletonData)
{
    if (skeletonData != null)
    {
        Debug.Log("Tracked users: " + skeletonData.NumUsers);

        Skeleton body = skeletonData.Skeletons.Closest();

        if (body != null)
        {
            var head3D = body.Joints[(int)JointType.Head].Real;
            var head2D = depthSensor.ConvertRealToProjCoords(head3D);

            var neck3D = body.Joints[(int)JointType.Neck].Real;
            var neck2D = depthSensor.ConvertRealToProjCoords(neck3D);

            var torso3D = body.Joints[(int)JointType.Torso].Real;
            var torso2D = depthSensor.ConvertRealToProjCoords(torso3D);

            // etc...
         }
   }
}

3D 坐标(X, Y, Z)以毫米为单位。

2D 坐标(X, Y)以像素为单位,在 640×480 深度帧的范围内。

为了检测最近的身体,我创建了一个简单的扩展方法,该方法根据检测到的骨架与传感器的距离降序进行排序。

public static class NuitrackExtensions
{
    public static Skeleton Closest(this Skeleton[] skeletons)
    {
        Skeleton body = null;

        float minDistance = 0f;

        foreach (Skeleton current in skeletons)
        {
            if (body == null)
            {
                body = current;
            }
            else
            {
                float distance = body.Joints[(int)JointType.Waist].Real.Z;

                if (distance < minDistance)
                {
                    minDistance = distance;
                    body = current;
                }
            }
        }

        return body;
    }
}

您可以使用上述信息来更新对应于人体关节的 RawImages 的位置。您也可以在点之间绘制线条。结果如下所示:

在过去的几年里,我帮助了无数公司将运动技术应用到他们的业务中。如果您打算迁移现有的 Kinect 项目,或者只是需要从头开始创建一个运动分析产品,请随时 与我开始合作项目

故障排除

以下是一些关于常见故障的评论。

应用程序无法检测到摄像头。

确保您已从制造商网站安装了摄像头驱动程序。另外,请检查 nuitrack_c11_sample.exe 文件,以确保 Nuitrack 已正确安装。

应用程序在使用过程中在运行时崩溃。

Nuitrack 试用版有 3 分钟的时间限制。这意味着您最多可以测试您的身体追踪应用程序 3 分钟。使用 Nuitrack 试用版的应用程序将在活动 3 分钟后自动崩溃。要分发您的应用程序,您需要购买商业版本。

Unity 2017 错误“PlayerSettings.mobileMTRendering”

Unity 2017 可能会显示以下错误:

Assets/Platform Changer/Editor/PlatformChanger.cs(77,28):
error CS0117:
`UnityEditor.PlayerSettings' does not contain a definition for `mobileMTRendering'

mobileMTRendering 属性丢失。导航到 PlatformManager.cs 文件,并将第 77 行从

PlayerSettings.mobileMTRendering = GetPlatform().multithreadedRendering;

to

PlayerSettings.MTRendering = GetPlatform().multithreadedRendering;

Unity 抛出 ModuleNotInitializedException

ModuleNotInitialized 异常通常意味着没有深度摄像头连接到计算机。如果您的摄像头已连接,则表示 Nuitrack 或驱动程序的安装出现了问题。拔下摄像头,重新安装驱动程序,然后重新插入摄像头。

那么,您喜欢 Orbbec Astra 摄像头吗?您喜欢 Nuitrack SDK 吗?请在下面的评论中告诉我!

下次再见……继续编码!

© . All rights reserved.