Table of Contents

外部帧数据源的输入帧数据要求

为使外部帧数据源正常工作,最重要的工作同时也是最棘手的部分是确保数据正确性。本文介绍了外部帧数据源的输入帧数据要求。

开始之前

输入帧数据类型

在 Unity 中,外部帧数据源通常需要在两个不同时间接收不同的数据,根据外部数据输入时间和数据特征,我们将这两组数据称为:

  1. 相机帧数据(camera frame data)
  2. 渲染帧数据(rendering frame data)

不同类型的外部帧数据源对这两组数据的需求不同:

  • 图像和设备运动数据输入扩展:同时需要相机帧数据及渲染帧数据
  • 图像输入扩展:只需要相机帧数据

相机帧数据

数据需求:

  1. 时间戳(timestamp)
  2. 原始物理相机图像数据(raw camera image data)
  3. 内参(intrinsics,包括图像大小、焦距、主点。如果有畸变还需要畸变模型和畸变参数)
  4. 外参(extrinsics,Tcw 或 Twc,标定的矩阵,表达物理相机相对设备/头的 pose 原点的物理偏移)
  5. 跟踪状态(tracking status)
  6. 设备位姿(device pose)

数据时间:

  • 物理相机曝光中点

数据使用:

  • API 调用时间:可根据外部代码的设计改变。一个大多数设备使用的常规方法是在 3D 引擎的渲染更新中查询,然后根据设备数据的时间戳来判断是否进一步进行数据处理
  • API 调用线程:3D 引擎的 game thread 或任何其它线程(如果使用到的所有外部 API 都是线程安全的)

Unity 中 API 调用示例如下:

void TryInputCameraFrameData()
{
    double timestamp;

    if (timestamp == curTimestamp) { return; }
    curTimestamp = timestamp;

    PixelFormat format;
    Vector2Int size;
    Vector2Int pixelSize;
    int bufferSize;

    var bufferO = TryAcquireBuffer(bufferSize);
    if (bufferO.OnNone) { return; }
    var buffer = bufferO.Value;

    IntPtr imageData;
    buffer.tryCopyFrom(imageData, 0, 0, bufferSize);

    var historicalHeadPose = new Pose();
    MotionTrackingStatus trackingStatus = (MotionTrackingStatus)(-1);

    using (buffer)
    using (var image = Image.create(buffer, format, size.x, size.y, pixelSize.x, pixelSize.y))
    {
        HandleCameraFrameData(deviceCamera, timestamp, image, cameraParameters, historicalHeadPose, trackingStatus);
    }
}

渲染帧数据

数据需求:

  1. 时间戳(timestamp)
  2. 跟踪状态(tracking status)
  3. 设备位姿(device pose)

数据时间:

  • 上屏时刻。TimeWarp 不计算在内。相同时刻的 device pose 数据会由外部(比如设备 SDK)用来设置虚拟摄像机的 transform 以渲染当前帧。
注意

TimeWarp(有时也称为 Reprojection 或 ATW/PTW)是 VR/AR 头显中常用的一种降低延迟的技术。它会在渲染完成后,根据最新的头部位姿对图像进行再次扭曲变换,以补偿渲染期间产生的头部运动。EasyAR 需要的是渲染开始时用于设置虚拟摄像机的位姿对应的时刻,而不是 TimeWarp 后实际上屏的时刻。

数据使用:

  • API 调用时间:3D 引擎的每个渲染帧
  • API 调用线程:3D 引擎的 game thread

Unity 中 API 调用示例如下:

void TryInputCameraFrameData()
{
    double timestamp;

    if (timestamp == curTimestamp) { return; }
    curTimestamp = timestamp;

    PixelFormat format;
    Vector2Int size;
    Vector2Int pixelSize;
    int bufferSize;

    var bufferO = TryAcquireBuffer(bufferSize);
    if (bufferO.OnNone) { return; }
    var buffer = bufferO.Value;

    IntPtr imageData;
    buffer.tryCopyFrom(imageData, 0, 0, bufferSize);

    var historicalHeadPose = new Pose();
    MotionTrackingStatus trackingStatus = (MotionTrackingStatus)(-1);

    using (buffer)
    using (var image = Image.create(buffer, format, size.x, size.y, pixelSize.x, pixelSize.y))
    {
        HandleCameraFrameData(deviceCamera, timestamp, image, cameraParameters, historicalHeadPose, trackingStatus);
    }
}

渲染帧数据

数据需求:

  1. 时间戳(timestamp)
  2. 跟踪状态(tracking status)
  3. 设备位姿(device pose)

数据要求细节

物理相机图像数据:

  • 图像坐标系:在传感器水平时获取的数据也应是水平的。数据应该以左上角为原点,行优先存储。图像不应翻转或颠倒。
  • 图像 FPS:正常 30 或 60 fps 的数据都可以。如果高 fps 有特殊影响,为达到合理的算法效果,最小可接受帧率为 2。建议使用高于 2 的 fps,通常情况下使用原始数据帧率即可。
  • 图像尺寸:为获取更好的计算结果,最大边应为 960 或更大。正常不鼓励在数据链路中进行耗时的图像缩放,建议直接使用原始数据,除非完整大小的数据拷贝时间已经长得无法接受。图像分辨率不能小于 640*480。
  • 像素格式:优先跟踪效果并综合考虑性能,通常格式优先顺序为 YUV > RGB > RGBA > Gray (YUV中的Y分量)。在使用 YUV 数据时,需要完整的数据定义,包括数据封装和填充细节。相较单通道图像而言,使用彩色图像 Mega 的效果会更好,但其它功能影响不大。
  • 数据访问:数据指针或等价实现。最好在数据链路中消除所有可能的非必须拷贝。HandleRenderFrameData 中 EasyAR 复制一份数据,之后异步使用,该同步调用完成后就不再使用图像数据。注意数据所有权。

Unity 中 API 调用示例如下:

void TryInputCameraFrameData()
{
    double timestamp;

    if (timestamp == curTimestamp) { return; }
    curTimestamp = timestamp;

    PixelFormat format;
    Vector2Int size;
    Vector2Int pixelSize;
    int bufferSize;

    var bufferO = TryAcquireBuffer(bufferSize);
    if (bufferO.OnNone) { return; }
    var buffer = bufferO.Value;

    IntPtr imageData;
    buffer.tryCopyFrom(imageData, 0, 0, bufferSize);

    var historicalHeadPose = new Pose();
    MotionTrackingStatus trackingStatus = (MotionTrackingStatus)(-1);

    using (buffer)
    using (var image = Image.create(buffer, format, size.x, size.y, pixelSize.x, pixelSize.y))
    {
        HandleCameraFrameData(deviceCamera, timestamp, image, cameraParameters, historicalHeadPose, trackingStatus);
    }
}

渲染帧数据

数据需求:

  1. 时间戳(timestamp)
  2. 跟踪状态(tracking status)
  3. 设备位姿(device pose)

后续步骤

相关主题

  • EasyAR 坐标系
  • 图像输入扩展示例 Workflow_FrameSource_ExternalImageStream