概览¶
这篇文章介绍了EasyAR Sense 3.0/4.0的API结构。
EasyAR Sense的API在3.0/4.0版本中,对原有API按照数据流进行了组件化的组织,使得EasyAR Sense可以更容易与其他系统进行对接,以满足更为灵活的需求。
结构¶
输入输出数据¶
InputFrame : 输入帧。包含图像、camera参数、时间戳、相机相对于世界坐标系的变换和跟踪状态。其中,camera参数、时间戳、相机相对于世界坐标系的变换和跟踪状态均为可选,但特定的算法组件会对输入有特定的要求。
OutputFrame : 输出帧。包含输入帧和同步处理组件的输出结果。
FeedbackFrame : 反馈帧。包含一个输入帧和一个历史输出帧,用于 ImageTracker 等反馈式同步处理组件。
Camera组件¶
CameraDevice : Windows、Mac、iOS、Android上的默认摄像头。
ARKitCameraDevice : iOS上的ARKit默认实现。(4.0版本功能)
ARCoreCameraDevice : Android上的ARCore默认实现。(4.0版本功能)
MotionTrackerCameraDevice :实现运动跟踪,通过多传感器融合解算设备的6DOF坐标。(4.0版本功能,只支持Android)
custom camera device: 自定义摄像头实现。
算法组件¶
反馈式同步处理组件:需要每帧跟着摄像机图像输出结果,并且需要上一帧处理结果用于避免相互干扰。
ImageTracker : 实现了平面卡片的检测和跟踪。
ObjectTracker :实现了3D object target的检测和跟踪。(Pro版本功能)
同步处理组件:需要每帧跟着摄像机图像输出结果。
SurfaceTracker :实现了对环境表面的跟踪。
SparseSpatialMap :实现了稀疏空间地图,提供了扫描物理空间同时生成点云地图并进行实时定位的能力。(4.0版本功能)
异步处理组件:不需要每帧跟着摄像机图像输出结果。
CloudRecognizer :实现了云识别。
DenseSpatialMap :实现了稠密空间地图,可用于实现碰撞、遮挡等效果。(4.0版本功能)
组件的可用性检查¶
所有的组件均有isAvailable函数,可用于判断该组件是否可用。
组件不可用的情况有
当前操作系统上没有实现。
组件所需要的依赖不存在,例如ARKit, ARCore。
组件在当前版本(variant)上不存在,例如一些精简版本中某些功能不存在。
组件在当前License下不可用。
使用组件之前务必要判断组件是否可用,并进行相应的fallback或者提示。
数据流¶
组件的连接方式如下图所示。
数据流辅助类¶
数据流的发出和接收端口,各组件需要包含这些端口
SignalSink / SignalSource :接收/发出一个信号(无数据)。
InputFrameSink / InputFrameSource :接收/发出一个 InputFrame 。
OutputFrameSink / OutputFrameSource :接收/发出一个 OutputFrame 。
FeedbackFrameSink / FeedbackFrameSource :接收/发出一个 FeedbackFrame 。
数据流的分支和合并
InputFrameFork :将一个 InputFrame 分成多个并行发出。
OutputFrameFork :将一个 OutputFrame 分成多个并行发出。
OutputFrameJoin :将多个 OutputFrame 合并成一个,并将所有的结果合并到Results中。需要注意其多个输入的连接不应该在有数据流入的同时进行,否则可能会陷入不能输出的状态。(推荐在Camera启动之前完成数据流连接。)
FeedbackFrameFork :将一个 FeedbackFrame 分成多个并行发出。
数据流的限流和缓存
InputFrameThrottler :接收并发出 InputFrame ,但一次只发出一个,只有在接收到一个触发信号后才会发出下一个 InputFrame ,接收到多个 InputFrame 时,后续的 InputFrame 可能会覆盖前面的 InputFrame 。
OutputFrameBuffer :接收 OutputFrame 并缓存,等待用户轮询,接收到 OutputFrame 的时候可以发出一个信号。
将 OutputFrameBuffer 发出的信号接到 InputFrameThrottler 上,即可完成整个限流过程。
数据流的转换
InputFrameToOutputFrameAdapter :可以将一个 InputFrame 直接包装成 OutputFrame ,用于渲染显示。
InputFrameToFeedbackFrameAdapter :可以将一个 InputFrame 和一个 FeedbackFrame 包装成 FeedbackFrame ,用于反馈式同步处理组件。
InputFrame数量的限制¶
CameraDevice 可以设置bufferCapacity,即发出 InputFrame 的最大数量,当前的默认值为8。
自定义摄像头可以使用 BufferPool 实现。
各组件需要的 InputFrame 数量,参考各组件的API文档。
如果 InputFrame 数量不足,可能造成数据流卡住,导致渲染卡住。
如果 InputFrame 数量不足,也有可能第一次启动不会渲染卡住,但切换到后台或暂停/启动各组件后渲染卡住,测试时需要注意覆盖到。
连接和断开连接¶
不推荐在数据流运行过程中连接和断开连接。
如果需要在运行过程中进行连接和断开连接,需要注意只能在割边上进行,不能在无向环的边上、OutputFrameJoin 的输入或者 InputFrameThrottler 的sideInput上进行,否则可能会陷入数据流卡在 OutputFrameJoin 和 InputFrameThrottler 等结点无法输出的状态。
算法组件均有start/stop功能,在stop的时候,帧将不会被处理,但仍然会从组件中输出,只是不带有结果。
典型用法¶
线程安全模型¶
每个类,如果不加说明,则其静态成员是线程安全的。
每个类,如果不加说明,则其实例成员在外部加锁的情况下是线程安全的,在不加锁的情况下不是线程安全的。
每个类,如果不加说明,则其析构函数可以在结束对对象的其他调用后,从任意线程调用,此时是线程安全的。
内存模型¶
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说明中的定义一致)