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

配置工作节点的一般方法

前文的例子中已经说明了在程序中动态配置节点信息的一般过程,节点配置完成的主要标志一般是对xn::Generator::StartGenerating()函数的调用。除此之外,OpenNI还提供了基于外置XML文件的节点配置方法,使用XML配置文件能够显著降低代码复杂度,同时提高应用程序的可用性和灵活性,本文将主要讨论上述方式结合OpenNI编程。

OpenNI支持的XML脚本功能非常强大,仅使用外置的文件就能够实现节点的创建、配置,甚至操作上下文属性(例如增加相应的许可证等)。通常可以使用xn::Context::RunXmlScript()直接执行脚本字符串,或通过xn::Context::RunXmlScriptFromFile()调用外部文件。

一个XML内容中必须包含一个OpenNI结点,该结点内共包含三个子结点:Licenses,Log和Production Nodes。其中Licenses结点提供了系统需要的额外的许可证,其格式一般如下:

[c]<Licenses> <License vendor="vendor1" key="key1"/> <License vendor="vendor2" key="key2"/> </Licenses>[/c]

Log结点用于配置OpenNI的日志系统,该结点内可添加下列可选元素属性:writeToConsole,设置日志信息是否在控制台中显示,默认为false。writeToFile:,设置日志信息是否将被写入文件,该文件将被放置在工作目录下,默认为false。writeLineInfo,设置是否每一条日志记录都需要包含文件名和行信息,默认为true。此外,Log还包含三个子结点:LogLevel,携带value属性,其值为0 (verbose), 1 (info), 2 (warnings) or 3 (errors),其中3为默认值,该结点决定了日志记录的粒度。Masks,包含一个mask元素列表,设置相应mask的开启和关闭。Dumps,包含一个dump元素列表,设置相应dump的开启和关闭。下面的XML脚本演示了一段日志配置信息:

[c]<Log writeToConsole="false" writeToFile="false" writeLineInfo="true"> <LogLevel value="3"/> <Masks> <Mask name="ALL" on="true" /> </Masks> <Dumps> <Dump name="SensorTimestamps" on="false" /> </Dumps> </Log>[/c]

ProductionNodes结点包含了工作结点的创建和配置信息,它包括了若干个子结点: GlobalMirror,设置Global Mirror属性的开启和关闭,相当于调用xn::Context::SetGlobalMirror()函数; Recording,设置是否启动一个记录,其file属性包括了记录文件名; Node,该子结点可以包含多个,它将引导OpenNI枚举并创建一个工作结点,其作用类似xn::Context::CreateAnyProductionTree()函数。其type属性表示枚举类型,值可包括下列内容:Device (XN_NODE_TYPE_DEVICE)

Depth (XN_NODE_TYPE_DEPTH)

Image (XN_NODE_TYPE_IMAGE)

IR (XN_NODE_TYPE_IR)

Audio (XN_NODE_TYPE_AUDIO)

Gesture (XN_NODE_TYPE_GESTURE)

User (XN_NODE_TYPE_USER)

Scene (XN_NODE_TYPE_SCENE)

Hands (XN_NODE_TYPE_HANDS)

Recorder (XN_NODE_TYPE_RECORDER)

Node结点的name属性允许设置一个工作节点名称。

Query,Node还含有一个Query子结点,用于枚举时的查询操作。Query可包含下列子结点:”Vendor”、”Name”、”MinVersion”、”MaxVersion”、”Capabilities”、”MapOutputModes”、”MinUserPositions”、”NeededNodes”,上述结点均可设置不同的子结点和属性,用于查询条件的选择,如果有多个子结点同时出现,那么OpenNI将按照AND进行逻辑整合。下列XML脚本演示了创建一个自定义属性的深度生成器:

[c]<Node type="Depth" name="MyDepth"> <Query> <Vendor>vendor1</Vendor> <Name>name1</Name> <MinVersion>1.0.0.0</MinVersion> <MaxVersion>3.1.0.5</MaxVersion> <Capabilities> <Capability>UserPosition</Capability> <Capability>Mirror</Capability> </Capabilities> <MapOutputModes> <MapOutputMode xRes="640" yRes="480" FPS="30"/> </MapOutputModes> <MinUserPositions>2</MinUserPositions> <NeededNodes> <Node>MyDevice</Node></NeededNodes> </Query> </Node>[/c]

Configuration子结点实际上代表了对工作节点的动态配置,其指令内容将是顺序执行的。同时,该结点几乎对应了OpenNI所有的Set配置操作,下面的例子演示了分别创建图像、深度和音频节点的过程:

[c]<ProductionNodes> <Node type="Image"> <Query> <MapOutputModes> <MapOutputMode xRes="320" yRes="240" FPS="60"/> </MapOutputModes> <Capabilities> <Capability>Cropping</Capability> <Capability>Mirror</Capability> </Capabilities> </Query> <Configuration> <MapOutputMode xRes="320" yRes="240" FPS="60"/> <PixelFormat>RGB24</PixelFormat> <Cropping enabled="true" xOffset="28" yOffset="28" xSize="200" ySize="160" /> <Mirror on="true" /> </Configuration> </Node> <Node type="Depth"> <Query> <Vendor>VendorX</Vendor> <MapOutputModes> <MapOutputMode xRes="640" yRes="480" FPS="30"/> </MapOutputModes><Capabilities> <Capability>UserPosition</Capability> </Capabilities> </Query> <Configuration> <MapOutputMode xRes="640" yRes="480" FPS="30"/> <UserPosition index="0"> <Min x="128" y="128" z="500"/> <Max x="600" y="400" z="2000"/> </UserPosition> <Property type="int" name="VendorXDummyProp" value="3" /> </Configuration> </Node> <Node type="Audio"> <Configuration> <WaveOutputMode sampleRate="44100" bitsPerSample="16" channels="2" /> </Configuration> </Node> </ProductionNodes>[/c]

通常在上述配置信息载入后,应手动调用xn::Context::StartGeneratingAll()函数启动数据流。然而也可以在XML中加入默认的Start信息,即在ProductionNodes和其Node子结点中均包含有startGenerating属性,其中如果前者的该属性为true,那么将意味着执行StartGeneratingAll(),否则只执行相应为true的工作节点。