API概览

这篇文章介绍了EasyAR Sense 4.0的API结构。

EasyAR Sense的API在3.0/4.0版本中,对原有API按照数据流进行了组件化的组织,使得EasyAR Sense可以更容易与其他系统进行对接,以满足更为灵活的需求。

结构

../_images/Overview_architecture.png

输入输出数据

../_images/Overview_input_output.png

InputFrame : 输入帧。包含图像、camera参数、时间戳、相机相对于世界坐标系的变换和跟踪状态。其中,camera参数、时间戳、相机相对于世界坐标系的变换和跟踪状态均为可选,但特定的算法组件会对输入有特定的要求。

OutputFrame : 输出帧。包含输入帧和同步处理组件的输出结果。

FeedbackFrame : 反馈帧。包含一个输入帧和一个历史输出帧,用于 ImageTracker 等反馈式同步处理组件。

Camera组件

CameraDevice : Windows、Mac、iOS、Android上的默认摄像头。

ARKitCameraDevice : iOS上的ARKit默认实现。

ARCoreCameraDevice : Android上的ARCore默认实现。

MotionTrackerCameraDevice :实现运动跟踪,通过多传感器融合解算设备的6DOF坐标。(只支持Android)

custom camera device: 自定义摄像头实现。

算法组件

反馈式同步处理组件:需要每帧跟着摄像机图像输出结果,并且需要上一帧处理结果用于避免相互干扰。

同步处理组件:需要每帧跟着摄像机图像输出结果。

  • SurfaceTracker :实现了对环境表面的跟踪。

  • SparseSpatialMap :实现了稀疏空间地图,提供了扫描物理空间同时生成点云地图并进行实时定位的能力。

异步处理组件:不需要每帧跟着摄像机图像输出结果。

组件的可用性检查

所有的组件均有isAvailable函数,可用于判断该组件是否可用。

组件不可用的情况有

  • 当前操作系统上没有实现。

  • 组件所需要的依赖不存在,例如ARKit, ARCore。

  • 组件在当前版本(variant)上不存在,例如一些精简版本中某些功能不存在。

  • 组件在当前License下不可用。

使用组件之前务必要判断组件是否可用,并进行相应的fallback或者提示。

数据流

组件的连接方式如下图所示。

../_images/Overview_dataflow.png ../_images/Overview_dataflow_feedback.png

数据流辅助类

数据流的发出和接收端口,各组件需要包含这些端口

数据流的分支和合并

数据流的限流和缓存

数据流的转换

InputFrame数量的限制

CameraDevice 可以设置bufferCapacity,即发出 InputFrame 的最大数量,当前的默认值为8。

自定义摄像头可以使用 BufferPool 实现。

各组件需要的 InputFrame 数量,参考各组件的API文档。

如果 InputFrame 数量不足,可能造成数据流卡住,导致渲染卡住。

如果 InputFrame 数量不足,也有可能第一次启动不会渲染卡住,但切换到后台或暂停/启动各组件后渲染卡住,测试时需要注意覆盖到。

连接和断开连接

不推荐在数据流运行过程中连接和断开连接。

如果需要在运行过程中进行连接和断开连接,需要注意只能在割边上进行,不能在无向环的边上、OutputFrameJoin 的输入或者 InputFrameThrottler 的sideInput上进行,否则可能会陷入数据流卡在 OutputFrameJoinInputFrameThrottler 等结点无法输出的状态。

算法组件均有start/stop功能,在stop的时候,帧将不会被处理,但仍然会从组件中输出,只是不带有结果。

典型用法

../_images/Overview_single_ImageTracker.png ../_images/Overview_multiple_ImageTracker.png ../_images/Overview_SparseSpatialMap.png ../_images/Overview_Sparse_DenseSpatialMap.png

线程安全模型

每个类,如果不加说明,则其静态成员是线程安全的。

每个类,如果不加说明,则其实例成员在外部加锁的情况下是线程安全的,在不加锁的情况下不是线程安全的。

每个类,如果不加说明,则其析构函数可以在结束对对象的其他调用后,从任意线程调用,此时是线程安全的。

内存模型

EasyAR Sense内部使用C++的std::shared_ptr进行引用计数,而引用计数和垃圾回收之前存在着根本上的不兼容,不能无缝转换。

  • 对于C, Traditional C++, C#, Java/Kotlin

    • 需要进行手动引用计数,使用dispose释放持有的对象的引用,使用clone从一个引用创建一个新的引用。

    • 特别需要注意的是传入到EasyAR Sense的回调的参数会在回调结束后自动释放,如果需要保留必须进行clone,自动释放的原因是为了支持传入没有任何逻辑的回调。

    • 需要注意的是传入到EasyAR Sense的回调中如果使用到EasyAR Sense的对象可能导致循环引用,需要当成资源(例如文件、操作系统句柄)进行手动释放,防止内存泄漏。

  • 对于C++17, Objective-C, Swift

    • 使用语言内置的引用计数。

    • 需要注意的是传入到EasyAR Sense的回调中如果使用到EasyAR Sense的对象可能导致循环引用,应合理使用引用捕捉、std::weak_ptr等。

向量和坐标系

如果没有特别说明,则采用以下惯例。

  • 向量均为列向量。

  • 矩阵均采用row-major。(OpenGL为column-major)

  • 坐标系均采用右手坐标系。(与OpenGL一致)

  • 世界坐标系的Y轴负方向为重力方向。

  • 设备坐标系的X轴向右,Y轴向上,Z轴为屏幕向外;对于屏幕可以旋转的设备,右和上的定义以其默认方向为准,特别的,Android的默认方向遵循系统定义(眼镜和部分平板的横屏放置为默认方向,手机和部分平板竖屏放置为默认方向),iOS的默认方向为竖屏放置。(与Android和iOS的IMU说明中的定义一致)