API 框架
OpenNI2 SDK architecture
OpenNI2的框架的核心是提供了两套软件接口:
1,应用层接口。对于应用层开发者屏蔽掉不同厂家3D Sensor的差异。
2,驱动层接口。实现驱动层接口的3D Sensor只要遵从OpenNI2的协议,就可以从OpenNI2应用层接口访问该设备。
OpenNI2的框架有显著的层次结构。所有API接口都是严格遵循这个层次结构来实现的。带着这个层次结构的思路去看代码,就会很清晰。
OpenNI2通过Driver Handler模块动态加载设备驱动。这样做的好处是,可以将OpenNI2的代码与3D Sensor的驱动分离开来,作为两个独立的工程去开发维护。
C++中API使用介绍
Hello World
是否想在深入研究之前体验一下我们的SDK?那就让我们动手写些代码吧!
于本教程结束前,您将会熟悉:
1,SDK的初始化与终止。
2,从传感器中读取数据。
3,检查Astra深度相机提供的深度信息。
开始前
如果您跳过了安装SDK和构建SDK提供的示例应用程式部分,请确保您至少已将OpenNI2 SDK下载并解压缩到可以轻松访问的文件夹中。
言归正传
第一步,我们将构建一个基础应用程序,作为逐步添加新功能的起点。 1,使用您喜欢的IDE,设置一个新的控制台程序项目并创建一个新的名为“main.cpp”的源文件。 2,将下述内容复制到您的 main.cpp 文件中:
#include <OpenNI.h>
#include <stdio.h>
#include <cstdio>
#include <iostream>
int main(int argc, char** argv)
{
std::cout << "hit enter to exit program" << std::endl;
system("pause");
return 0;
}
- 所有的应用程序必须包含OpenNI.h。它是OpenNI2 SDK的核心,是所有基于C++的OpenNI2 SDK的应用程序所必须的。
- 我们将使用system("pause");以确保我们有机会在应用程序关闭窗口前看到自己的程序运行的结果。
OpenNI的初始化与终止
为了让OpenNI准备好执行我们的命令,我们首先必须初始化OpenNI,这毫无疑问是通过初始化函数initialize()完成。当我们准备结束SDK的会话时,我们仍需给OpenNI一个彻底关闭的机会。这是通过调用终止函数shutdown()来完成的。 添加以下两行代码:
int main(int argc, char** argv)
{
Status rc = OpenNI::initialize();
if (rc != STATUS_OK)
{
printf("Initialize failed\n%s\n", OpenNI::getExtendedError());
return 1;
}
// what will go here? you'll find out soon!
OpenNI::shutdown();
std::cout << "hit enter to exit program" << std::endl;
system("pause");
return 0;
}
信任但也要确认
先别操之过急,让我们先花点时间来确保一切都如我们所预期。编译并运行该应用程序。应用程序应该可以启动,打印一系列诊断信息到控制台,然后应用程序在耐心的等待用户按下“回车”键。一旦按下“回车”键,该应用程序便会正常退出。
注意
默认情况下,OpenNI2会将大量诊断信息记录到控制台。如果您遇到了问题,这可能是一个寻找答案的好地方。接下来:与OpenNI2传感器对话。
连接到OpenNI2-打开设备
现在我们知道了如何正确初始化和终止OpenNI2,是时候与OpenNI2传感器进行实际通信了。为此,我们使用Device类,Device类是对一个设备的抽象,提供了连接一个设备,以及获取设备的配置信息和设备支持的流的种类的能力。但是,就目前而言,我们可以将Device视为实体设备,并通过Device对设备进行控制。
在初始化和终止OpenNI2之间,我们声明一个Device变量。
int main(int argc, char** argv)
{
Status rc = OpenNI::initialize();
if (rc != STATUS_OK)
{
printf("Initialize failed\n%s\n", OpenNI::getExtendedError());
return 1;
}
Device device;
rc = device.open(ANY_DEVICE);
if (rc != STATUS_OK)
{
printf("Couldn't open device\n%s\n", OpenNI::getExtendedError());
return 2;
}
device.close();
OpenNI::shutdown();
std::cout << "hit enter to exit program" << std::endl;
system("pause");
return 0;
}
现在,可以肯定的是,它看起来似乎是我们在先前步骤的代码的基础上又加了几行代码,但是这几行比它看起来要重要得多。仅通过声明和构造一个Device对象,并调用Device对象的open方法,您就可以指示OpenNI2开始连接到它可以定位的第一个可用的OpenNI2传感器。
注意
OpenNI2提供一个额外的构造函数使您可以连接到特定OpenNI2传感器。
获取传感器数据
是时候充分利用我们的Device对象来获取一些数据了。为此,我们需要读取OpenNI2设备提供的一个数据流。数据流包含来自我们相机的数据,该数据被打包在称为“帧”的数据包中。当前,OpenNI支持多种类型的流,包括深度流、红外流和彩色流。
为访问来自OpenNI2设备的数据流并访问到帧,我们需要一个VideoStream来接入其中一个数据流。 出于本应用程序的目的,我们将专注于深度流。该流向我们提供了相机可以看到的任何物体的距离,这些距离数据(以像素为单位)被打包在一个帧中。
首先,让我们使用Device创建一个VideoStream。
int main(int argc, char** argv)
{
Status rc = OpenNI::initialize();
if (rc != STATUS_OK)
{
printf("Initialize failed\n%s\n", OpenNI::getExtendedError());
return 1;
}
Device device;
rc = device.open(ANY_DEVICE);
if (rc != STATUS_OK)
{
printf("Couldn't open device\n%s\n", OpenNI::getExtendedError());
return 2;
}
VideoStream depth;
if (device.getSensorInfo(SENSOR_DEPTH) != NULL)
{
rc = depth.create(device, SENSOR_DEPTH);
if (rc != STATUS_OK)
{
printf("Couldn't create depth stream\n%s\n", OpenNI::getExtendedError());
return 3;
}
}
depth.destroy();
device.close();
OpenNI::shutdown();
std::cout << "hit enter to exit program" << std::endl;
system("pause");
return 0;
}
接下来,我们用上一步创建的VideoStream depth来启动深度流,获取深度数据。
int main(int argc, char** argv)
{
Status rc = OpenNI::initialize();
if (rc != STATUS_OK)
{
printf("Initialize failed\n%s\n", OpenNI::getExtendedError());
return 1;
}
Device device;
rc = device.open(ANY_DEVICE);
if (rc != STATUS_OK)
{
printf("Couldn't open device\n%s\n", OpenNI::getExtendedError());
return 2;
}
VideoStream depth;
if (device.getSensorInfo(SENSOR_DEPTH) != NULL)
{
rc = depth.create(device, SENSOR_DEPTH);
if (rc != STATUS_OK)
{
printf("Couldn't create depth stream\n%s\n", OpenNI::getExtendedError());
return 3;
}
}
rc = depth.start();
if (rc != STATUS_OK)
{
printf("Couldn't start the depth stream\n%s\n", OpenNI::getExtendedError());
return 4;
}
depth.stop();
depth.destroy();
device.close();
OpenNI::shutdown();
std::cout << "hit enter to exit program" << std::endl;
system("pause");
return 0;
}
首先需要通过 VideoStream来检索最新的帧,然后调用getData从我们的帧中获得深度帧数据。
int main(int argc, char** argv)
{
Status rc = OpenNI::initialize();
if (rc != STATUS_OK)
{
printf("Initialize failed\n%s\n", OpenNI::getExtendedError());
return 1;
}
Device device;
rc = device.open(ANY_DEVICE);
if (rc != STATUS_OK)
{
printf("Couldn't open device\n%s\n", OpenNI::getExtendedError());
return 2;
}
VideoStream depth;
if (device.getSensorInfo(SENSOR_DEPTH) != NULL)
{
rc = depth.create(device, SENSOR_DEPTH);
if (rc != STATUS_OK)
{
printf("Couldn't create depth stream\n%s\n", OpenNI::getExtendedError());
return 3;
}
}
rc = depth.start();
if (rc != STATUS_OK)
{
printf("Couldn't start the depth stream\n%s\n", OpenNI::getExtendedError());
return 4;
}
int changedStreamDummy;
VideoStream* pStream = &depth;
rc = OpenNI::waitForAnyStream(&pStream, 1, &changedStreamDummy, SAMPLE_READ_WAIT_TIMEOUT);
if (rc != STATUS_OK)
{
printf("Wait failed! (timeout is %d ms)\n%s\n", SAMPLE_READ_WAIT_TIMEOUT, OpenNI::getExtendedError());
continue;
}
rc = depth.readFrame(&frame);
if (rc != STATUS_OK)
{
printf("Read failed!\n%s\n", OpenNI::getExtendedError());
continue;
}
if (frame.getVideoMode().getPixelFormat() != PIXEL_FORMAT_DEPTH_1_MM && frame.getVideoMode().getPixelFormat() != PIXEL_FORMAT_DEPTH_100_UM)
{
printf("Unexpected frame format\n");
continue;
}
DepthPixel* pDepth = (DepthPixel*)frame.getData();
depth.stop();
depth.destroy();
device.close();
OpenNI::shutdown();
std::cout << "hit enter to exit program" << std::endl;
system("pause");
return 0;
}
接着把获取到的深度数据打印出来。
int main(int argc, char** argv)
{
Status rc = OpenNI::initialize();
if (rc != STATUS_OK)
{
printf("Initialize failed\n%s\n", OpenNI::getExtendedError());
return 1;
}
Device device;
rc = device.open(ANY_DEVICE);
if (rc != STATUS_OK)
{
printf("Couldn't open device\n%s\n", OpenNI::getExtendedError());
return 2;
}
VideoStream depth;
if (device.getSensorInfo(SENSOR_DEPTH) != NULL)
{
rc = depth.create(device, SENSOR_DEPTH);
if (rc != STATUS_OK)
{
printf("Couldn't create depth stream\n%s\n", OpenNI::getExtendedError());
return 3;
}
}
rc = depth.start();
if (rc != STATUS_OK)
{
printf("Couldn't start the depth stream\n%s\n", OpenNI::getExtendedError());
return 4;
}
int changedStreamDummy;
VideoStream* pStream = &depth;
rc = OpenNI::waitForAnyStream(&pStream, 1, &changedStreamDummy, SAMPLE_READ_WAIT_TIMEOUT);
if (rc != STATUS_OK)
{
printf("Wait failed! (timeout is %d ms)\n%s\n", SAMPLE_READ_WAIT_TIMEOUT, OpenNI::getExtendedError());
return 5;
}
rc = depth.readFrame(&frame);
if (rc != STATUS_OK)
{
printf("Read failed!\n%s\n", OpenNI::getExtendedError());
return 6;
}
if (frame.getVideoMode().getPixelFormat() != PIXEL_FORMAT_DEPTH_1_MM && frame.getVideoMode().getPixelFormat() != PIXEL_FORMAT_DEPTH_100_UM)
{
printf("Unexpected frame format\n");
return 7;
}
DepthPixel* pDepth = (DepthPixel*)frame.getData();
int middleIndex = (frame.getHeight() + 1)*frame.getWidth() / 2;
printf("[%08llu] %8d\n", (long long)frame.getTimestamp(), pDepth[middleIndex]);
depth.stop();
depth.destroy();
device.close();
OpenNI::shutdown();
std::cout << "hit enter to exit program" << std::endl;
system("pause");
return 0;
}
最后,运行您的应用程序来检测一切是否正常。正常情况下,弹出的控制台窗口会打印一行获取到的数据帧数据。运行完成后,请按“回车”键。
前面展示了如何从OpenNI2设备中获取一帧数据!接着我们学习下如何处理一些列帧。
获取流数据(一系列数据帧)
在之前的基础上只需要循环调用 VideoStream中的readFrame函数就可以使用数据流了。在下面的例子中,我们将从深度流中获取前100帧,并将每个帧的第一个像素值打印到控制台。
下述代码与我们上一个示例的代码非常相似,唯一的不同是除了我们在帧处理代码外面添加了一个do while 循环之外,还添加了一些变量用于存储循环次数和我们想要处理的最大帧数。
int main(int argc, char** argv)
{
Status rc = OpenNI::initialize();
if (rc != STATUS_OK)
{
printf("Initialize failed\n%s\n", OpenNI::getExtendedError());
return 1;
}
Device device;
rc = device.open(ANY_DEVICE);
if (rc != STATUS_OK)
{
printf("Couldn't open device\n%s\n", OpenNI::getExtendedError());
return 2;
}
VideoStream depth;
if (device.getSensorInfo(SENSOR_DEPTH) != NULL)
{
rc = depth.create(device, SENSOR_DEPTH);
if (rc != STATUS_OK)
{
printf("Couldn't create depth stream\n%s\n", OpenNI::getExtendedError());
return 3;
}
}
rc = depth.start();
if (rc != STATUS_OK)
{
printf("Couldn't start the depth stream\n%s\n", OpenNI::getExtendedError());
return 4;
}
int changedStreamDummy;
VideoStream* pStream = &depth;
//Stores the maximum number of frames we're going to process in the loop
const int maxFramesToProcess = 100;
//Sentinel to count the number of frames that we've processed
int count = 0;
//The frame processing loop
do{
rc = OpenNI::waitForAnyStream(&pStream, 1, &changedStreamDummy, SAMPLE_READ_WAIT_TIMEOUT);
if (rc != STATUS_OK)
{
printf("Wait failed! (timeout is %d ms)\n%s\n", SAMPLE_READ_WAIT_TIMEOUT, OpenNI::getExtendedError());
continue;
}
rc = depth.readFrame(&frame);
if (rc != STATUS_OK)
{
printf("Read failed!\n%s\n", OpenNI::getExtendedError());
continue;
}
if (frame.getVideoMode().getPixelFormat() != PIXEL_FORMAT_DEPTH_1_MM && frame.getVideoMode().getPixelFormat() != PIXEL_FORMAT_DEPTH_100_UM)
{
printf("Unexpected frame format\n");
continue;
}
DepthPixel* pDepth = (DepthPixel*)frame.getData();
printf("[%08llu] %8d\n", (long long)frame.getTimestamp(), pDepth[0]);
count++;
}while (count < maxFramesToProcess);
depth.stop();
depth.destroy();
device.close();
OpenNI::shutdown();
std::cout << "hit enter to exit program" << std::endl;
system("pause");
return 0;
}
编译并运行。当程序运行且传感器对准您时,稍微移动一点点,并观察帧上的数据值变化。
获得成就!您刚刚完成了您的第一个OpenNI2应用程序! 如果您尚未在OpenNI2上获得足够乐趣,请继续进行“获取流数据”。
获取流数据
数据流类型
OpenNI2 SDK支持三种数据流类型。这些数据流由传感器生成,并通过SDK传递给应用程序。您可以根据您的需要选择合适的数据流。
流类型 | 描述 |
SENSOR_COLOR | 来自传感器的RGB像素数据。每个彩色帧中包含了每个像素的每个颜色分量的0-255范围内的值。 |
SENSOR_DEPTH | 来自传感器的深度数据。每个深度帧中包含了传感器视场内的每个像素的距离值(默认情况下的单位:毫米)。 |
SENSOR_IR | 来自传感器的红外数据。 |
获取数据
OpenNI2 SDK提供了两种方法来获取流数据。根据您的特定用例和应用程序的复杂性,其中的一种方法可能比另一种更适合。
轮询
获取帧数据的轮询方法是获取流数据的最直接方法,也是Hello World教程中使用的方法。为使用此方法,您只需要调用OpenNI::waitForAnyStream并通过VideoStream::readFrame()方法读取流数据。如果有新的数据产生了,readFrame()方法就会提供一个可以访问最新产生的视频帧的帧引用(VideoFrameRef)。如果没有新的帧产生,OpenNI::waitForAnyStream这个方法就会阻塞直到有新的帧产生。如果您想限制SDK以等待新帧到达的时间,可以将超时时间作为参数传递给OpenNI::waitForAnyStream函数。
Status rc = OpenNI::initialize();
if (rc != STATUS_OK)
{
printf("Initialize failed\n%s\n", OpenNI::getExtendedError());
return 1;
}
Device device;
rc = device.open(ANY_DEVICE);
if (rc != STATUS_OK)
{
printf("Couldn't open device\n%s\n", OpenNI::getExtendedError());
return 2;
}
VideoStream depth;
if (device.getSensorInfo(SENSOR_DEPTH) != NULL)
{
rc = depth.create(device, SENSOR_DEPTH);
if (rc != STATUS_OK)
{
printf("Couldn't create depth stream\n%s\n", OpenNI::getExtendedError());
return 3;
}
}
rc = depth.start();
if (rc != STATUS_OK)
{
printf("Couldn't start the depth stream\n%s\n", OpenNI::getExtendedError());
return 4;
}
int changedStreamDummy;
VideoStream* pStream = &depth;
rc = OpenNI::waitForAnyStream(&pStream, 1, &changedStreamDummy, SAMPLE_READ_WAIT_TIMEOUT);
if (rc != STATUS_OK)
{
printf("Wait failed! (timeout is %d ms)\n%s\n", SAMPLE_READ_WAIT_TIMEOUT, OpenNI::getExtendedError());
return 5;
}
rc = depth.readFrame(&frame);
if (rc != STATUS_OK)
{
printf("Read failed!\n%s\n", OpenNI::getExtendedError());
return 6;
}
事件
使用基于事件的方法获取帧数据需要少量的附加设置,但允许开发人员将帧的处理委托给一个或多个单独的类。OpenNI2 SDK提供了一个名为VideoStream::NewFrameListener的抽象类,该类只实现了一个名为NewFrameListener::onNewFrame的函数。一旦VideoStream流中有数据帧到来并准备好被处理时,就会立即调用NewFrameListener::onNewFrame函数。
从NewFrameListener中派生的侦听器类的示例:
class PrintCallback : public VideoStream::NewFrameListener
{
public:
void onNewFrame(VideoStream& stream)
{
stream.readFrame(&m_frame);
}
private:
VideoFrameRef m_frame;
};
定义了侦听器类后,为了使用它,必须在应用程序中实例化侦听器,然后使用VideoStream::addNewFrameListener函数将其添加到 VideoStream中。
侦听器的示例用法:
Status rc = OpenNI::initialize();
if (rc != STATUS_OK)
{
printf("Initialize failed\n%s\n", OpenNI::getExtendedError());
return 1;
}
Device device;
rc = device.open(ANY_DEVICE);
if (rc != STATUS_OK)
{
printf("Couldn't open device\n%s\n", OpenNI::getExtendedError());
return 2;
}
VideoStream depth;
if (device.getSensorInfo(SENSOR_DEPTH) != NULL)
{
rc = depth.create(device, SENSOR_DEPTH);
if (rc != STATUS_OK)
{
printf("Couldn't create depth stream\n%s\n", OpenNI::getExtendedError());
return 3;
}
}
rc = depth.start();
if (rc != STATUS_OK)
{
printf("Couldn't start the depth stream\n%s\n", OpenNI::getExtendedError());
return 4;
}
PrintCallback depthPrinter;
// Register to new frame
depth.addNewFrameListener(&depthPrinter);
// Wait while we're getting frames through the printer
while (true)
{
Sleep(100);
}
实际上,上面代码中的while循环不需要一直执行,当应用程序关闭或发生另一个特定于应用程序的事件发生时,需要退出循环。
有关侦听器的更实用示例,请继续阅读Event Based Read。
Event Based Read示例
完成 Hello World教程之后,想获取更多知识吗? 现在您已经掌握了OpenNI2 SDK的一些基本概念,让我们使用另一种方式来读取OpenNI2 传感器的深度流。
在本教程结束时,您应该熟悉:
- NewFrameListener 类的用途
- 如何定义NewFrameListener
- 使用NewFrameListener处理深度流。
开始之前: 1,请先下载和解压最新的OpenNI2 SDK。 2,使用您喜欢的IDE,设置一个新的控制台应用程序项目,创建一个名为“ main.cpp”的新源文件。 3,将以下内容复制到main.cpp文件中。
#include <stdio.h>
#include "OpenNI.h"
int main(int argc, char** argv)
{
Status rc = OpenNI::initialize();
if (rc != STATUS_OK)
{
printf("Initialize failed\n%s\n", OpenNI::getExtendedError());
return 1;
}
Device device;
rc = device.open(ANY_DEVICE);
if (rc != STATUS_OK)
{
printf("Couldn't open device\n%s\n", OpenNI::getExtendedError());
return 2;
}
VideoStream depth;
if (device.getSensorInfo(SENSOR_DEPTH) != NULL)
{
rc = depth.create(device, SENSOR_DEPTH);
if (rc != STATUS_OK)
{
printf("Couldn't create depth stream\n%s\n", OpenNI::getExtendedError());
return 3;
}
}
rc = depth.start();
if (rc != STATUS_OK)
{
printf("Couldn't start the depth stream\n%s\n", OpenNI::getExtendedError());
return 4;
}
// More of your code will go here
depth.stop();
depth.destroy();
device.close();
OpenNI::shutdown();
std::cout << "hit enter to exit program" << std::endl;
system("pause");
return 0;
}
侦听数据流
在Hello World教程中,我们通过循环调用OpenNI::waitForAnyStream 来等待一个数据帧的到来,并且VideoStream的readFrame函数来读取一个数据帧。在简单的情况下,例如我们的Hello World应用程序,此解决方案非常有效。但是,如果我们同时读取多个VideoStream中的数据帧并且处理数据帧,又该怎么处理呢?所有这些情况中,循环中的代码都可能很快变得复杂、混乱且麻烦。
为解决该等问题,OpenNI2 SDK为我们提供了一个定义和创建NewFrameListener的框架。NewFrameListener有一个名为onNewFrame的函数,当准备处理特定类型的新帧时,将调用该函数。因此,我们的侦听器不会在 OpenNI::waitForAnyStream上循环,而是在帧准备好后立刻自动将最新的帧传递给onNewFrame函数。
为了在我们的示例中使用NewFrameListener。 1,我们需要定义一个实现NewFrameListener的侦听器类。此侦听器类将使我们能够访问来自OpenNI2传感器的实际帧。 我们将在onNewFrame函数中获得这些帧。 将以下代码复制到::include指令下方和主函数main上方:
using namespace openni;
void analyzeFrame(const VideoFrameRef& frame)
{
DepthPixel* pDepth;
int middleIndex = (frame.getHeight()+1)*frame.getWidth()/2;
switch (frame.getVideoMode().getPixelFormat())
{
case PIXEL_FORMAT_DEPTH_1_MM:
case PIXEL_FORMAT_DEPTH_100_UM:
pDepth = (DepthPixel*)frame.getData();
printf("[%08llu] %8d\n", (long long)frame.getTimestamp(),
pDepth[middleIndex]);
break;
default:
printf("Unknown format\n");
}
}
class DepthFrameListener : public VideoStream::NewFrameListener
{
public:
void onNewFrame(VideoStream& stream)
{
stream.readFrame(&m_frame);
analyzeFrame(m_frame);
}
private:
VideoFrameRef m_frame;
};
注意 唯一需要的函数是onNewFrame函数。此类中的其他函数将用来支持我们在该函数中所做的工作。
定义DepthFrameListener后,让我们在主函数中构造侦听器,并将其添加到上一步创建的 VideoStream中。
#include <stdio.h>
#include "OpenNI.h"
int main(int argc, char** argv)
{
Status rc = OpenNI::initialize();
if (rc != STATUS_OK)
{
printf("Initialize failed\n%s\n", OpenNI::getExtendedError());
return 1;
}
Device device;
rc = device.open(ANY_DEVICE);
if (rc != STATUS_OK)
{
printf("Couldn't open device\n%s\n", OpenNI::getExtendedError());
return 2;
}
VideoStream depth;
if (device.getSensorInfo(SENSOR_DEPTH) != NULL)
{
rc = depth.create(device, SENSOR_DEPTH);
if (rc != STATUS_OK)
{
printf("Couldn't create depth stream\n%s\n", OpenNI::getExtendedError());
return 3;
}
}
rc = depth.start();
if (rc != STATUS_OK)
{
printf("Couldn't start the depth stream\n%s\n", OpenNI::getExtendedError());
return 4;
}
DepthFrameListener depthPrinter;
// Register to new frame
depth.addNewFrameListener(&depthPrinter);
// More of your code will go here
depth.stop();
depth.destroy();
device.close();
OpenNI::shutdown();
std::cout << "hit enter to exit program" << std::endl;
system("pause");
return 0;
}
等待直到键盘点击事件发生
我们已经打开了Device,并且正在侦听通过Device的 VideoStream流入的深度帧。 但是上面的程序,可能连一个数据帧都没有处理就已经结束了。因此我们加入一个循环,直到有键盘按钮点击事件发生才停止循环。为了捕获键盘点击事件,我们引入头文件::include <conio.h>,并定义了wasKeyboardHit函数。另外程序结束之前需要调用removeNewFrameListener来移除侦听器。
#include <stdio.h>
#include "OpenNI.h"
#include <conio.h>
int wasKeyboardHit()
{
return (int)_kbhit();
}
int main(int argc, char** argv)
{
Status rc = OpenNI::initialize();
if (rc != STATUS_OK)
{
printf("Initialize failed\n%s\n", OpenNI::getExtendedError());
return 1;
}
Device device;
rc = device.open(ANY_DEVICE);
if (rc != STATUS_OK)
{
printf("Couldn't open device\n%s\n", OpenNI::getExtendedError());
return 2;
}
VideoStream depth;
if (device.getSensorInfo(SENSOR_DEPTH) != NULL)
{
rc = depth.create(device, SENSOR_DEPTH);
if (rc != STATUS_OK)
{
printf("Couldn't create depth stream\n%s\n", OpenNI::getExtendedError());
return 3;
}
}
rc = depth.start();
if (rc != STATUS_OK)
{
printf("Couldn't start the depth stream\n%s\n", OpenNI::getExtendedError());
return 4;
}
DepthFrameListener depthPrinter;
// Register to new frame
depth.addNewFrameListener(&depthPrinter);
// Wait while we're getting frames through the printer
while (!wasKeyboardHit())
{
Sleep(100);
}
depth.removeNewFrameListener(&depthPrinter);
depth.stop();
depth.destroy();
device.close();
OpenNI::shutdown();
std::cout << "hit enter to exit program" << std::endl;
system("pause");
return 0;
}
让我们编译并运行我们的解决方案。在您将一些深度帧信息打印到控制台后,您会发现您已经掌握了侦听器以及其他OpenNI SDK核心功能。现在,再接再厉,发挥您的想象力,并使用OpenNI SDK进行各种创新!
Android中API使用介绍
前言
为了使用户正确的、高效的在自己的项目中快速接入Orbbec Android平台的OpenNI2.0-SDK,防止在使用SDK 相关API接口的过程中由于不规范的调用而引起其他问题,故拟定以下内容来规范关键性API的调用。
OpenNI2.0-SDK
SDK框架介绍
OpenNI 2 分层设计,OpenNI 2 框架如下:
Openni2.0 Driver层:
- 平台适配:隔离windows和linux系统之间的差异,包括线程,内存管理,事件/互斥锁,定时器等;
- 适配windows和linux下usb通信接口: linux使用libusb通信,windows使用orbbec自己的驱动obdrv.sys对上层提供统一的接口;
- Usb通信:包括设备枚举,usb控制命令实现,视频流的接收,解析。
Openni层:主要封装对外的获取视频流接口及参数设置的接口。
库文件
Orbbec-SDK提供给用户的包括两部分内容,5个so动态库文件:
1个jar文件:
ini文件
两个ini配置文件:
SDK接入
将库文件放在接入工程Module的libs目录下,ini文件放在接入工程的Module的app->src->main->asset->openni目录下,在Module的build.gradle中配置重新指定jniLibs目录,最后同步整个工程。
如图所示:
SDK初始化
初始化方式
在调用SDK之前必须要初始化,一般在程序运行开始时进行, 比如Android应用的onCreate方法中。初始化方法如下:
方法1:自定义Application初始化,自定义的Application需要在Module的AndroidManifest.xml文件中注册。
方法2:Activity的onCreate中完成。
初始化接口
初始化调用接口:
接口类 | API | 参数 | 描述 |
OpenNI | OpenNI .setLogAndroidOutput(true); | ture:输出Android 日志 false:反之 | 设置SDK Log 日志是否输出,自动输出到终端平台。 |
OpenNI .setLogMinSeverity(0); | 0 - Verbose; 1 - Info; 2 - Warning; 3 – Error; | 设置Log日志输出级别 | |
OpenNI .Initialize(); | | 初始化SDK,必须调用 | |
Logcat重定向
该功能是帮助客户获取到SDK输出的log日志信息,可以将log信息重新保存、重新定向输出到其他存储文件,用于遇到异常是分析问题使用。
Logcat重定向实现
1.需要实现日志重定向接口类IOpenNILogCat。
接口类 | API | 描述 |
IOpenNILogCat | int verbose(String tag, String msg); | 创建类实现IOpenNILogCat接口类,根据API回调函数获取重定向输出的log日志信息。 |
| int debug(String tag, String msg); | |
| int info(String tag, String msg); | |
| int warning(String tag, String msg); | |
| int error(String tag, String msg); | |
2.设置logcat重定向输出并初始化SDK。
接口类 | API | 参数 | 描述 |
OpenNI | OpenNI.setLogAndroidOutputRedirect(true); | ture:重定向输出Android 日志 false:反之输出log日志 | 设置SDK Log 日志是否输出,自动输出到终端平台。 |
OpenNI.setLogMinSeverity(0) | 0 - Verbose; 1 - Info; 2 - Warning; 3 – Error; | 设置Log日志输出级别 | |
OpenNI .Initialize(); | 无 | 初始化SDK,必须调用 | |
OpenNILog | OpenNILog.setLogRedirect(logRedirect); | IOpenNILogCat实现类 | 设重定向的类 |
3.代码实现
请求打开UsbDevice
请求打开UsbDevice是Android系统授权的过程,在Android系统中操作UsbDevice必须要先申请权限。
请求打开UsbDevice接口
在Orbebc-SDK中,请求UsbDevice过程:
- OpenNIHelper枚举Orbbec的usb设备,如果未找到Orbbec的usb设备,回调未找到设备,程序终止;
- 如果“1”找到Orbbec usb设备,OpenNIHelper向系统发送申请UsbDevice权限的广播;
- OpenNIHelper注册广播监听器监听系统授权后UsbDevice请求状态返回;
- OpenNIHelper调用用户注册的监听器返回UsbDevice请求结果,请求结果包括UsbDevice打开成功、打开失败和设备未发现三种结果。
请求UsbDevice接口:
接口类 | API | 参数 | 描述 |
OpenNIHelper | OpenNIHelper(Context context); | Context建议使用:getApplicationContext() | OpenNIHelper初始化 |
requestDeviceOpen(OpenNIHelper.DeviceOpenListener listener) | DeviceOpenListener | 请求并打开UsbDevice的连接 | |
UsbDevice请求结果回调接口:
接口类 | API | 参数 | 描述 |
DeviceOpenListener | void onDeviceOpened(UsbDevice device); | UsbDevice device | 返回请求成功的UsbDevice |
void onDeviceOpenFailed(String msg); | String msg | 失败返回错误信息回调此接口表示打开设备失败 | |
void onDeviceNotFound(); | 无 | 设备未找到回调 | |
注意:如果OpenNIHelper没有枚举到设备,或者请求权限失败,通过DeviceOpenListener回调UsbDevice请求结果。
具体实现方式
OpenNIHelper初始化,实现方式:OpenNIHelper openNIHelper=new OpenNIHelper(getApplicationContext());
可以根据自己的需求在程序初始化时调用,且只需要调用一次即可,例如在onCreate完成最后初始化。
请求UsbDevice并注册状态监听:
实现方式:openNIHelper.requestDeviceOpen(deviceOpenListener);
注册回调获取设备监听器,如图:
- 如果是Pro系列深度设备(Color是标准的UVC摄像头),需要自己申请color摄像头的权限(Android6.0以上就需要动态申请权限),并重写Activity的onRequestPermissionsResult函数,Android6.0以上需要用户授权的情况下才可以获取访问Camera设备,因此Pro系列深度设备的UVC摄像头需要在onRequestPermissionsResult回调中打开。
Device打开
这里的Device是即将打开使用的Orbbec设备,要使用正确的Device需要经过枚举、匹配、打开三个步骤。
Device枚举
Orbbec Device枚举是通过OpenNI.enumerateDevices()接口实现,
实现方式:List<DeviceInfo> deviceInfos=OpenNI.enumerateDevices();
具体调用接口:
接口类 | API | 参数 | 描述 |
OpenNI | enumerateDevices (); | 无 | 返回List<DeviceInfo> 设备列表信息 |
Device匹配
获取到已经申请权限的UsbDevice后,与通过OpenNI枚举(“5.1”)到Orbbec 的DeviceInfo进行VID, PID对比匹配,查找出Orbbec的Usb Device。
匹配逻辑:
详细匹配 |
(deviceInfos.getUsbProductId() == device.getProductId() && deviceInfo.getUsbVendorId() == device.getVendorId()) |
Device打开
查找出Orbbec的Device后打开。
无参打开方式
实现方式:Device device = Device.open();
具体调用接口:
接口类 | API | 参数 | 描述 |
Device | open (); | 无 | 返回打开成功的Device |
错误码回调打开方式
实现方式:Device device = Device.open(Device.OniDeviceOpenListener listener);
具体调用接口:
接口类 | API | 参数 | 描述 |
Device | open (Device.OniDeviceOpenListener listener); | OniDeviceOpenListener | 返回打开成功的Device,打开失败OniDeviceOpenListener错误的状态码信息。 |
接口类 | API | 参数 | 描述 |
OniDeviceOpenListener | deviceOpenError(int statusCode); | statusCode | |
statusCode如下:
设备打开失败的时回调该接口函数,同时返回错误的状态码信息值,如下:
/*状态码正常*/
STATUS_OK = 0;
/*状态码异常,除了返回详细的错误码外*/
STATUS_ERROR = 1;
/*未找到设备*/
STATUS_NO_DEVICE = 6;
/*状态码超时异常*/
STATUS_TIME_OUT = 102;
/*设备已经被打开*/
STATUS_DEVICE_IS_ALREADY_OPENED = 4097;
/*USB层未找到设备*/
STATUS_USB_DEVICE_NOT_FOUND = 4099;
/*USB接口设置失败*/
STATUS_USB_SET_INTERFACE_FAILED = 4102;
/*USB接口设置失败*/
STATUS_USB_DEVICE_OPEN_FAILED = 4103;
/*获取USB设备描述符失败*/
STATUS_USB_ENUMERATE_FAILED = 4104;
/*设置USB配置失败*/
STATUS_USB_SET_CONFIG_FAILED = 4105;
/*USB子系统初始化失败*/
STATUS_USB_INIT_FAILED = 4112;
/*libusb返回内存不足*/
STATUS_LIBUSB_ERROR_NO_MEM = 4113;
/*libusb返回设备打开权限错误(权限拒绝)*/
STATUS_LIBUSB_ERROR_ACCESS = 4114;
/*libusb 返回没有找到设备*/
STATUS_LIBUSB_ERROR_NO_DEVICE = 4115;
/*libusb 返回IO错误(Input/output error)*/
STATUS_LIBUSB_ERROR_IO = 4116;
/*liusb 返回Entity not found*/
STATUS_LIBUSB_ERROR_NOT_FOUND = 4117;
/*liusb 返回Resource busy*/
STATUS_LIBUSB_ERROR_BUSY = 4118;
/*libusb 返回其它错误*/
STATUS_LIBUSB_ERROR_OTHER = 4096;
Device打开业务实现
方式一:
方式二:
VideoStream创建
Device打开后,创建VideoStream, VideoStream的创建分为Depth、Color(通过OpenNI2.0协议的)、IR三种类型。
VideoStream创建
实现方式:VideoStream stream = VideoStream.create(device, SensorType.DEPTH);
这里的Device是步骤“5”得到的,具体调用接口。
接口类 | API | 参数 | 描述 |
VideStream | create(device, SensorType.DEPTH); | Device | “5.3”成功打开的Device |
SensorType | VideoStream类型 | | |
SensorType | IR(1); COLOR(2); DEPTH(3); | 无 | 根据SensorType创建不同类型的VideoStream类型,包括Depth、IR和Color(by OpenNI)。 |
VideoMode获取
VideoStream创建成功,可以获取、设置对应创建的Stream的分辨率、数据输出格式、帧率等。
实现方式:List<VideoMode> videoModes = stream.getSensorInfo().getSupportedVideoModes();
此处的stream是“6.1”成功创建的 VideoStream。
具体调用接口:
接口类 | API | 参数 | 描述 |
List<VideoMode> | getSensorInfo().getSupportedVideoModes() | 无 | 返回当前创建VideStream支持的VideoMode类型列表 |
VideoMode设置
实现方式:
stream.setVideoMode(videoMode);
此处的stream是“6.1”得到的VideoStream,videoMode是“6.2”得到的。
具体接口调用:
接口类 | API | 参数 | 描述 |
VideoStream | setVideoMode(videoMode) | VideoMode | 设置VideStream输出的数据流模式 |
注意:
Orbbec.ini中可以配置默认的数据流的分辨率, 输出格式,如果代码中有设置VideoMode,则会覆盖该配置。
VideoStream创建业务实现
VideoStream整体实现过程如图:
VideoStream创建流类型实现
Depth流业务实现
业务描述:
1. 创建Depth流类型; 2. 获取Depth流支持的VideoMode列表; 3. 设置Depth流输出的VideoMode类型,VideoMode类型通过类型过滤检索后设置。 如:D2 VideoMode设置查找分辨率w:400,h:640,PixelFormat:DEPTH_1_MM。
IR流业务实现
业务实现描述:
1. 创建IR流类型; 2. 获取IR流支持的VideoMode列表; 3. 设置IR流输出的VideoMode类型,VideoMode类型通过类型过滤检索后设置。 如:D2 VideoMode设置查找分辨率w:640,h:400,PixelFormat:GRAY16。
Color流业务实现
业务实现描述:
1. 创建Color流类型; 2. 获取Color流支持的VideoMode列表; 3. 设置Color流输出的VideoMode类型,VideoMode类型通过类型过滤检索后设置。 如:P3X VideoMode设置查找分辨率w:384,h:640,PixelFormat:RGB888或YUYV。 注意事项:P3X 该RGB依赖主路UVC RGB,主路UVC RGB输出后该RGB才可输出。
VideoStream开流
VideoStream数据流的获取(请求)分为主动获取和回调两种方式。
主动获取方式
实现方式(开启一个子线程去实现):
videoStream.start();
OpenNI.waitForAnyStream(streams,2000);(** 2000是超时等待的时间, 单位是ms)**
List<VideoStream>可以添加多个VideoStream, 如下:
VideoStream depthstream = VideoStream.create(device, SensorType.DEPTH); VideoStream colorstream = VideoStream.create(device, SensorType.COLOR); List<VideoStream> streams = new ArrayList<VideoStream>(); Streams.add(depthstream); Streams.add(colorstream);
具体接口调用:
接口类 | API | 参数 | 描述 |
OpenNI | waitForAnyStream(List<VideoStream> streams, int timeout); | streams:VideoStream 列表; timeout 等待一帧数据的超时时间; | 这个函数是阻塞的,直到一帧新的可用的数据返回 |
VideoStream | start(); | 无 | 开始流数据生成输出 |
VideoFrameRef | readFrame(); | 无 | 读取一帧数据流引用 |
release(); | 无 | 释放一帧数据流引用 | |
| readFrame()和release() 接口必须一起使用,读完后必须释放,防止内存泄露。 | | |
如图:
回调获取方式
通过设置回调接口实现(优先选择此方案),实现方式:
videoStream.start();
videoStream.addNewFrameListener(newFrameListener);
videoFrameRef.readFrame();
videoFrameRef. Release();
具体接口调用:
接口类 | API | 参数 | 描述 |
VideoStream | start(); | 无 | 打开流数据并输出 |
addNewFrameListener(newFrameListener); | 数据回调接口 | 设置数据流回调 | |
VideoFrameRef | readFrame(); | 无 | 读取一帧数据流引用 |
release(); | 无 | 释放一帧数据流引用 | |
具体接口调用:
接口类 | API | 参数 | 描述 |
NewFrameListener | onFrameReady(VideoStream var1); | var1:返回的流数据引用 | 返回可用的数据流引用,此回调函数中避免执行其他耗时操作。 |
VideoFrameRef的readFrame()和release() 函数必须同时调用,防止内存泄露。 | | | |
详细接口调用如图:
VideoStream 停流
VideoStream停止流后如果要重新获取流数据,需调用开始流的接口,即:“7”步骤。
实现方式:VideoStream.stop();
接口类 | API | 参数 | 描述 |
VideoStream | stop(); | 无 | 停止VideoStream流数据输出 |
removeNewFrameListener(NewFrameListener streamListener) | NewFrameListener | 取消数据异步回调接口监听 | |
通过主动方式实现,详细接口调用如图:
通过回调方式实现,需要移除回调代码:
VideoStream.removeNewFrameListener (newFrameListener);
详细接口调用如图:
VideoStream 销毁
实现方式:VideoStream.destroy();
VideoStream销毁后如果要再获取流需要重新创建VideoStream,即:执行“6”步骤。
接口类 | API | 参数 | 描述 |
VideoStream | destroy(); | 无 | 销毁VideoStream,与 VideoStream创建对应,需同步调用。 |
详细接口调用如图:
img
Device关闭
实现方式:device.close();
调用此接口后,如果要重新打开设备获取流数据,需从“4.2”步骤开始执行。
接口类 | API | 参数 | 描述 |
Device | close(); | 无 | 调用这个接口将关闭任何硬件设备 |
详细接口调用如图:
UsbDevice关闭
实现方式:openNIHelper.shutdown()
此API与步骤“4”对应,如果要重新获取设备需从步骤“4.1”开始执行。
接口类 | API | 参数 | 描述 |
OpenNIHelper | shutdown(); | 无 | 关闭UsbDevice的连接 |
详细接口调用如图:
SDK释放
实现方式:OpenNI.shutdown();
SDK释放与文档“3”对应调用,在调用OpenNI.shutdown()接口前必须释放所有的ViewStream和Device资源,即执行“8、9、10、11”步骤,若要重新使用SDK需从步骤“3”开始操作。若退出整个APP也许调用以上接口。
接口类 | API | 参数 | 描述 |
OpenNI | shutdown(); | 无 | 释放Orbbec-SDK资源 |
详细接口调用如图,建议调用处:
接口协同调用规范
接口协同调用规则指:规定“流数据”在成功获取和停止的原则下,规范正确合理的API调用顺序和调用一一对应原则。
主动获取数据流程规范图
回调模式获取图像流程图
SDK释放
在Android应用程序中退出程序时候需要释放SDK所有资源,例如在Activity的onDestroy ()生命周期函数中去调用。最后退出整个APP时请调用步骤12对应的接口。
释放方式1,逐个资源释放:
释放方式2:
删除数据流回调监听器,关闭Device(关闭Device中会停止和释放VideoStream),释放所有资源:
扩展API接口
Device相关基础接口
获取设备信息
接口类 | API | 参数 | 描述 |
Device | getDeviceInfo() | 无 | 返回DeviceInfo信息 |
设置激光状态
接口类 | API | 参数 | 描述 |
Device | setLaserEnable(boolean enable) | true打开,false关闭 | 打开或者关闭激光 须谨慎调用该接口,无特殊需求可不调用。 |
获取激光使能状态
接口类 | API | 参数 | 描述 |
Device | getLaserEnable() | 无 | 返回true打开,false关闭激光 须谨慎调用该接口,无特殊需求可不调用。 |
设置LDP状态
接口类 | API | 参数 | 描述 |
Device | setLdpEnableRegister(boolean ldpEnable) | true打开false关闭 | 打开或者关闭LDP,这个API接口除了一代Astra系列其他产品使用。 须谨慎调用该接口,无特殊需求可不调用。 |
接口类 | API | 参数 | 描述 |
Device | setLdpEnable(boolean ldpEnable) | true打开false关闭 | 打开或者关闭LDP,这个扩展API,一代Astra系列和一代升级的Astra 系列某些带LDP产品有这个功能 须谨慎调用该接口,无特殊需求可不调用。 |
获取LDP状态
接口类 | API | 参数 | 描述 |
Device | getLdpEnableRegister() | 无 | 读取LDP开关状态,返回true打,false关闭这个API接口除了一代Astra系列其他产品使用。 须谨慎调用该接口,无特殊需求可不调用。 |
设置IR泛光灯状态
接口类 | API | 参数 | 描述 |
Device | setIrFloodEnable(boolean enable) | true打开,false关闭 | 打开或者关闭泛光灯 须谨慎调用该接口,无特殊需求可不调用。 |
获取IR泛光灯状态
接口类 | API | 参数 | 描述 |
Device | getIrFloodEnable() | 无 | true打开,false关闭 须谨慎调用该接口,无特殊需求可不调用。 |
设置IR增益
接口类 | API | 参数 | 描述 |
Device | setGain(int gain) | gain增益值 | 设置设备增益值大小 |
获取IR增益
接口类 | API | 参数 | 描述 |
Device | getGain() | 无 | 返回设备增益大小 |
获取USB类型
接口类 | API | 参数 | 描述 |
Device | getUSBSpeed() | 无 | 返回设备USB类型,具体参照DeviceUSBSpeed |
DeviceUSBSpeed
接口类 | 描述 |
DeviceUSBSpeed | Device USB类型枚举类。 USB_LOW_SPEED = 0; USB_FULL_SPEED = 1; USB_HIGH_SPEED = 2; //USB2.0 USB_SUPER_SPEED = 3;//USB3.0 |
获取相机保存标定参数
接口类 | API | 参数 | 描述 |
Device | getOBCameraParams() | 无 | 返回OBCameraParams相机标定参数 |
获取固件版本号
接口类 | API | 参数 | 描述 |
Device | getFirmwareVersion () | 无 | 返回设备固件版本号 |
获取设备SN号
接口类 | API | 参数 | 描述 |
Device | getSerialNumber() | 无 | 返回设备SN号 |
硬件D2C支持判断
接口类 | API | 参数 | 描述 |
Device | isImageRegistrationModeSupported(ImageRegistrationMode mode) | ImageRegistrationMode | 判断是否支持硬件D2C,一般传参:DEPTH_TO_COLOR |
设置硬件D2C模式
接口类 | API | 参数 | 描述 |
Device | setImageRegistrationMode(ImageRegistrationMode mode) | ImageRegistrationMode | 设置硬件D2C模式,OFF关闭, DEPTH_TO_COLOR打开 |
获取硬件D2C模式
接口类 | API | 参数 | 描述 |
Device | getImageRegistrationMode() | 无 | 返回硬件D2C模式:ImageRegistrationMode,OFF关闭,DEPTH_TO_COLOR打开 |
设置Depth 和IR交替输出模式
接口类 | API | 参数 | 描述 |
Device | setDepthIrAlternateMode(int nMode) | int nMode (DepthIrMode) | 默认数据流输出模式为Depth和散斑IR。 设置Depth和IR交替输出模式,仅仅部分设备支持,如海燕Pro、海燕Plus、P3X,其它USB模组不支持。 |
参数 | 参数描述 |
int nMode | DepthIrMode MODE_DEPTH_NIR(0):Depth和纯净IR模式,即:Depth和纯净IR交错输出; MODE_SPECKLE_IR(1):Depth和散斑IR模式,即:Depth和散斑IR模式同时或单独输出; MODE_NIR(2): 纯净IR模式,即:只输出纯净IR; |
获取Depth 和IR交替输出模式
接口类 | API | 参数 | 描述 |
Device | getDepthIrAlternateMode() | 无 | 获取Depth和IR交替输出模式,仅仅部分设备支持,如海燕Pro、海燕Plus、P3X,其它USB模组不支持。 返回值: 0:Depth 和IR 交错输出; 1:散斑IR模式; 2:纯净IR模式; |
VideoStream相关基础接口
设置镜像
接口类 | API | 参数 | 描述 |
VideoStream | setMirroringEnabled(boolean isEnabled) | booean | 设置VideoStream镜像状态,true打开,false关闭。 |
调用后orbbec.ini配置文件配置无效。 | | | |
获取镜像状态
接口类 | API | 参数 | 描述 |
VideoStream | getMirroringEnabled() | 无 | 返回VideoStream镜像状态,true打开,false关闭。 |
设置VideoMode
接口类 | API | 参数 | 描述 |
VideoStream | setVideoMode(VideoMode videoMode) | VideoMode | VideoStream创建后设置设置分辨率、PixelFormat、帧率(FPS)。 分辨率:根据不同设备决定; PixelFormat: Depth(DEPTH_1_MM); IR(GRAY16),Color(RGB888); FPS:一般设置30FPS,暂时不支持动态设置。 |
| | | 调用后orbbec.ini配置文件配置无效。 |
PixelFormat定义:
Depth : DEPTH_1_MM(100), DEPTH_100_UM(101), SHIFT_9_2(102), SHIFT_9_3(103) IR : RGB888(200), GRAY8(202), GRAY16(203) Color : RGB888(200), YUV422(201), JPEG(204), YUYV(205)
获取VideoMode
接口类 | API | 参数 | 描述 |
VideoStream | getVideoMode() | 无 | 获取当前VideoStream输出的VideoMode模式 |
设置Depth 最大值
接口类 | API | 参数 | 描述 |
VideoStream | setStreamMaxDepth(int maxDepth) | int (单位:mm) | 设置Depth最大值的目的是过滤掉Depth不再这个范围内的点的Depth,需要在VideoStream的create函数和start函数之间设置,设置的参考代码和设置Depth的分辨率类似。 |
设置Depth 最小值
接口类 | API | 参数 | 描述 |
VideoStream | setStreamMinDepth(int minDepth) | int (单位:mm) | 设置Depth最小值的目的是过滤掉Depth不再这个范围内的点的Depth,需要在VideoStream的create函数和start函数之间设置,设置的参考代码和设置Depth的分辨率类似。 |
设置数据输入格式
接口类 | API | 参数 | 描述 |
VideoStream | setStreamInputFormat(StreamInputFormat inputFormat) | int | 设置VideoStream的输入数据格式(固件到SDK),在VideoStream的create函数和start函数之间设置。 |
StreamInputFormat 定义:
Depth : DEPTH_FORMAT_16_BIT(0), DEPTH_FORMAT_10_BIT(2), DEPTH_FORMAT_11_BIT(3), DEPTH_FORMAT_12_BIT(4)
IR : IR_FORMAT_16_BIT(0), IR_FORMAT_10_BIT(2) Color : COLOR_FORMAT_YUV422(5), COLOR_FORMAT_MJPEG(8)
设置HoleFilter
接口类 | API | 参数 | 描述 |
VideoStream | setStreamHoleFilter(int holeFilter) | int | 填洞滤波,0:表示关闭滤波功能,开启时取值1,2,3,4 (HoleFilter代表窗口滤波器的大小,1是 3*3, 2是 5*5, 3是7*7, 4是9*9),在VideoStream的create函数和start函数之间设置。 |
设置SoftFilter
接口类 | API | 参数 | 描述 |
VideoStream | setSoftFilter(SoftFilterType softFilter) | SoftFilterType | 软件滤波,调用该接口需谨慎,会消耗Android平台资源,如影响深度数据的接收。 |
参数 | 参数描述 |
SoftFilterType | CLOSE(0):关闭软件滤波,默认不调用该接口是关闭状态; OPEN(2):打开软件滤波。 |
配置文件介绍
Openni.ini配置文件
Verbosity=0 输出Log的等级; LogToConsole=1 输出Log到控制台 ; LogToFile=1 输出Log到文件; LogToAndroidLog=1 在Android平台输出log
[Log] ;0 - Verbose ;1 - Info ;2 - Warning ;3 - Error. Default - None
Orbbec.ini配置文件
;---------------- Sensor Default Configuration -------------------
[Device]
; Mirroring. 0 - Off , 1 - On (default)
;设置Device的mirror属性,depth和ir、color默认mirror。
;Mirror=1
; FrameSync. 0 - Off (default), 1 - On
;设置depth和color帧同步,只有color是openni协议传输的设备支持帧同步
;FrameSync=1
; Stream Data Timestamps. 0 - milliseconds, 1 - microseconds (default)
;设置时间戳的单位,这个地方不用修改,用默认值。(0:表示ms, 1:表示微秒)
;HighResTimestamps=1
; Stream Data Timestamps Source. 0 - Firmware (default), 1 - Host
;设置时间戳源,不用修改,用默认值,用固件的时间戳 (0:固件时间戳,1:主机的时间戳)
;HostTimestamps=0
; USB interface to be used. 0 - FW Default, 1 - ISO endpoints (default on Windows), 2 - BULK endpoints (default on Linux/Mac/Android machines), 3 - ISO endpoints for low-bandwidth depth
;usb传输类型,值为2,不能修改
UsbInterface=2
[Depth]
; Output format. 100 - 1mm depth values (default), 102 - u9.2 Shift values.
;设置depth的输出格式 100:表示1mm精度;101:100um精度;102:表示输出原始视差;
;OutputFormat=100
; Is stream mirrored. 0 - Off, 1 - On
;覆盖Device 的Mirror值, depth镜像,0:表示关闭镜像;1:表示打开镜像;
;Mirror=1
; 0 - QVGA, 1 - VGA, 4 - QQVGA. Default: Arm - 4, other platforms - 0, -14 1280x720, 15 1280x960,-16 1280x800, -17 640x400 -20 320x200,-21 480x640, -25 960x1280, -26 800x1280,-27 400x640
;设置Depth的分辨率;
Resolution=1
; Frames per second (default is 30)
;设置depth的帧率(目前不支持动态设置分辨率)
;FPS=30
; Min depth cutoff. 0-10000 mm (default is 0)
; 过滤的最小深度值,小于该深度值,过滤掉,置为0。
; 举例:(如:MinDepthValue =300,那么小于30厘米的depth就会过滤掉)
;MinDepthValue=0
; Max depth cutoff. 0-10000 mm (default is 10000)
;过滤最大的深度值,大于该值的depth会过滤掉,置为0 。
;MaxDepthValue=10000
; Input format. 0 - Uncompressed 16-bit, 1 - PS Compression,2 - Packed 10-bit, 3 - Packed 11-bit, 4 - Packed 12-bit. Default: Arm - 4, other platforms - 3
;深度打包格式,现在我们用到的有(10bit,11bit,12bit) 其中3:表示11bit;4:表示12bit;2:表示10bit(D2和Atlas,Mipi公板 设置成2)
;InputFormat=3
; software filter 0-off ,1--on (default)
;软件滤波开关,2.3.0.55 SDK及后续版本支持
;SoftFilter=0
; Depth Rotate 0-off(default) ,1--on (only atlas device support)
;Depth旋转功能,在2.3.0.61版本支持,只有Atlas设备有这个功能
;DepthRotate=0
; Hole Filler. 0 - Off, 1 - On (default)
;填洞滤波,0:表示关闭滤波功能,开启时取值1,2,3,4 :(HoleFilter代表窗口滤波器的大小,1是 3*3, 2是 5*5, 3是7*7, 4是9*9)
;HoleFilter=0
[Image]
;整个[Image]字段只有对走Openni协议 rgb有效,对UVC协议的无效;
; Output format. 200 - RGB888 (default), 201 - YUV422, 202 - Gray8 (2.0 MP only), 205 - YUYV
;设置color图像的输出格式,只有对openni输出的有效,目前支持RGB888(200)和YUV422(201);
;OutputFormat=201
; Is stream mirrored. 0 - Off, 1 - On
;覆盖Device Mirror值,color 图像的镜像方式;0:非镜像;1:镜像
;Mirror=1
; 0 - QVGA (default), 1 - VGA, 2 - SXGA (1.3MP), 3 - UXGA (2.0MP), 14 - 720p, 15 - 1280x960
;设置color图像的分辨率
Resolution=1
; Frames per second (default is 30)
;设置color的帧率,目前我们大部分产品都是恒定帧率,不支持动态设置分辨率
;FPS=30
; Input format. 0 - Compressed 8-bit BAYER (1.3MP or 2.0MP only), 1 - Compressed YUV422 (default in BULK), 2 - Jpeg, 5 - Uncompressed YUV422 (default in ISO), 6 - Uncompressed 8-bit BAYER (1.3MP or 2.0MP only), 7 - Uncompressed YUYV,8 - MJPEG
;设置color图像的打包格式,目前设置成5,不要修改,P3X输出8-MJPEG格式
InputFormat=5
[IR]
; Output format. 200 - RGB888, 203 - Grayscale 16-bit (default)
;设置IR的输出格式
;OutputFormat=203
; Input format. 0 - Uncompressed 16-bit, 1 - PS Compression,2 - Packed 10-bit(default), 3 - Packed 11-bit(Not Supported), 4 - Packed 12-bit(Not Supported).
;IR打包格式,现在我们用到的有(16bit,10bit) 其中0:表示16bit;2:表示10bit(默认输出10bit)
;InputFormat=2
; Is stream mirrored. 0 - Off, 1 - On
;覆盖Device字段的Mirror值,设置IR镜像 0:表示非镜像;1:表示镜像
;Mirror=1
; 0 - QVGA (default), 1 - VGA, 2 - SXGA(1.3MP), 4 - QQVGA. -14 1280x720, 15 1280x960,-16 1280x800, -17 640x400 -20 320x200,-21 480x640, -25 960x1280, -26 800x1280,-27 400x640
;设置IR分辨率,分辨率列表和depth一样
Resolution=1
; Frames per second (default is 30)
;设置帧率,暂时不支持动态设置;;FPS=30
Libuvc应用
Android平台Orbbec模组RGB如果是UVC设备需要使用第三方libuvc应用打开,libuvc使用基于GitHub开源框架UVCCamera:https://github.com/saki4510t/UVCCamera。
详细使用请请参考官方源码,下面只列出如何在libuvc中应用回调方式将原数据返回应用层供客户使用。
数据监听器注册
设置RGB数据回调监听器 |
camera.setFrameCallback(mIFrameCallback, UVCCamera. FRAME_FORMAT_MJPEG); |
数据回调
RGB数据回调监听器
private final IFrameCallback mIFrameCallback = new IFrameCallback() {
@Override public void onFrame(final ByteBuffer frame) {
}
};