使用 Orbbec Astra + Nuitrack(Kinect 替代品) 进行身体跟踪
今天,我想向大家介绍 Orbbec Astra 传感器和 Nuitrack 身体追踪 SDK。这是一篇面向希望使用新的深度传感器和新的身体追踪 SDK 来开发出色的运动应用程序的软件开发者的深入教程。
引言
在 微软宣布(并非突然)Kinect 退出市场 后,我一直致力于为我的客户及其业务提供可行的替代方案。我的公司在过去七年里一直致力于开发运动分析应用程序,因此我深知此类项目是多么具有挑战性。
今天,我想向大家介绍 Orbbec Astra 传感器和 Nuitrack 身体追踪 SDK。这是一篇面向希望使用新的深度传感器和新的身体追踪 SDK 来开发出色的运动应用程序的软件开发者的深入教程。我们将开发一个简单的 Windows 应用程序,它将执行以下操作:
- 可视化并显示深度流
- 追踪最近的人的骨架
- 在深度流上方显示人体关节
下面是它的样子
让我们来认识一下 Orbbec Astra 和 Nuitrack!
必备组件
- Orbbec Astra 或 Orbbec Astra Pro(也可在亚马逊上购买)
- Nuitrack 身体追踪 SDK
- Unity3D 5.5+
- Visual Studio 2017
- Windows 10
传感器: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.zip 或 nuitrack-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 工作正常!
开发身体追踪应用程序
现在让我们进入激动人心的部分。我们将使用 Nuitrack
和 Unity3D 来开发我们的第一个身体追踪应用程序。我假设您已经下载了 Nuitrack SDK。
启动 Unity 并打开 VicoVRSDK.unitypackage
示例。这将自动启动 Unity3D 并提示您创建一个新项目。
Unity 随后会提示您导入包。您只需要 Nuitrack 和 Plugins 文件夹中的内容,但也可以导入所有内容,这样您就可以尝试内置的演示。
要开始,我们将添加一个新的 Unity 场景,其中包含以下组件:
- 一个
Canvas
元素;这将包含应用程序的用户界面。 - 一个
RawImage
元素;这将显示深度流的可视化。 - 17 个
RawImage
元素;每个元素对应一个人体关节。
另外,添加一个 NuitrackSample.cs 脚本,您可以在其中引用以上所有内容。要使用 Nuitrack
,您首先需要导入其命名空间:
using nuitrack;
要访问深度和骨骼信息,您需要创建一个 DepthSensor
和一个 SkeletonTracker
对象。
DepthSensor
对象将使我们能够访问原始深度流。原始深度流是一个距离值数组。
SkeletonTracker
对象将允许我们访问身体数据的更高级别表示。
private DepthSensor depthSensor;
private SkeletonTracker skeletonTracker;
在您的 Start()
方法中,初始化 Nuitrack
,创建 DepthSensor
和 SkeletonTracker
对象的实例,并订阅它们各自的事件:
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 吗?请在下面的评论中告诉我!
下次再见……继续编码!