从 Project Tango 生成和导出点云

Generate and export point cloud from Project Tango

经过几个星期的等待,我终于有了我的 Project Tango。我的想法是创建一个应用程序,生成我房间的点云并将其导出到 .xyz 数据。然后我将使用 .xyz 文件在浏览器中显示点云!我首先编译和调整 Google 的 github.

上的点云示例

现在我使用 onXyzIjAvailable(TangoXyzIjData tangoXyzIjData) 来获取 x y 和 z 值的帧;点。然后我将这些帧以 Vector3 的形式保存在 PCLManager 中。在我扫描完我的房间后,我简单地将所有 Vector3 从 PCLManager 写入一个 .xyz 文件,使用:

OutputStream os = new FileOutputStream(file);
size = pointCloud.size();
for (int i = 0; i < size; i++) {
    String row = String.valueOf(pointCloud.get(i).x) + " " 
               + String.valueOf(pointCloud.get(i).y) + " " 
               + String.valueOf(pointCloud.get(i).z) + "\r\n";
    os.write(row.getBytes());
}
os.close();

一切正常,没有编译错误或崩溃。唯一似乎出错的是云中点的旋转或平移。当我查看点云时,一切都乱七八糟;我扫描的区域无法识别,但点数与记录的相同。

这可能与我没有将 PoseData 与 XyzIjData 一起使用这一事实有关吗?我对这个主题有点陌生,很难理解 PoseData 到底做了什么。有人可以向我解释并帮助我修复点云吗?

是的,你必须使用 TangoPoseData

我猜你使用 TangoXyzIjData 是正确的;但是您通过这种方式获得的数据与设备的位置以及拍摄时设备的倾斜方式有关。

这是我解决这个问题的方法:
我从 java_point_to_point_example 开始。在此示例中,他们使用 2 个不同的坐标系获取 2 个不同点的坐标,然后将这些坐标写入基本坐标系对。

首先你必须设置你的 exstrinsics,这样你就可以执行你需要的所有转换。为此,我在 setTangoListener() 函数的末尾调用了 mExstrinsics = setupExtrinsics(mTango) 函数。这是代码(您也可以在我上面链接的示例中找到)。

private DeviceExtrinsics setupExtrinsics(Tango mTango) {
    //camera to IMU tranform
    TangoCoordinateFramePair framePair = new TangoCoordinateFramePair();
    framePair.baseFrame = TangoPoseData.COORDINATE_FRAME_IMU;
    framePair.targetFrame = TangoPoseData.COORDINATE_FRAME_CAMERA_COLOR;
    TangoPoseData imu_T_rgb = mTango.getPoseAtTime(0.0,framePair);
    //IMU to device transform
    framePair.targetFrame = TangoPoseData.COORDINATE_FRAME_DEVICE;
    TangoPoseData imu_T_device = mTango.getPoseAtTime(0.0,framePair);
    //IMU to depth transform
    framePair.targetFrame = TangoPoseData.COORDINATE_FRAME_CAMERA_DEPTH;
    TangoPoseData imu_T_depth = mTango.getPoseAtTime(0.0,framePair);
    return new DeviceExtrinsics(imu_T_device,imu_T_rgb,imu_T_depth);
}

然后当你得到点云时你必须"normalize"它。使用你的 exstrinsics 非常简单:

public ArrayList<Vector3> normalize(TangoXyzIjData cloud, TangoPoseData cameraPose, DeviceExtrinsics extrinsics) {
    ArrayList<Vector3> normalizedCloud = new ArrayList<>();

    TangoPoseData camera_T_imu = ScenePoseCalculator.matrixToTangoPose(extrinsics.getDeviceTDepthCamera());

    while (cloud.xyz.hasRemaining()) {
        Vector3 rotatedV = ScenePoseCalculator.getPointInEngineFrame(
                new Vector3(cloud.xyz.get(),cloud.xyz.get(),cloud.xyz.get()),
                camera_T_imu,
                cameraPose
        );
        normalizedCloud.add(rotatedV);
    }

    return normalizedCloud;
}

这应该足够了,现在你有了一个点云和你的基本参考系。 如果您叠加两个或更多这样的 "normalized" 云,您可以获得房间的 3D 表示。

解释了 ,还有另一种使用旋转矩阵执行此操作的方法。

我的解决方案非常慢(开发工具包需要大约 700 毫秒才能标准化约 3000 点的云),因此它不适合 3D 重建的实时应用程序。

Atm 我正在尝试使用 NDK 和 JNI 在 C 中使用 Tango 3D 重建库。该库有很好的文档记录,但设置环境并开始使用 JNI 非常痛苦。 (事实上​​我现在卡住了)。

随波逐流

There still is a problem when I turn around with the device. It seems that the point cloud spreads out a lot.

我猜你正在经历一些漂移。
当您单独使用 Motion Tracking 时会发生漂移:它由许多非常小的错误组成,在估计您的 Pose 时,所有这些都会导致很大的错误你相对于世界的姿势。例如,如果你拿着你的探戈设备绕着圈走,跟踪你的TangoPoseData,然后你在电子表格或任何你想要的东西中画出你的轨迹,你会注意到平板电脑永远不会return起点,因为他渐行渐远。
解决方案是使用 区域学习 。 如果您对这个主题没有明确的想法,我建议您观看 2016 年 Google I/O 中的 talk。它将涵盖很多要点并给您一个很好的介绍。

使用区域学习非常简单。
您只需在 TangoPoseData.COORDINATE_FRAME_AREA_DESCRIPTION 中更改 基准参考系 。通过这种方式,您可以告诉您的 Tango 估计他的姿势,而不是根据您启动应用程序时的位置,而是根据该区域中的某个固定点。 这是我的代码:

private static final ArrayList<TangoCoordinateFramePair> FRAME_PAIRS = 
    new ArrayList<TangoCoordinateFramePair>();
{
    FRAME_PAIRS.add(new TangoCoordinateFramePair(
            TangoPoseData.COORDINATE_FRAME_AREA_DESCRIPTION,
            TangoPoseData.COORDINATE_FRAME_DEVICE
    ));
}

现在您可以像往常一样使用这个 FRAME_PAIRS

然后你必须修改你的 TangoConfig 以便使用密钥 TangoConfig.KEY_BOOLEAN_DRIFT_CORRECTION 发布 Tango 以使用 区域学习。请记住,在使用 TangoConfig.KEY_BOOLEAN_DRIFT_CORRECTION 时,您不能使用学习模式并加载 ADF(区域描述文件)。
所以你不能使用:

  • TangoConfig.KEY_BOOLEAN_LEARNINGMODE
  • TangoConfig.KEY_STRING_AREADESCRIPTION

以下是我在我的应用程序中初始化 TangoConfig 的方式:

TangoConfig config = tango.getConfig(TangoConfig.CONFIG_TYPE_DEFAULT);
//Turning depth sensor on.
config.putBoolean(TangoConfig.KEY_BOOLEAN_DEPTH, true);
//Turning motiontracking on.
config.putBoolean(TangoConfig.KEY_BOOLEAN_MOTIONTRACKING,true);
//If tango gets stuck he tries to autorecover himself.
config.putBoolean(TangoConfig.KEY_BOOLEAN_AUTORECOVERY,true);
//Tango tries to store and remember places and rooms,
//this is used to reduce drifting.
config.putBoolean(TangoConfig.KEY_BOOLEAN_DRIFT_CORRECTION,true);
//Turns the color camera on.
config.putBoolean(TangoConfig.KEY_BOOLEAN_COLORCAMERA, true); 

使用此技术,您将消除这些价差。

PS
在我上面链接的谈话中,大约 22:35 他们向您展示了如何将您的应用程序移植到 Area Learning。在他们的示例中,他们使用 TangoConfig.KEY_BOOLEAN_ENABLE_DRIFT_CORRECTION。此密钥不再存在(至少在 Java API 中)。请改用 TangoConfig.KEY_BOOLEAN_DRIFT_CORRECTION