自然交互编程入门:创建你的“Hello World”NI应用

自然交互(NI)是一种以人类感官为基础的人机交互概念,主要关注视觉和听觉感官。PrimeSense的NITE™是感知3D世界并将其转化为有意义的数据的中间件,类似于人类的方式。NITE作为感知引擎,理解用户在其环境中的交互,并包含计算机视觉算法。

开始之前

本章提供了一个简单的步骤教程,描述了如何启动一个简单的NITE项目。

首先,需要下载并安装以下软件:

  • OpenNI
  • NITE中间件
  • 传感器相关软件(驱动程序)

本节描述了如何在Windows上设置环境,使用NITE开发自己的应用程序。

要使用NITE创建一个简单项目,请按照以下步骤操作:

  1. 在Visual Studio中创建一个新的项目,或打开一个现有项目,希望在其中使用NITE。
  2. 在Visual Studio菜单中,打开“项目”菜单并选择“项目属性”。
  3. 在“C/C++”部分,找到“附加包含目录”,添加环境变量$(OPEN_NI_INCLUDE)的值(默认位置是C:\Program Files\OpenNI\Include)。同样添加环境变量$(XN_NITE_INSTALL_PATH)后跟\Include的值(默认位置是C:\Program Files\Prime Sense\NITE\Include)。
  4. 在“链接器”部分,找到“附加库目录”,添加环境变量$(OPEN_NI_LIB)的值(默认位置是C:\Program Files\OpenNI\Lib)。同样添加环境变量$(XN_NITE_INSTALL_PATH)后跟\Lib的值(默认位置是C:\Program Files\Prime Sense\NITE\Lib)。
  5. 在“链接器”部分,找到“输入”节点,添加openNI.lib和XnVNITE_1_4_1.lib库到字段中。
  6. 在“调试”部分,找到“工作目录”,添加$(TargetDir)到字段中。这将允许调试应用程序。

虽然Windows和Linux平台包都可以下载,但本文档仅介绍如何在Windows上使用。

实际代码

本节列出了创建“Hello World”NI应用所需的代码部分。

需要包含OpenNI和NITE头文件:

// 通用头文件 #include <stdio.h> // OpenNI头文件 #include <XnOpenNI.h> // NITE头文件 #include <XnVNite.h>

XnOpenNI.h将包含任何所需的OpenNI头文件。XnVNite.h将包含任何所需的NITE头文件。

初始化OpenNI应用程序有两种方式:(i)显式打开传感器并启动流;(ii)隐式使用XML文件。后者允许应用程序更灵活,通过允许在不重新编译应用程序的情况下更改传感器/流。

// 使用xml初始化OpenNI #define SAMPLE_XML_FILE "../Data/Sample-Tracking.xml"

现在将添加应用程序的全局变量。

XnBool g_bQuit = false; XnVSessionManager* g_pSessionManager = NULL; static XnUInt32 g_nWaveCounter = 1;

注意,g_pSessionManager对象也可以是局部变量,但为了简单和更容易的清理,决定将其作为全局变量使用。

在这种情况下,回调函数用于事件处理。就像希望应用程序在鼠标点击或按键时触发处理函数一样。也希望当NI事件发生时,应用程序会触发NI处理函数,即回调函数。

// 会话开始的回调 void XN_CALLBACK_TYPE SessionStart(const XnPoint3D& ptFocusPoint, void* UserCxt) { printf("Session started. Please wave ...\n"); } // 会话结束的回调 void XN_CALLBACK_TYPE SessionEnd(void* UserCxt) { printf("Session ended. Please perform focus gesture to start session\n"); } // 挥手检测的回调 void XN_CALLBACK_TYPE OnWaveCB(void* cxt) { printf("Hello World - Wave number: %d!\n", g_nWaveCounter); if (2 <= g_nWaveCounter) CleanAndExit(); ++g_nWaveCounter; }

在主函数中,将初始化整个OpenNI和NITE组件,并创建一个无限循环,不断从传感器读取数据,NITE将分析这些数据。

首先,需要初始化OpenNI入口点,即xn::Context:

xn::Context context; xn::ScriptNode scriptNode; // 创建上下文 XnStatus rc = context.InitFromXmlFile(SAMPLE_XML_FILE, scriptNode); if (rc != XN_STATUS_OK) { printf("Couldn't initialize: %s\n", xnGetStatusString(rc)); return 1; }

在这里,通过使用位于SAMPLE_XML_FILE路径的XML文件隐式初始化上下文。这样的文件可以在NITE安装文件夹的Data文件夹下找到。

其次,需要初始化NITE入口点,即XnVSessionManager:

// 创建会话管理器 g_pSessionManager = new XnVSessionManager(); if (NULL == g_pSessionManager) { printf("Out of memory\n"); CleanAndExit(); } rc = g_pSessionManager->Initialize(&context, "Click,Wave", "RaiseHand"); if (rc != XN_STATUS_OK) { printf("Error: SessionManager: %s\n", xnGetStatusString(rc)); CleanAndExit(); } // 注册会话回调 g_pSessionManager->RegisterSession(NULL, &SessionStart, &SessionEnd, NULL);

使用可以用于提取深度流的OpenNI上下文初始化会话管理器,并预定义了焦点和快速重新聚焦手势。

在这里,为了开始NI会话,需要执行Wave手势或Click手势。一旦进入NI会话,手将被跟踪,以便检测其他基于手点的手势(控制)。如果由于某种原因跟踪丢失,例如,手离开了视场(FOV),会话将在RaiseHand事件发生时继续,例如,手返回到FOV。

这段代码的最后一部分是注册会话函数回调。这将使能够在屏幕上打印会话开始时(SessionStart())的消息,即用户执行了焦点手势。当会话结束时(SessionEnd()),即没有手点可用并且快速重新聚焦宽限期结束(=默认宽限期时间为15秒)。

现在需要创建并初始化一个检测Wave手势的NITE树。这是一个非常简单的NITE树,只包含一个分支:XnVWaveDetector:

// 初始化并注册wave控制 XnVWaveDetector wd; wd.RegisterWave(NULL, OnWaveCB); g_pSessionManager->AddListener(&wd); // 初始化完成。开始生成 context.StartGeneratingAll();

首先,实例化一个Wave Detector;wd。然后,注册Wave回调函数,一旦检测到wave,该函数将被调用。然后通过将其添加到手点的监听器列表中,将Wave Detector连接到会话管理器。

一旦NITE树完成,可以调用StartGeneratingAll()函数,该函数将开始生成流。

由于希望不断从传感器读取数据并相应地更新NITE组件,需要创建一个无限循环,不断读取传感器流并用它们更新NITE树。

// 主循环 while (!g_bQuit) { context.WaitAnyUpdateAll(); g_pSessionManager->Update(&context); }

NIHelloWorld.zip文件包含一个Windows项目,其中包含本文档中描述的示例代码。

如果有一个与OpenNI兼容的深度传感器,并且已经按照本文档中的说明操作,将能够编译并运行此示例。需要将传感器连接到计算机并运行应用程序。

一旦应用程序运行,站在传感器前约1米到2.5米的距离。执行焦点手势以开始会话;Wave或Click。为了执行Click手势,需要将手向前伸展朝向传感器,然后稍微向后收回手,动作要平滑,如下图所示。

图3-1:“Click”焦点手势

一旦获得了焦点,将收到一个打印的通知,表明它,并且将能够执行Wave手势在屏幕上打印“Hello World”消息。为了退出应用程序,需要执行Wave手势两次。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485