OpenNI(开放式自然交互)是一个由业界领导的非营利组织,该组织专注于提高和改善自然交互设备,应用软件的互操作能力,通过使用这些硬件和中间件来很方便地访问和使用一些设备。OpenNI是一个开放源码的API,源码公布在www.OpenNI.org.,有兴趣的读者可以自行下载阅读。
3.1.1 OpenNI架构
OpenNI是一个多语言,跨平台的框架,它定义了编写应用程序,并利用其自然交互的API。OpenNI API由一组可用来编写通用自然交互应用的接口组成。OpenNI的主要目的是形成一套标准的API,以用来建立下面两个方面之间的通信桥梁:
·视觉和声音传感器(能够“看到”或者“听到”周围环境的设备);
·视觉和声音的中间件(分析声音和视觉数据,并能够理解的软件组件)。
例如软件接受视觉数据,返回探测到的手在数据中的位置。例如,一个中间件可以接受一幅有人的图像,计算并返回人手掌在图像中的位置,OpenNI提供了一组基于传感器设备的API,以及一组由中间件组件实现的API。通过打破传感器和中间件之间的依赖,使用OpenNI的API编写应用程序就不需要额外努力去处理不同的中间件带来的问题(跨平台)。
OpenNI的API还允许开发人员直接基于最原始的数据格式编写中间件上层的算法,而不用考虑这些数据来自哪个传感器,并且OpenNI的这种机制给了传感器制造商一个充分的自由空间去制造自己的传感器而不用考虑上层OpenNI兼容的应用程序。
OpenNI的API使得自然交互应用开发人员通过传感器输出的标准化了的数据类型来处理真实的三维数据(这些标准化的数据类型可以表示人体的全身,手的位置,或者仅仅是一个含有深度信息的像素图等),编写应用程序时不用考虑传感器或者中间件供应商的相关细节。
图3-1表示1.5版本OpenNI原理的三层视图,每一层代表一种不可或缺的元素。
图3-1 OpenNI架构
·顶层:表示处于OpenNI顶部的执行自然交互的应用软件。
·中间层:表示OpenNI,OpenNI提供与传感器和中间件交互的通信接口,即分析来自传感器的数据。
·底层:表示捕获场景中视频和音频元素的硬件设备。
最上层是应用程序,也就是我们这些程序开发者所需要编写的部分,最下面这一层是硬件部分,目前OpenNI支持的硬件包含了3D Sensor、RGB Camera、Audio Device。而中间一层就是OpenNI部分,除了负责和硬件部分的沟通之外,也在自身内部存在有中间件的空间,可以用来做进一步的数据处理,比如手势识别、追踪等。就1.5版本OpenNI来说,在Middleware部分定义了四种原件,如表3-1所示。
表3-1 Middleware部分定义的四种原件
对于1.5版本的OpenNI来说,PrimeSense已经提供了一套NITE作为最主要的Middleware,并且提供上面所列的所有功能,如果开发者有更进阶的需求,也可以自行写一套相容于OpenNI的Middleware来使用。而目前,对于OpenNI 2.0之后的版本来说,由于OpenNI架构的改变(开放了Middleware部分),所以开发者可选的第三方Middleware更加丰富。第三方Middleware功能也更加全面。
3.1.2 OpenNI支持的模块
何为模块,在OpenNI中,我们把以完成某些同层次功能的集合体称为模块,模块概念的应用使得OpenNI功能的分层更加清晰。在实际OpenNI的框架中,OpenNI是为物理设备和中间件组件提供接口的抽象层,而众多可以完成某项功能的组件会被注册到这个OpenNI框架中,根据这些组件所能完成功能的不同来分类,这些被分类的组件集合称为模块。模块的概念使得OpenNI用于生产和处理感官数据。选择需要的硬件设备组件或中间件组件的时候更加灵活简单。
图3-2所示为OpenNI框架下模块的概念图,清晰地反应了不同模块与OpenNI框架之间的关系。
图3-2 OpenNI模块概念图
传感器模块详细内容如表3-2所示。
表3-2 传感器模块
中间件组件模块详细内容如表3-3所示。
表3-3 中间件组件模块
3.1.3 OpenNI的功能
OpenNI发布了一组特定的功能,并在未来进一步地增加功能选项。当前支持的功能如表3-4所示。
表3-4 OpenNI支持的功能
这些功能在OpenNI中的位置有的是属于上下文对象的功能,有的功能则是挂在每一个生产节点下的,不同的生产节点可以有相同的功能,不过不同的生产节点也都有其特定的功能。表3-5直观地描述了这些生成器下的特定功能。
表3-5 各生成器下的特定功能
3.1.4 OpenNI中的对象
OpenNI中还存在着“对象”的概念,OpenNI中的对象主要有上下文对象和元数据对象。图3-3表示OpenNI中和上下文对象及元数据对象相关的概念图。
图3-3 OpenNI对象概念图
·上下文对象(Context)是OpenNI中的主要对象,上下文是一个保存了应用程序使用OpenNI的完整状态的对象,它包含了应用程序所使用的全部的生产链。同一个应用程序可以创建多个上下文,但是上下文之间不能共享信息,例如,中间件节点不能从另一个上下文使用设备节点。初次使用之前上下文必须被初始化。
·元数据对象(Metadata)封装了一系列关联到具体数据本身的属性,例如,深度图的典型属性,图的分辨率(X,Y轴的像素),每一个生成器都有特定的元数据对象。另外,在相关数据被生成时录制节点的配置,元数据对象扮演着重要的角色。通俗点说,元数据对象就是将数据和属性封装到一起的对象。
实际上,上下文对象就类似于构建OpenNI程序的一张白纸,而所有的生产节点都要画在这张白纸上,多个上下文对象意味着多张白纸,它们各自“纸上”的生产节点是不能互相通信的。每一个生产节点的配置信息(通常是配置其产生数据的格式)与其产生的数据封装在一起就是我们所说的元数据对象,所以每一个生产节点的元数据对象都是特定的,当开发者需要对生产节点进行配置的时候也就需要对元数据对象的数据格式部分进行设置,还有当开发者需要获取生产节点产生的数据时,也可以从元数据对象中获取到所需要的信息。
3.1.5 OpenNI版本更新说明
本书介绍的OpenNI版本为1.5版本,所以在实际使用OpenNI时会包含三个部分:SDK、驱动以及中间件。三者均可以在OpenNI官网下载。
·OpenNI SDK原始码:一个开发包,可以在OpenNI官网下载。地址如下:https://github.com/OpenNI/OpenNI。
·OpenNI相容硬体模组:实际上这部分是硬件驱动,相应的原始码地址如下:https://github.com/PrimeSense/Sensor。
·OpenNI相容中间件:1.5版本所使用的中间件为PrimeSense NITE。
根据笔者对最新版本OpenNI 2.0的了解,OpenNI中Middleware(中间件)这一部分已经开放出去,这一部分的改变会在后面内容介绍到,所以读者可以根据不同的开发需求,选择相应的Middleware,当然本书中介绍的NITE也可以免费下载使用。
注意
OpenNI 2.0代表OpenNI基本设计理念的一次重大变革。OpenNI 2.0大大降低了API的复杂性。重要的是,OpenNI 2.0极大地简化了通信接口。
1.简化中间件接口
之前的OpenNI 1.5的插件架构已被更新。现在OpenNI 2.0是严格通过驱动获取相关的深度和图像信息的API。PrimeSense提供的解析深度信息的NITE中间件作为一个独立的中间件软件包,它拥有自己的API。此前,该NITE API是通过插件包含相应的功能。
比较OpenNI 2.0架构与OpenNI 1.5架构,如图3-4所示。
图3-4 OpenNI 1.5版本与OpenNI 2.0版本架构比对
通过上图可以看出,OpenNI 1.5与OpenNI 2.0版本之间最大的架构区别在于Middleware的改变,在OpenNI 1.5中Middleware是不对外开放的,所能使用的Middleware也仅有一个就是PrimeSense公司自己发出的NITE,不过在改版后的OpenNI 2.0系列中,Middleware是开放的,也就是可以由第三方开发者发出,这一点极大地丰富了第三方Middleware,也使得OpenNI的功能更加多样化。
2.简化的数据类型
OpenNI 1.5有各种各样的复杂的数据类型。例如,depth maps包含在元数据中。这使得与许多类型的数据交流更为复杂。OpenNI 2.0则更为简洁,提供ir、rgb、depth data统一的数据表示;提供访问底层数组;消除极少使用的以及不相关的数据。
OpenNI 2.0解决了进行隐式双缓冲的问题。基于OpenNI 1.5的帧处理方式,SDK底层总是被迫使用从sensor传输到双缓冲的所有数据,这会影响到OpenNI执行、复杂性和性能。OpenNI 2.0中的数据类型的简化使得允许使用不需要双缓冲输入的数据。
当然,如果需要,它也可以是双缓冲。
3.从以数据为中心向以设备为中心转变
OpenNI 2.0的API被描述为以设备为中心的,而不是以数据为中心的整体设计。比如Production Nodes、Production Graphs、Generators、Capabilities以及其他数据概念在OpenNI 2.0中已经被取消,但OpenNI 2.0与OpenNI 1.5所提供的功能一般是相同的。
4.减少核心类的数量
对于OpenNI 2.0,程序员学习和使用新的API会容易得多。OpenNI 1.5有近百个类,以及数以百计的结构体和枚举类型。而在OpenNI 2.0中,这个数目已经减少到大约十几个。学习OpenNI 2.0可以从以下四个核心类开始。
·openni::OpenNI
·openni::Device
·openni::VideoStream
·openni::VideoFrameRef
5.以事件驱动的访问数据
在OpenNI 1.5中数据的存取是依靠一个循环的阻塞的函数提供新的帧,在新的帧到达之前,线程将被阻塞。OpenNI 2.0仍保留了此功能,但它同时也提供了事件驱动回调函数读取深度。
表3-6就给出OpenNI 2.0中新增加的类及其功能,有兴趣的读者可以自行阅读新增类的详细信息。
表3-6 新增类及其功能
提示
除此之外,在OpenNI 1.5版本和OpenNI 2.0版本中一些功能相同的类也做了一些变化,具体变化有兴趣的读者可以自行查询。