Kinect来了——解析SDK(OpenNI Framework 2)

前文主要介绍了OpenNI FrameWork的基本概念和整体构架,在正式进入API概览之前,我们需要对工作节点(Production Nodes)进行一些补充说明。

工作节点的数据创建/销毁机制

通常把能够输出数据的工作节点称为“生成器”,这里我们可以把“生成器”看作一个对象。而当“生成器”对象被首次创建时,这些对象往往不会立即执行有关数据处理的代码,而需要等待上层应用针对该节点输入相关配置信息之后才进行。实际上“生成器”必须等候相关应用的执行指令到达之后才进行创建数据操作。这一操作往往通过下列虚方法实现:

[c]xn::Generator::StartGenerating();[/c]

应注意 ,上面的StartGenerating函数的作用是开始执行数据生成操作,有时我们希望停止生成新数据,但最好能保留该工作节点的配置信息。那么就没有必要销毁该工作节点对象,只需调用下面的函数即可:

[c]xn::Generator::StopGenerating();[/c]

事实上每一个“生成器”节点都需要实现数据输入操作,但有时可能会遇到这种情况:程序运行可能需要上一次处理的数据结果,为了避免频繁I/O,每个“生成器”节点必须在内部保存一份数据结果副本,直到上层代码显示调用更新数据备份区的函数。此类函数通常是以下形式:

[c]xn::Generator::WaitAndUpdateData();[/c]

调用该函数就意味着通知工作节点需要重置自己的数据备份区,并等待下一次新的数据生成操作。在一条完整的工作链上,程序员需要一次性刷新所有工作节点的数据备份区,那么依照不同情况可以选择相应的简便处理方式:

[c]xn::Context::WaitAnyUpdateAll();        //当任意节点产生新数据时,所有节点都刷新自己的数据备份区;

xn::Context::WaitOneUpdateAll();        //只有当某一个指定节点产生新数据时,所有节点才刷新自己的数据备份区,这种情况通常适用于只有一个控制节点的应用程序;

xn::Context::WaitNoneUpdateAll();        //所有节点立即刷新数据备份区;

xn::Context::WaitAndUpdateAll();        //只有当全部节点都产生新数据时,所有节点才刷新自己的数据备份区;[/c]

上述函数均会在延迟两秒后自动退出。

官方建议程序员应尽量使用形如xn::Context::Wait…UpdateAll()的函数进行数据备份区刷新,除非确实需要只刷新某一个节点,上述方式也会在一定程度上简化程序员的设计和编码工作。

主要数据对象

OpenNI的最基本的数据对象是指上下文对象,上下文对象保存了应用程序使用OpenNI的所有状态信息,包括所有工作链。应注意同一个应用程序可同时创建多个上下文对象,但上下文之间无法共享信息。同时上下文对象必须进行初始化后才能首次使用,且需保证所有的附加模块均得到正确的载入和确认。应用程序可以通过调用shutdown函数释放上下文对象所使用的内存空间。

OpenNI中还定义了一种元数据对象,元数据主要用于保存与特殊数据类型有关的属性信息。例如在一套深度映射数据中,其解析度的大小就属于元数据范畴。任何从生成器节点产生的数据都拥有相应的元数据对象。设计元数据对象的目的在于,由于节点配置可由人为随机干预,任何生成器节点的配置信息和其所产生的数据信息始终无法保证完全一致,因此有必要对每套数据也封装进相应的属性信息,这就是元数据对象的作用。

配置变更

每一个OpenNI中所包含有关配置的选项都携带以下方法:

1、Set函数,用于修改当前配置;

2、Get函数,用于返回当前配置内容;

3、Register和Unregister函数,用于为配置变更事件注册一个回调函数;

数据生成器

1、基本映射图像生成器,OpenNI中用于生成任意数据映射类型的最基本的映射生成器,它的功能主要包括配置控制、特性分配、可替换的视点特性以及帧同步特性;

2、深度映射生成器,主要功能包括获取深度映射、获取设备的最大深度范围、设备的视野属性配置、用户位置特性等;

3、图像生成器,主要功能包括获取彩色图像、获取像素格式属性;

4、红外数据生成器,用于获取当前的红外映射图像;

5、场景分析器,用于获取传感器原始数据,并对原始数据内容进行分类标记和输出,其主要功能包括获取分类映射图像(每一个像素都携带相应的标签)、获取水平面坐标;

6、音频生成器,主要功能包括获取音频缓冲区、配置音频设备属性,包括采样率、通道数以及采样带宽等;

7、姿态生成器,用于对特定的人物或手势进行跟踪,主要功能包括姿态添加/删除、获取活动姿态、注册/反注册姿态存在回调函数、注册/反注册姿态变更毁掉函数;

8、手部标记点生成器,用于跟踪手部标记点,主要功能包括开始/停止手部跟踪、注册/反注册手部跟踪回调函数(包括手部的进/出以及位置变化);

9、用户生成器,用于生成场景中有关人物的数据,主要功能包括返回用户数据、获取用户信息、获取用户质心CoM、获取携带用户标记像素的场景图像、注册/反注册用户进/出回调函数。

最后,我们将介绍几个OpenNI的基本程序框架。

Comments

Kinect来了——解析SDK(OpenNI Framework 1)

本文和后文主要介绍PrimeSense OpenNI Framework的基本架构和设计思路,以及应用开发方面的一些基本问题。应注意这两篇文章不能完全替代官方User Guide的作用,但能帮助读者快速理解并上手OpenNI。此外,由于截至目前微软并不承认除Microsoft Kinect SDK beta之外的其它中间件和应用层API产品,使用OpenNI研究Kinect技术只能局限于研究学习活动,而且此举潜在风险尚无法完全暴露出来。

1 概述

OpenNI实际上首先指开放自然交互联盟,该组织由PrimeSense于2010年底发起,现有成员包括一家核心技术提供商、两家应用开发商和一家设备制造商。OpenNI目前致力于构建OpenNI自然交互应用程序框架,这个框架包括与底层视频和音频传感器进行通信的接口,以及建立其上的高级中间件构件,例如视觉计算和语音识别技术等。下图大致说明了OpenNI体系的层次抽象视图:

[singlepic id=42 w=320 h=240 mode=watermark float=center]

上图的底层设备主要是指视频/深度、音频传感器等,但不仅限于此;OpenNI API主要扮演了与底层设备和顶层应用程序通信的角色,这部分的设计将直接影响应用程序的构建和部署;中间件构件实际上囊括了自然交互所有的核心技术,它的作用就是针对OpenNI采集的原始数据,利用先进的视觉和语音识别算法对原始数据进行精确分析和计算,并生成能够反映真实世界中人物(或其它任何物体)的空间位置、姿态、语音特征,再通过模式分类算法对上述特征进行有效识别和归纳,最终返回有知识意义的N维离散信息。OpenNI定义的中间件构件应包括以下几个部分:

1、全身分析中间件:该组件从原始数据中提取并生成与人体相关的离散信息,这里典型的数据结构包括对关节点、朝向、质心等的描述;

2、手部分析中间件:该组件从原始数据中提取并生成与手部相关的位置信息,该信息通常是指一个点的三维坐标;

3、姿态检测中间件:该组件从原始数据中提取并分析与人体姿态相关的视频信息,并通过分类算法对其进行标识,并反馈识别结果(例如对一个挥手动作的识别,该组件应能及时反馈目标挥手的通知信息);

4、场景分析中间件:该组件从原始数据中提取并分析整个场景信息,并从中分离出有意义的前景(如人物)和背景信息、场景的平面坐标表示、以及对场景中人物个体的识别。

OpenNI API将这些后处理信息提交至上层应用程序,相关应用程序根据已知的自然交互信息和自身的决策算法进行相应的计算和反馈。

由于PrimeSense的关系,OpenNI目前只支持PS提供的硬件方案,但这并不意味着今后的OpenNI只会向着一个方向发展(实际上OpenNI组织的建立恐怕就是考虑到这一点)。不过目前OpenNI只支持3D传感器、RGB摄像头、红外摄像头以及音频传感器设备(也就是说,如果你能够自己凑齐上述物件,那么结合OpenNI构建自然交互程序并不困难,Kinect只是一种便利廉价的硬件方案之一)。

2 工作节点(Production Nodes)

OpenNI使用了工作节点的定义来描述自己的工作流,所谓的工作节点就是能够接收并产生数据的组件,每一个工作节点均可以调用底层节点提供的数据(甚至更改节点配置),并能将数据传递至上层节点。若干工作节点的有效串联就构成了一个工作链,工作链描述了OpenNI中各工作节点的拓扑关系,并提供了一种可行的工作流模型。

对应OpenNI的层次抽象设计,工作节点被分为两大类:一种是传感器节点,另一种是中间件节点。

1、传感器节点:

设备节点,该节点表示某一个硬件设备,如RPG摄像头,设备节点主要用于对相关硬件进行配置;

深度生成节点,能够产生场景的深度映射数据,该节点可由与OpenNI体系保持兼容的任意3D传感器实现;

图像生成节点,产生RGB彩色图像,该节点可由与OpenNI体系保持兼容的任意视频传感器实现;

红外数据生成节点,产生红外图像映射数据,该节点可由与OpenNI体系保持兼容的任意红外传感器实现;

音频生成节点,产生音频数据流,该节点可由与OpenNI体系保持兼容的任意音频传感器实现;

2、中间件节点

姿态警告节点,当某一特定姿态被识别时会产生特殊的回调信息;

场景分析节点,分析场景,分离前景和背景、识别场景中的人物、检测水平面。该节点会生成一个已识别的深度映射数据,其中的每个像素都被标记为不同状态以标识人物和背景部分;

手部生成节点,支持手部的检测和跟踪,当手部被检测到时会产生特殊的回调信息,当手部被持续跟踪时实时更改其位置信息;

用户生成节点,产生一个三维场景中的身体信息表示。

值得一提的是,OpenNI还定义了数据回放接口,其中包括数据记录、回放和记录的编解码操作接口。

3 节点特性

OpenNI为每个工作节点配置了特性属性,特性类似于一种扩展功能。对每个工作节点来说,这些特性的配置非常灵活,不同的中间件提供商可根据需要对自己开发的工作节点进行相应的配置。同时,每个工作节点所对应的特性集合是可选的,用户可根据自身需要对其进行合理配置。应注意,目前OpenNI所提供的几种节点特性并不是固定的设计,在今后会添加更多的节点特性并对已有特性进行调整,现在看来这部分可能是未来设计时需要慎重考虑的地方之一。

关于节点的可用特性列表,读者可查阅OpenNI的官方网站和用户指南。

4 其它

除上述基本属性组成外,OpenNI还设计了若干机制以扩展其上层应用的适应性。

模拟节点 模拟节点实际上是指空节点,也就是不实现任何数据生成的逻辑代码,而类似一种抽象的数据接口层。这种设计往往被用于应用程序的构建当中。

应用程序间的设备共享和节点锁定 OpenNI的工作节点所产生的数据通常只来源于唯一的硬件设备,而该设备可能同时被若干个应用程序所调用。这也就意味着OpenNI的工作节点需要具备一定的同步机制以保证上述任务的并发执行。

就OpenNI这种应用程序框架而言,实现操作系统的进程级并发是很困难的。因此这里OpenNI默认所有的设备节点处于全局共享模式,即任何应用程序均可更改节点配置,同时节点配置一旦发生变更则立即产生回调信息,并通知所有注册至该节点的应用程序。另外,所有工作节点还可处于一种锁定模式,在该模式下OpenNI将屏蔽对应节点”Set”方法的调用,如果该节点恰是设备节点,那么就意味着该设备节点的“Lock Aware”特性被开启。

许可机制 OpenNI提供了一种模块与应用间简单的许可机制,任何一个OpenNI上下文对象均保有一份当前已载入的许可证列表,在任何层次均可检查该列表,并搜索特定的许可证。许可证一般由发行商名称和许可证编号组成,发行商可以利用该许可机制控制其知识产权的使用权。

通用框架工具集 OpenNI集成该工具集的目的是降低跨平台构建应用程序的复杂度,而事实上标准的OpenNI并没有包含这一部分,因此该部分仅仅处于概念阶段。

记录 记录经常被用于调试操作。OpenNI支持记录整个工作链,包括每个工作节点的配置信息和节点间的数据流。OpenNI包含一套完整的记录和回放机制,标准API中是由nimRecorder模块实现的,该模块还定义了一个新的文件格式“.ONI”,用以保存上述信息。

工作节点的异常状态反馈 每一个工作节点均包含相应的异常或错误状态定义。默认的异常状态为“OK”,只有当出现真正的异常或错误时,该状态才会变为Error Status中定义的任何一种信息,同时没有实现异常状态反馈机制节点的异常状态将始终为“OK”。应用程序可以通过为每一个节点注册回调函数以接收其异常状态反馈。此外还可以通过定义全局异常状态来接收任何节点的异常信息,后者的方法通常是最容易实现的。

向后兼容性 OpenNI需要保证完全的向后兼容,这就意味着所有当前构建的应用程序均能完美运行在后续版本的OpenNI框架中,而无需重新编码或编译。

下面我们将重点关注OpenNI的具体API设计和程序基本框架。

Comments

玩仙剑的都是可怜的剧情控!

的确,本文将肯定是一篇牢骚之作。[nggallery id=7]

也许有人以为,与十六年前相比,今天的RPG市场存在玩家流失、开发周期漫长、盗版泛滥,甚至幸存下来的RPGers眼光越来越高、以至开发团队吃力不讨好等众多问题。然而我要说的是,这回的五代之坑爹完全不出我对北软的预料,在仙剑败笔史上恐怕是坐稳了第二把交椅(这里就暂不提带头大哥了)。

去年一共有两款国产中文RPG面市,包括年初的《云之遥》和夏天的《古剑奇谭》。在一口气玩过《古剑》二周目后,我觉得中文RPG越来越讲究游戏品质,尽管一如既往地缺乏游戏性,但在脚本剧情上仙剑系列自坑王二代以后就基本没再弱过:这种局面在2007年的四代和去年的《古剑》(尽管寄予厚望,但我仍希望把它当做是仙剑系列的衍生作品,然而现在看来,若干年之后这种看法可能会受到严格的质疑)上甚至达到了一个顶峰,玩家反馈甚至可以称得上是好评如潮。

然而这次果断被五代坑了。由于没赶上《古剑》的预售,这次我特意提前一个月在淘宝上预定了仙五,好在卖家RP不差,7月6号顺丰到货(正式的全国首发是7月7号)。遗憾的是此后在学校忙了一个多月,8月17号放假,昨晚历经30个小时通关。通关后的唯一感想就是:仙五外传到底还有没有必要再出了?

从剧情上看,尽管五代同样是一个全新的故事,但为迎合系列的世界观,游戏固然脱离不了一部分原始设定。问题在于无论从对原设的衔接还是发展两方面考虑,本作企划都显得十分生硬。例如蜀山七圣,到最后给人感觉不过是个噱头,除了后期的闯七宫情节外基本上是彻底的酱油群体。诚然北斗七星传统上是被道教奉为星神,但设定上有点抄袭小说里的“全真七子”,七星伏魔阵也有参照天罡北斗阵的嫌疑,蜀山倒不如改称全真派算了。还有关于魔界的设定方面,这次发展出了魔界“八族”说,和三代以后的魔尊说完全不符,也不排除是为了外传做铺垫的可能。

另一方面,本作主题为“心愿”,但故事的发展过程并不很贴近主题,许多主线情节基本上可归为支线,因此给人有些故意“充数”的感觉,致使玩家对后续剧情发展逐渐丧失兴趣。

游戏系统上,五代与前作相比几乎没有任何改进,贴符/炼符系统只不过是新瓶旧酒流,战斗系统中新增的合击系统也毫无新意。可见自上软团队于2007年末解散后,仙剑系列经历了两年的沉寂,又经两年研发,最终出来的还是一个成本受到严格控制的“续作”,关于这点也适用于这次的音乐部分,续创太多,原创太少,精品更少。

引擎利用上,还是因为成本问题,仙五的RenderWare引擎必然还会用到外传中。我想说的是,这么一款看重剧情和画面表现力的RPG游戏,坚持使用落后引擎的结果只能是让人不断失望——更何况系列到现在已经如此混乱的世界观了(轩辕剑系列就还好,只是六代已是遥遥无期了)。

值得一提的是,19号晚百游官网上正式发布了仙五的第一部免费DLC和语音包,至此我才得以体验到视角解锁后的游戏场景——事实上五代的运镜设置非常不利于鼠标操作,使得非但没有进一步提高游戏的表现力,反而给玩家造成一些困扰。

总而言之,仙五这次能号称八十万套销量,基本可以说是近年来几部类似作品共同发力的结果。而制作团队无谓的坚持,只能让人担心接下来的续作可能注定将成为仙剑十六年的狗尾续貂了。

Comments

Kinect来了——硬件篇

作为一款集成了诸多先进视觉技术的自然交互设备,Kinect在学术和工业界均享有较高的关注度。本文将在参考PrimeSense传感器技术若干专利文献的基础上,试图探寻Kinect硬件技术的物理原理及其发展前景。为证明本文所描述的内容与Kinect的相关性,还要感谢ifixit写于去年底的一篇Microsoft Kinect Teardown拆解教程,这位前人使得Kinect所有的内部元件得以被我们尽收眼底,从而为我们的“推测”提供了事实依据。当然主要还是因为我是绝对不会把啃奶拆着玩的:)

Kinect硬件系统概览

Kinect的硬件系统其实并不复杂(所以理应便宜到爆?),如下图所示:

[singlepic id=33 w=320 h=240 mode=watermark float=center]

Kinect使用NEC uPD720114的USB 2.0集线器控制器作为数据集成接口,主要控制芯片包括Allegro Microsystems A3906(低电压步进器和单/双路直流电机驱动器)、Marvell AP102(带摄像机接口控制器的SoC)/PrimeSense PS1080-A2(成像处理器SoC)、TI TAS1020B(USB音频控制器)和其它辅助计算/存储设备。本文的剩余内容将依次分析Kinect的三大硬件原理:姿态调整、音频输入、视频输入。

1 转动电机系统

尽管Kinect提供了可跟踪目标物体的物理姿态调整机制,然而该部分相对比较简单,因为这些电机和塑料齿轮看起来有够简陋…实际上在官方出品的Programming Guide中描述了tilt机制的基本规格:±28°V,而Kinect成像系统自身的视角大小为43° V/57°H。同时手册还建议避免频繁调用tilt功能,其最低标准是每秒不超过1次(或每20秒不超过15次)调用。目前看来tilt功能脆弱且基本发挥不了作用,当然今后对应的商业版本可能会是个例外。

2 音频采集系统

Kinect的音频系统采用了四元线性麦克风阵列技术。一般而言,麦克风阵列中包含四个相互独立的小型麦克风,每个设备之间相距数厘米,其排列可呈线形或“L”形。与一般的单麦克风数据相比较,阵列技术包含有效的噪音消除和回波抑制(acoustic echo cancellation,AEC)算法,同时采用波束成形(Beamforming)技术通过每个独立设备的响应时间确定音源位置,并尽可能避免环境噪音的影响。上述Beamforming算法的细节来源于微软研究院,有兴趣的读者可以参考《A NEW BEAMFORMER DESIGN ALGORITHM FOR MICROPHONE ARRAYS》这篇文章,原文发表于IEEE-Proceedings of ICASSP 2005 USA。

从元件上看,除了Kinect所有的四元麦克风阵列以外,还配置了Wolfson Microelectronics WM8737G(配置了前置放大器的24bits立体声ADC)用于进行本地的音频信号处理。关于Kinect Audio系统的软件部分我们将在后续的API专题中进行详细介绍。

3 视频成像系统

Kinect的成像系统来源于PrimeSense的专利技术,尽管微软官方一直遮遮掩掩,但很容易通过分析PS的设计来了解Kinect。下面首先给出Kinect视频传感器的规格:

帧率:30FPS,深度/RGB数据;

帧解析度:深度数据QVGA320x240,RGB数据VGA640x480;

作用范围:1.2-3.5米,深度/RGB数据。

值得一提的是,PrimeSense官网上给出的Reference Design的规格要高出许多,可以看出Kinect主要追求的是经济效益。我们注意到Kinect的电源和USB是同一个接口,而仅连接PC后Kinect的LED会点亮,但还不能执行主要功能。只有再接入电源后才能正式启动(Kinect的功率达到了12W,而普通USB一般是2.5W)。

[singlepic id=34 w=320 h=240 mode=watermark float=center]

上图从左向右,分别是OG12/0956/D306/JG05A红外发射器、VNA38209015彩色CMOS以及Microsoft/X853750001/VCA379C7130红外CMOS。中间的摄像头提供了彩色VGA图像,剩余的两个元件主要用于提供QVGA深度数据。

那么关键问题就是,PrimeSense是如何获取这些深度数据呢?

截至目前,最精确可行的光学测距方法可能就是ToF(time of flight),例如LDM激光测距、IDM红外测距等等具体技术已经实现了产品化;另一方面,如今许多三维扫描仪都采用了三角测距法,特别是对手持式扫描设备而言。然而上述这些技术都不太适用于Kinect这种家用设备:首先是测量环境的限制,其次还要考虑成本因素。

PrimeSense的测距技术类似一部分结构光技术,“结构光”指一些具有特定模式的光,其pattern的图案可以是线、点、面等多种图形。结构光扫描法的原理是首先将结构光投射至物体表面,再使用摄像机接收该物体表面反射的结构光图案,由于接收图案必会因物体的立体形状而发生变形,那么就可以试图通过该图案在摄像机上的位置和形变程度来计算物体表面的空间信息。普通的结构光方法仍然是部分采用了三角测距原理进行深度计算。

参考Google Patents上的Range mapping using speckle decorrelation(No. US7433024B2)以及DEPTH MAPPING USING PROJECTED PATTERNS(No. 0118123 A1)两篇技术文档,已经有前人对PrimeSense的方法进行了详细解释。

PrimeSense将其深度测量技术命名为Light coding,与结构光法不同的是,Light coding的光源被称为“激光散斑(laser speckle)”,是当激光照射到粗糙物体或穿透毛玻璃后形成的随机衍射斑点。这些散斑具有高度的随机性,而且会随着距离的不同变换图案。也就是说空间中任意两处的散斑图案都是不同的。只要在空间中打上这样的结构光,整个空间就都被做了标记,把一个物体放进这个空间,只要看看物体上面的散斑图案,就可以知道这个物体在什么位置了。

当然,在这之前要把整个空间的散斑图案都记录下来,所以要先做一次光源的标定。在PrimeSense的专利上,标定的方法是这样的:每隔一段距离,取一个参考平面,把参考平面上的散斑图案记录下来。假设Natal规定的用户活动空间是距离电视机1米到4米的范围,每隔10cm取一个参考平面,那么标定下来我们就已经保存了30幅散斑图像。需要进行测量的时候,拍摄一副待测场景的散斑图像,将这幅图像和我们保存下来的30幅参考图像依次做互相关运算,这样我们会得到30幅相关度图像,而空间中有物体存在的位置,在相关度图像上就会显示出峰值。把这些峰值一层层叠在一起,再经过一些插值,就会得到整个场景的三维形状了。

值得注意的是,尽管没有对PrimeSense下手,微软在前不久先后收购了3DV和Canesta,两家均握有大量ToF视频跟踪技术专利的科技公司。可以想见,Kinect作为消费市场的零号机,可能很快就会有更加强大的商用同伴诞生。

Comments

MS Kinect开发社区的最新进展

三个月前,我们展示了一套配合使用OpenNI+SensorKinect+NITE在Windows平台上驱动Kinect的Demo程序,事实证明,上述框架已完全可满足基于最新版本的Kinect的PC项目开发了。不过,微软在连续跳票一个多月后终于坐不住了,于北京时间6月17日凌晨开放The Kinect for Windows SDK beta下载页面,并作为正规军首次杀入这个吸引了众多发烧友和研究人员的技术萌芽领域。

由于最近一段时间非常忙,我们几乎没有空闲时间用于对快速发展中的Kinect技术进行潜心研究。幸运的是,我得以在暑假一天半的假期里花几个小时研究来自微软的SDK。很显然,因为她的姗姗来迟,越来越多的国内开发者尝试进入这个领域,而又由于Kinect技术在应用层面实际上要求比较高的知识和技术门槛,这也成了Kinect社区拥有一批具有较高技术素养的核心成员的重要原因。

首先应当说明的是,我拿到的SDK其实是微软在7月29日发布的1.00.12版,msdn上给出的Refresh Details解释新版本在驱动和运行库部分相较旧版而言得到了一些增强,目前也没有发现存在任何兼容问题。须知MS的Kinect SDK beta只支持Windows 7操作系统,开发环境要求VS2010/.Netframework 4.0。关于硬件部分的要求在试验阶段其实几乎可以忽略,除非你买到了非盒装的Kinect(拆机版也可额外购买电源/USB数据接口)。

对于初学者而言,还有一些组件需要额外安装,但这些都不是必须的。例如几个经典的Demo程序,例如骨骼跟踪,就需要Microsoft DirectX® SDK - June 2010 or later version和Runtime for Microsoft DirectX® 9才可以编译运行;另外对于语音命令识别的Sample程序,还需要安装Microsoft Speech Platform Runtime, version 10.2 (x86 edition)、Microsoft Speech Platform - Software Development Kit,version 10.2 (x86 edition)以及Kinect for Windows Runtime Language Pack, version 0.9(acoustic model from Microsoft Speech Platform for the Kinect for Windows SDK Beta。上述开发库提供了内容绘制、图像和图形处理、语音识别等非Kinect原生功能,仅仅这些,Kinect综合技术的一角其实已经显现出来了。

那么下面就是一个运用骨骼跟踪和语音识别技术的官方Demo:

[singlepic id=32 w=320 h=240 mode=watermark float=center]

在试用了几个不同的Demo后,我认为微软这次放出的SDK其实并非想象中好。问题主要在于开发平台比较单调,尽管支持非托管的C++代码,但是官方demo基本上都使用C#.NET/WPF开发,在与现有资源相结合的部分还做得不够好,而且demo的bug比较多;另外与OpenNi/NITE组合相比前者似乎性能较低——当然其精度较之后者能好一些,但区别并不明显。

荷兰人Jasper Brekelmans是一名长期关注Kinect技术的开发人员,他在博客上对截至目前微软的beta版和PrimeSense的OpenNi进行了比较。我们总结了他的文章,并将其划分为四个主要问题:

问:什么是Microsoft’s Kinect SDK (Beta)能而OpenNi还不能做到的?

答:目前微软的产品提供了音频支持、调整倾角的转动电机motor/tilt、在全身跟踪骨骼跟踪方面:非标准姿势检测(相对于OpenNi的投降姿势…),头部、手、脚、锁骨检测以及关节遮挡等细节上的处理更为细致(但精度是否更高还不能确定)。此外,SDK beta还提供了多机接口,使许多尚在设想中的特殊应用有直接变为现实的可能。当然,MS的开发库在安装上非常容易,也基本不需要任何设置即可使用。提供了可用视频和深度图输入的事件触发机制。

问:那么微软的产品没有提供什么功能?

答:对许多开发者而言最大的问题可能是微软对非商业使用的限制,而OpenNi则不存在这方面问题。此外,微软的SDK目前并未提供手势识别和跟踪功能,而在前一篇文章中我们已经看到用NITE的手势识别和跟踪组件控制鼠标光标的例子。

另一方面,SDK beta未能实现RGB图像/深度图像的互对齐,只是提供了对个体坐标系的对齐,而该功能在许多应用中实际上是很有必要的。

在全身骨骼跟踪中,SDK只计算了关节的位置,并未得出其旋转角度。从可移植的角度来看,SDK beta只能用于Kinect/Win7平台,而OpenNi还至少支持华硕的WAVI Xtion体感设备,今后支持的硬件平台还可能更多。相比较而言SDK beta不支持Unity3D游戏引擎、不支持记录/回放数据写入磁盘、不支持原始红外视频数据流、也不支持像OpenNi一样的角色入场和出场的事件响应机制。

问:能不能再说说OpenNi/NITE提供的功能?

答:可用于商业开发、包含手势识别和跟踪功能、可自动对齐深度图像和RGB图像,全身跟踪、关节旋转角度计算、看起来性能较好、跨平台多设备支持、已有众多游戏产品应用、支持记录/回放数据写入磁盘、支持原始红外视频数据流、支持角色入场和出场的事件响应机制。

问:那么OpenNi/NITE不能做什么?

答:未提供音频功能、不支持调整倾角的转动电机motor/tilt、在全身跟踪骨骼跟踪方面:无法跟踪头部、手、脚和锁骨的旋转动作,需要标准姿势检测(即著名的投降姿势…),关节遮挡等细节上的处理似乎存在算法bug。不能自动安装并识别Kinect多机环境。安装过程较为繁琐,特别是NITE还要申请开发证书编码。OpenNi也没有提供可用视频和深度图输入的事件触发机制。

总结: OpenNI最大的优势就是允许跨平台多设备,以及商业应用。但从原始数据的采集和预处理技术上看,微软的SDK似乎更稳定一些,况且还提供了不错的骨骼和语音支持。对于部分身体部位识别方面的功能,SDK beta没有提供局部识别和跟踪,这需要自己的后续开发(至少在相当一段时期内微软可能都不会提供此类功能)。OpenNi/NITE虽然提供了手势识别和跟踪,然而在全身骨骼姿势识别和跟踪上还要更多借鉴微软的产品。

因此,按照目前在社区中的表现,SDK beta和OpenNi/NITE孰优孰劣还真无法一下子确定。而且随着越来越多的开发者加入微软这一方,SDK beta的普及可能会更快,但在更高层次的应用上,对二者的选用往往是需要一定智慧的。

Comments

我的西大三宝(3)

3 南校区的癞蛤蟆

从南校区的东门进入校园,首先会看到一大片绿葱葱的草坪,草坪的中央点缀了几处灌木丛。校园东西中轴线上有一条小路,从东门进去沿此路可直抵模拟法庭,路北的草坪上遗落了一座曾经供校工们居住的庭院,尽管近年几已无人居住,然而如果你在夏季的某个上午经过那大草坪,从东面望去,炙热的阳光已洒满不远处庭院的外墙上,那墙足有两、三米高,而墙后竟伸出几株涨势颇盛的向日葵来,反比墙还高出一米左右。我从没见过如此高的向日葵。

尽管大草坪总不是人迹罕至的地方,大学校园里的却例外。常能在上午看到三三两两的校工驾着草坪车在场地中央转圈圈,也许他们没有能创造出麦田怪圈的想象力,但总能看出工人们其实是很热衷于这项工作的。

盛夏逢雨便是幸事,许多住在宿舍中的同学都能不知不觉体会到一觉自然醒的好处。每到此时我都会想起一只住在大草坪里的老友,那老友足足比一个拳头还大,它白天总蛰伏在地表以下的洞穴中,即使到了夜半也很难寻觅到其踪迹——不过,如果到了久旱逢霖,老友就经常兴奋异常得昏了头,时不时蹦跶到大草坪的边缘以外,运气不好的话就刚好和某个路过的冒失鬼撞个正着。

老友俗称癞蛤蟆,汉字中“癞”有凹凸不平的意思,人们往往对对癞蛤蟆不很主流的外表印象深刻,这恐怕是这个有点“不雅”的俗名流传开来的主要原因之一。我第一次见到老友时,恰逢甘霖济旱,夜里十一点多从实验室下来,细雨正绵,大草坪中央飘着一层薄雾。由于临近楼管大妈锁门睡觉,于是步行速度自然而然就有些加快。

这时脚下没留神就踩断一截枯枝——“嘎嘣”一下,紧接着感到脚的前方不远处有个黑影忽然往草坪方向一跃,前进了大概几十厘米。我吓了一跳,赶紧抬脚躲避,借着对面人行道上的路灯一看,原是一只好大的癞蛤蟆。那蛤蟆倒也不惊慌,尽管刚才已是奋力一跳,却没有再急于钻进草丛里,就一动不动了。

次日中午,天早已放晴,气温回升。依旧是从实验室下来,在距前晚不远处又遇到一只肤色稍浅的癞蛤蟆,由于夜晚光照的原因,我并无法确定它就是晚上的那只。只不过,那蛤蟆依旧岿然不动:正如工业光魔的《Rango》一样,当一只变色龙被遗落在西部的戈壁上,瞬间蜕两层皮都是常事了。而癞蛤蟆似乎从未意识到这种危险,依然呆若木鸡。

后来我发现,蛤蟆这种犹如被石化一般,其实恰恰是一种抵御外部危险的正常反应:由于不善跳跃,在行人繁杂的行道上缓缓爬行无疑是十分危险的。同时,蛤蟆亦可以通过长期匍匐以期能作出爆发一跳,以备当真正有危及生命的险情发生时得以逃脱——尽管这在其较受人欢迎的近亲——青蛙看来不过是小菜一碟,但对癞蛤蟆来说,却再现了这个物种与其宿命的抗争。

事实上,无论是漫长的文明史,还是现代科学的证据都表明,蟾蜍——这毕竟才是癞蛤蟆的真名,正是人类眼里两栖纲中地位最高的物种之一。中国古代神话中嫦娥居住的月宫广寒,即相传是一蟾蜍化成,因此也常称其为蟾宫,固才有屈原《天问》的“夜光何德,死则又育?厥利惟何,而顾菟在腹?”两问,尤有近代闻一多先生经缜密调查终指出“顾菟”意喻蟾而非兔。可见每晚在月亮上忙不迭捣着不死药的,除了白兔还有蟾蜍啊。在其它一些典故中,更有“金蟾”一说风靡于五行风水之学,民间的热情更是经久不息。

另一方面,传统中医上把蟾蜍的分泌物称为“蟾酥”,是一种极为名贵的中药材。在国外,一些热带地区甚至专门引进蟾蜍以避农害,收效甚好。

可见,我的这个常年蛰伏南校区大草坪中,昼伏夜出了无数个岁月的蟾蜍老友,早已是声名远播,名满天下了。

(完)

Comments

我的西大三宝(2)

假期里这个系列的文章确实包含三篇,一文一宝,写完回家。有同学好奇前文中的戴胜鸟到底算不算是西大的宝贝,我觉得当然算,只是如果我们非要强调所谓的“西大三宝”,恐怕这种过于具象化的描述还不足以承载西北大学已经走过的一百一十个春秋,因此文章最初发布时特意将题目冠以“我的”二字作为约束,这样不免又让人诚惶诚恐起来。

2 鹦鹉与喜鹊

在本部校园的任何一个角落都有机会看到灰喜鹊的身影,而喜鹊们最喜欢栖息在行政楼前的那两三棵大树上。

每当在西门里等校车时,我都会趁着机会去观察那一片披着蓝黑色外衣的鸟。鸟们并不安分,围绕着旁边那栋矮楼叽叽喳喳个不停,有时甚至趴在二、三楼房间的窗户上,似乎很执着地想向里面的人们传达什么信息。

沿着喷水池南边的岔口向前走一小段路就是教学六楼。有意思的是,尽管位置显眼,但六号楼却人迹罕至——即使它也拥有不逊色于这座老校园的历史。一年多前,一群以CEO自居的乡镇企业家们聚集在这里,共同出资重新翻修了这座在他们眼里早已破败不堪的六号楼,随后设下门禁阻挡闲杂人员,而教室则专供诸CEO们在每个周末集会学习使用。于是,这座楼虽然暂时告别了往日的窘迫,人气却更显凋零。

CEO们每月挑上几个吉利的日子便过来听会儿课,且又因为装修过的教室仅限在前两层,导致二层以上几乎成了无人区,于是一只金黄色的小鹦鹉便趁机居住在这里。

那鹦鹉并不十分畏人,如果你能缓缓靠近它,甚至是轻轻触碰都不会太过惊动这个小家伙。我发现鹦鹉每天午后准时出现在通往三楼的阶梯上,且双眼几乎全部闭住,待感受到一点风吹草动才会张开一条缝隙。等接近晚饭时间,鹦鹉才会懒懒地扑扇几下翅膀,显得很不情愿地离开原来的位置。

令我感到好奇的是,这鹦鹉的每日生活确实显得单调,然而墙外的喜鹊却过着另外一种完全不同的生活:不远处,几只灰喜鹊从空中滑翔而过,又迅速各自隐藏在密叶丛中,互相以嘎嘎的叫声示意;此时,墙内的鹦鹉丝毫没有注意到这些动静,依旧岿然不动地立在阶梯中间。

很显然,鹦鹉与喜鹊从未羡慕过对方的生活,甚至于让我怀疑他们是否曾经注意到对方的存在。事实上,上述假设也许永远都不可能发生。

渐渐地,喜鹊的数目越来越多,活动范围也覆盖到了整个校园——它们成了校园天空真正的主人,并被当作西大老校园的标志之一。六号楼里,也许已是硕果仅存的这只鹦鹉依旧全神贯注,它对酷热天气的承受力远远超过了人类。

遗憾的是,我后来再去六号楼拜谒那鸟时,除了蝉鸣和窗外的嘈杂声,那鸟竟已踪迹全无了。

Comments

我的西大三宝(1)

西大有三宝,这是我来西大整整五年时间才深刻体会到的。本文原应待两年后离开时再放出,然而时光荏苒,届时是否还有幸能在校园里觅得“三宝”,我自己都不太确定。当然,现在所述的“三宝”却依旧是眼前鲜活的景物。

1 戴胜

第一次见到戴胜鸟是在科技楼西侧的草坪旁边,彼时已近深秋,一只黄褐色的大鸟突然从我的头顶掠过,沿着波浪状的轨迹直飞到我面前的步行道上。我之前的确不知道这鸟原叫作戴胜,它拥有细长且扁平的头冠,有部分甚至耷拉在脑袋后侧,独特的叫声也令人感到惊奇。我和那鸟僵持了一会,突然想到要赶下一趟校车,于是便继续前行了几步——大鸟突然竖起头冠,那冠羽像一把色彩鲜明的扇子立在那里,鸟被迫向旁边挪动了两步,依然夹带着那独特的叫声——的确漂亮极了——随后扑扇了几下翅膀,消失在一片枯黄的密叶中。我对这鸟的来历好奇的很,通过对它奇特外形的描述仔细查找确认一番,才得知“戴胜”这一雅号。

“戴胜”之所以得名,还是源于古人对戴胜鸟华美头冠的艳羡,就好似头戴华胜一般。中国自古就有许多诗歌吟咏戴胜,然而这里我想先给出一篇古希腊哲人亚里士多德有关戴胜的文章,在《动物志》第九卷中作如下描述:

……戴胜亦会变换其颜色和外观,恰如埃斯库罗斯在以下诗句中所述:

……The hoopoe also changes its colour and appearance, as Aeschylus has represented in the following lines:—

戴胜见到自己的卑微,

The Hoopoe, witness to his own distress,

大神却令穿上多样的花衣:

Is clad by Zeus in variable dress:-

有时是一只戴着盔缨的山鸟,

Now a gay mountain-bird, with knightly crest,

有时又换上了苍鹰的白毛;

Now in the white hawk’s silver plumage drest,

跟着节序的变易,

For, timely changing, on the hawk’s white wing,

脱掉银灰的羽翼,

He greets the apparition of the Spring.

正当春光来到林荫,

Thus twofold form and colour are conferred,

他就重新打扮全身。

In youth and age, upon the selfsame bird.

这套冠履显得他年轻又且美丽,

The spangled raiment marks his youthful days,

而那银灰的古装正合老成的旨趣;

The argent his maturity displays;

等到坡上黍黄的时候,

And when the fields are yellow with ripe corn,

还得配些秋色的文绣。

Again his particoloured plumes are worn.

然而世事总不能尽如鸟意,

But evermore, in sullen discontent,

他从此深隐到何处的山里。

He seeks the lonely hills, in self-sought banishment.

—— Translated by D’Arcy Wentworth Thompson

同时期的中国古代典籍亦有《礼记.月令》:“……是月也,命野虞无伐桑柘。鸣鸠拂共羽,戴胜降于桑……”。意在指“季春之月”即阴历五月,戴胜降落在农田中,一步一啄,犹如农耕,因此鼓励人们像戴胜一样勤于农作。 此外,古人咏戴胜知天时而劝人耕,亦可谓是数不胜数。可见,戴胜鸟与人类伴居至少已有两千多年的历史了。

然而尽管戴胜并不算是什么珍惜鸟类,这的确是我们唯一一次相遇。虽然我也曾经从紫藤园辗转至木香园,再寻觅到润林苑,此后却再也没有能够有幸遇见戴胜轻巧的身影徜徉于西大的树梢间。

现如今,那只聪慧机敏、温柔灵动的戴胜,犹如这座老校园往日的生机勃勃一样,恐怕只能成为记忆中的沧海一粟了。

Comments

代码如诗,因此请不要代码如Shi

下周久违的仙五就要到家了,因此本文是我这周末在学校作完,下周休息且将专注通关,那么隔周的文章就会是相关的体验和评测了。

打开这个blog所依赖的wordpress项目官网,首页下方常年静静地躺着这么一句话:CODE IS POETRY(代码如诗)。

如今,编码已是大部分程序员仅有的几个生存技能之一了。程序员写代码的目的无非是养家糊口,费尽脑汁地想方设法满足需求,做到让客户满意,老板放心,以此换来一份还算体面的工作和报酬。除此之外 ,罕见的假期和无尽的加班——这既是冰冷的deadline要求,如今也已成为这个竞争严酷的行业的一个标志性特征。

我第一次听说“IT工业”这个词汇时就产生一些疑惑,这个看似一(多)人一(多)本打天下的行业怎么能和生产高度社会化的大工业联系在一起——后来等逐渐快“想明白”了,现在又普遍表达为“IT服务业”。可见我们自己都时常纠结于这些政治和经济词汇中,对个人修行又有什么好处。 因此我认为,程序员的工作应归属于文学类,确切地讲是代码诗人。

若干年前,我也曾写过许多如今看来颇幼稚可笑的诗歌,现在想想文学作品的任务不外就是叙述事实,表达观点或抒发情感,作家的阅历和天赋决定了读者的口碑。相比较而言,代码是程序员用来叙述事实,表达观点的终端工具,功能上和文学的区别似乎不大。唯一不同之处就在于,读者通过文字大概就可以了解作家,用户却只能通过综合的产品体验去评价程序员,在某种意义上说,程序员要比作家难作的多!另一方面,文学往往惊艳于作家的灵光一闪,而代码却更多依赖于理性和经验,源泉不同,其表现却是相同:同样一幅场景,无论使用文字还是代码,都有无限可能的表达方式。

而且,代码还不能仅仅等同于一般意义上的文学作品。计算语言学(或计算机语言学)特别注重强调形式化,这是使用计算语言表示数理方法的基础。然而形式化并不意味着必须符号化,否则使用计算语言的优势也无法得以体现。现代计算语言的发展也证明了计算语言是朝着形式化与拟人化双重目标前进的。而文学作品中形式化最为深刻的体裁恐怕就是那些诗词歌赋了——这难道不是代码如诗的又一力证!

此时我又想起了数年前的那数十篇诗歌,无一不是逃离理性的表达。如今我所能做的,竟也只是纯粹理性状态下才能写下的一行行字符。尽管意境不同,美好却是不变。于是强迫自己亲手写下每一行代码,过程艰辛,却也心安理得,纵使独臂难支,体验依旧。

最后,代码于我如诗,于众则未必。我喜欢读如诗的代码,却非常厌恶如Shi的代码,也许无论是现在或未来,我都不会成为一名代码诗人,但这却不影响我作为如诗代码的读者之一。我唯一的愿望就是:眼前这篇代码能多些诗一般的灵气和酣畅,少些Shi一样的世俗和愚蠢。若能如是,还有什么兴趣爱好堪比与此呢。

Comments

宫崎骏和他的自然法则

宫老的片子我向来都是力挺,这次也不例外。

尽管比起三年前的《金鱼姬》还差了近六十亿本土票房,然而无论是宫崎吾朗还是米林宏昌,吉卜力近几次由新人扛鼎的作品丝毫都不失其国民级动画的风范。此外依旧不变的是,我仍可耻地等到一年后的DVD发行版面市——还得是由热心网友在第一时间提供抓轨下载……不过,相较于宫老过去的几部作品,这次从影片《借りぐらしのアリエッティ》中看到了吉卜力试图淡化创作者的个人情绪,且期望承担更多社会责任——这恐怕也是影片缺少几分灵气的重要原因吧!

无论如何,观影的过程还是让人感到舒适和温馨的。整个故事以男主角翔的独白倒叙展开,翔当时正准备接受心脏病手术,而此时父母离婚,母亲也远走国外,姥姥便专程驱车带翔到东京都附近的家中静养一周。不过姥姥的这栋住宅却不一般:宅基下面住了三代的小小人族,这些小小人族通常必须用“借”的方式从人类家中获得生活必需品,其独特的生存方式充满挑战却倒也其乐融融,唯一的禁忌就是不能被人类发现,否则就必须被迫搬离住所。

翔已经是母亲家族在此居住的第四代,据说姥姥的父亲曾在屋内见到小小人族,当即就从英国购置了一套华美精致的人偶房屋,希望小小人族能搬到这个“新家”中。遗憾的是除了翔的母亲和姥姥的父亲以外,家中再没人能亲眼见到过小小人族,而能请小小人族们在人偶房屋居住——到翔这代已经是四代家人的一个梦想了。

十分幸运的是,翔刚到姥姥家的第一天就无意中撞见了偷跑出来的小小人族女孩Arrietty,但也只是一个一闪而过的身影而已。而当晚上Arrietty跟随父亲又来翔的家中“借东西”,突然意识到翔这个人类发现了自己的存在,便匆忙和父亲跑回家中。其实当天晚上翔只是安静看着Arrietty的一举一动,从未有过恶意的想法。早上起来翔发现Arrietty临走时不小心丢下的一块方糖——于是把糖块放回到小小人族们经常出没的地方。Arrietty的家人知道了翔留下的方糖,认为是人类为了抓捕小小人族而设置的陷阱,父亲遂决定举家搬迁。

尽管Arrietty不愿搬离,但也无奈于对家人安全的考虑。然而故事还未结束,翔姥姥家的管家春发现了小小人族的秘密,春是本片唯一的麻烦制造者——不对,还有一只狂暴乌鸦……这在片头就有明确的表示了。春决定抓住家中所有小小人族,趁Arrietty搬家之际抓走了Arrietty的母亲荷蜜莉,并请来了捕鼠公司帮忙。Arrietty情急之下向翔求助,翔不顾病重和春周旋,并帮助Arrietty救出了荷蜜莉。而春也因为抓捕小小人族的计划失败而懊恼不已。

夜,Arrietty和家人准备顺溪而下迁往森林的另一边。此时的翔同样夜不能寐,终于在家猫尼亚的带领下及时赶到并与Arrietty做了最后告别。

现在回想一下,宫老过去二、三十年的影片不是自然题材就是生活题材。而最近的几部片子,比如《崖の上のポニョ》和本片,都尽量要做到自然与生活的统一,事实上脚本构思的也十分巧妙——尤其是三年前的那只金鱼姬和她的奇幻水世界。而这部改编自英国上世纪50年代儿童作家的作品,只是在主题上更加明确和深化了:这世间的物种无一不享有最平等的生存权利,尽管面临进化和自然选择,但各物种无不全力以赴,力争生存,而这星球上拥六十七亿之众的人类,也应该始终保有一颗对其他物种的尊重和对自然的敬畏之心。而对于从小就患有心脏疾病的翔来说,Arrietty和小小人族们永不放弃的勇气也坚定了自己面对未来的信心。

最后,我们回到技术上看。宫老对CG的反感是出了名的,尽管近年来吉卜力的作品一直都在试图引入CG技术,但其小心翼翼的步伐也使得宫老近三十年来的动画技术几乎没有太多突破——这绝非是为了说明手绘动画已经过时,毕竟宫老和吉卜力的影响力是有目共睹的——我们看看更大众化的哆啦a梦系列,三十年如一日的机器猫剧场版在技术上始终走在业界前列,但愈发缺少原著的灵魂了。不过如果我们将视界扩展至全球,CG动画的市场份额仍然在不断扩大,老牌手绘Disney也不得不和着Pixar的脚步做起了全三维CG并横扫世界,尽管Disney还在坚持制作自己的手绘影片,然而其是否宁愿赔本赚吆喝到底也不为人知。我相信,随着CG技术在艺术表现力上突飞猛进式的发展,我们终将有机会踏入这个现实世界中的梦幻王国。

Comments