带你认识Google 屌炸天的AR增强现实技术——Tango

这两年虚拟现实VR和增强现实AR简直火的不要不要的,众多巨头都在发力,Google也推出了自己的AR技术解决方案,因为目前介绍Tango的中文资料还比较少,所以本人结合官网文档和自己的理解写了本文,如有错漏请不吝赐教。

一、简介

1. Tango是什么,可以用来干什么?

Tango是Google的一个AR增强现实项目,配合其独特的移动设备和SDK可以方便的在应用中使用AR技术。

2. Tango室内定位为什么有很高的精确度?

众所周知,传统的定位技术(GPS\\WIFI等)在室内定位上精度很低,那么Tango是怎么实现室内定位的呢?

Tango采用的是“参照定位”,即相对于“初始位置”的一种定位方式,不涉及到卫星定位。它根据硬件设备的传感器,比如重力传感器、IMU陀螺仪等,获取移动设备相对于初始位置的“位移”和“旋转角度”,自己构建了一个“参照坐标系”,因此有较高的准确度。

当然,还有其他一些软件技术手段,比如通过区域学习修正偏差等。

3. 几个重要的概念

Tango中如下3个概念,其实也算是3个功能模块。开发者通过设置TangoConfig对象的相应字段来选择开启哪些功能。

a. 移动追踪(motion tracking)

移动追踪指的是,Tango会记录追踪移动设备的在3D空间中的位置,位置数据包括地点和超像旋转角度等、实时报告给应用。

b. 区域学习(Area Leaning)

移动追踪只会反馈移动设备当前的坐标信息、对于设备“看”到的东西没有任何记忆,区域学习使移动设备能够看到和记住物理空间的关键视觉特征,比如边缘,角落等。

区域学习会把看到的保存起来,下次再次“看”到的时候会进行匹配,利用这些数据修正误差(漂移修正),使得轨迹追踪、定位更加准确。

c. 深度感知(Depth Perception)

深度感知给予设备“明白”物体之间的距离,这是通过独特的硬件设备技术实现的,比如“结构光”、“光速飞行时间TOF”和Stereo立体测量

4. Tango的简单使用方式

在Android中,Tango是一个后台Sevice,负责AR工作。我们使用Tango的方式就是启动这个Service,与其进行交互。

Tango主要有如下两个对象:

private Tango mTango; //Tnago对象
private TangoConfig mConfig;  //配置

按照需求对TangoConfig类进行配置,下面代码配置了移动追踪和自动恢复

 private TangoConfig setupTangoConfig(Tango tango) {
       
        TangoConfig config = tango.getConfig(TangoConfig.CONFIG_TYPE_DEFAULT);
        //开启移动追踪功能
        config.putBoolean(TangoConfig.KEY_BOOLEAN_MOTIONTRACKING, true);

        // 自动恢复
        config.putBoolean(TangoConfig.KEY_BOOLEAN_AUTORECOVERY, true);
        return config;
    }

初始化Tango,调用它的connect()方法。

 @Override
    protected void onResume() {
        super.onResume();

        mTango = new Tango(HelloMotionTrackingActivity.this, new Runnable() {
            @Override
            public void run() {
                synchronized (HelloMotionTrackingActivity.this) {
                        mConfig = setupTangoConfig(mTango);
                        mTango.connect(mConfig);
                        startupTango(); //处理数据
                }
            }
        });
    }

通过回调处理数据,上一步中处理数据的方法是startupTango(),其源码如下

  private void startupTango() {
        //设置坐标参照系
        final ArrayList<TangoCoordinateFramePair> framePairs =
                new ArrayList<TangoCoordinateFramePair>();
        framePairs.add(new TangoCoordinateFramePair(
                TangoPoseData.COORDINATE_FRAME_START_OF_SERVICE,
                TangoPoseData.COORDINATE_FRAME_DEVICE));

        // 通过回调获取和处理坐标数据
        mTango.connectListener(framePairs, new OnTangoUpdateListener() {
            @Override
            public void onPoseAvailable(final TangoPoseData pose) {
                //在这里写处理移动追踪和区域学习数据的代码
            }

            @Override
            public void onXyzIjAvailable(TangoXyzIjData xyzIj) {
                // We are not using onXyzIjAvailable for this app.
            }

            @Override
            public void onPointCloudAvailable(TangoPointCloudData pointCloud) {
                // 如果开启深度感知,则在这里处理点阵信息
            }

            @Override
            public void onTangoEvent(final TangoEvent event) {
                //在这里处理各种事件,比如鱼眼摄像头出问题,pose数据失效事件等
            }

            @Override
            public void onFrameAvailable(int cameraId) {
                // We are not using onFrameAvailable for this application.
            }
        });
    }

应用不在前台的时候,断开和Tango的连接(官网推荐的用法)

 @Override
    protected void onPause() {
        super.onPause();
        synchronized (this) {
            mTango.disconnect();
          }
    }

二、开发者必备

1. 学习资料

2. 开发方式

开发方式 软件需求 设备
Java Android Android Studio、 TangoReleaseLibs(Tango SDK) Tango Device
Unity Android Unity 5.2.1以上(配置好Android开发环境)、Tango Unity SDK Tango Device

注:Android API版本 只支持 API Level 17 及以上,Tango Device是必须的,没有其独特的感应设备,Tango没办法正常工作。

三、移动追踪(motion tracking)

1. Tango的坐标数据——pose

pose是Tango中的坐标表示,其具体的Java对象是TangoPoseData,其包含了两个信息:三维坐标、物体的朝向,其结构如下:

struct PoseData {
    double orientation[4]; //朝向信息,四元数表示
    double translation[3]; //三维坐标信息
}

三维坐标系可以用下图表示,当我们正常站立手持移动设备面向自己的脸部时,X轴的正方向是向右的。

image

朝向信息,也可以说成旋转信息,如下图理解,三个方向上的旋转,用四元数表示(这个我不太懂,三个旋转用四元数表示好像是为了方便计算,具体请百度)。

image

2. pose的生命周期

pose数据是有可能失效的,比如鱼眼摄像头发生了错误导致出错等。下图 是pose数据的状态转换图。

image

3. 应用获取和处理pose数据

private void startupTango() {
        // 设置坐标参照系
        final ArrayList<TangoCoordinateFramePair> framePairs =
                new ArrayList<TangoCoordinateFramePair>();
        framePairs.add(new TangoCoordinateFramePair(
                TangoPoseData.COORDINATE_FRAME_START_OF_SERVICE,
                TangoPoseData.COORDINATE_FRAME_DEVICE));

        // 在回调中获取坐标信息
        mTango.connectListener(framePairs, new OnTangoUpdateListener() {
            @Override
            public void onPoseAvailable(final TangoPoseData pose) {
                logPose(pose);
            }

          });
    }

    /**
     *  打印坐标信息
     */
    private void logPose(TangoPoseData pose) {
        StringBuilder stringBuilder = new StringBuilder();

        float translation[] = pose.getTranslationAsFloats();
        stringBuilder.append("Position: " +
                translation[0] + ", " + translation[1] + ", " + translation[2]);

        float orientation[] = pose.getRotationAsFloats();
        stringBuilder.append(". Orientation: " +
                orientation[0] + ", " + orientation[1] + ", " +
                orientation[2] + ", " + orientation[3]);

        Log.i(TAG, stringBuilder.toString());
    }

四、区域学习(Area Leaning)

1. ADF文件

区域学习将设备“看到的信息”保存成ADF(Area Description File)文件,采用UUID进行唯一标识。ADF文件算是一种持久化的数据,可以重复利用。

ADF文件实际上是一种键值对的文件形式,它其中保存了区域学习记录的信息,但是这些空间信息不需要也不允许开发者进行修改,其他官网公开的属性有如下几个:

键值 解释
KEY_UUID UUID唯一标识
KEY_NAME 文件的name
KEY_TRANSFORMATION ADF到全局坐标的一个转换 (x, y, z, qx, qy, qz, qw)
KEY_DATE_MS_SINCE_EPOCH ADF文件保存的时间

此外,我们也可以加入一些自己定义的键值对信息。

2. 区域重定位(区域匹配)

如果载入使用以前的ADF文件,要实现正常的功能,必须进行一个重定位过程,用户要手持设备走到现实中与载入的ADF匹配的地域,tango会将环境信息和ADF文件信息做匹配,匹配成功了即意味着“重定位”成功。

区域匹配是有可能失败的,Tango的区域匹配成功率与环境的“多样性”有关,如果环境很空旷,或者各个房间都是一模一样的,那么区域学习和匹配陈功率较低。如果环境中有各式各样的物品,那么成功率较高。

3. 加载和使用ADF文件示例

开启区域学习

TangoConfig mConfig = mTango.getConfig(TangoConfig.CONFIG_TYPE_CURRENT);
mConfig.putBoolean(TangoConfig.KEY_BOOLEAN_LEARNINGMODE, true);

加载特定UUID标识的ADF文件

 mConfig.putString(TangoConfig.KEY_STRING_AREADESCRIPTION, uuid);

获取最近所有的ADF文件

ArrayList<String> fullUUIDList = new ArrayList<String>();

fullUUIDList = mTango.listAreaDescriptions();

保存当前的ADF文件,这个可能很耗时,不要在UI线程做(官方提供了SaveAdfTask来做这件事)。

Tango.saveAreaDescription()

在回调中处理区域学习的位置数据,因为文章开头有讲述,其他步骤省略了。

@Override
public void onPoseAvailable(TangoPoseData pose) {

if (pose.baseFrame == TangoPoseData.COORDINATE_FRAME_AREA_DESCRIPTION
        && pose.targetFrame == TangoPoseData.COORDINATE_FRAME_DEVICE) {
    // 这个条件意味着移动设备到了一个新的位置
}
else if (pose.baseFrame == TangoPoseData.COORDINATE_FRAME_AREA_DESCRIPTION
        && pose.targetFrame == TangoPoseData.COORDINATE_FRAME_START_OF_SERVICE) {
    // 这个条件告诉我们,设备回到了ADF文件区域的开始位置,也意味着重定位过程成功。
    //开发者可以视其为重定位成功的信号
}

五、深度感知(Depth Perception)

深度感知目前为平衡对设备和处理器的要求,理想的扫描距离为0.5米到4米之间,近距离物品扫描和手势检测并不完美。对于采用红外光技术的深度感知设备,在如下两种情况有可能工作不正常:

  • 环境中红外光在光源中占据较高比例,比如阳光和白炽灯照射的区域
  • 不反射红外光的物品难以被正常扫描

深度感知的工作原理就是扫描摄像头照射的区域,对照射到的物品计算其空间位置,给出一大堆三维点阵的信息(point cloud)

深度感知仍旧在回调里面编写获取数据的方法,回调中不能做耗时操作,如果上次回调没有完成,因为你无法获取最新的数据。

  @Override
  public void onPointCloudAvailable(final TangoPointCloudData pointCloudData) {
       //在这里处理点阵数据
    }

六、 总结

1. Tango功能总结

功能 数据表示 对应的数据类 用途
移动追踪 三维坐标信息和物体的朝向信息 TangoPoseData 检测移动设备的位置和朝向
区域学习 ADF文件 TangoAreaDescriptionMetaData 提高移动追踪的准确度、记忆空间信息(做室内导航)
深度学习 点阵信息(一大堆三维坐标集合) TangoPointCloudData 扫描建模

2. 如何利用它开发AR应用

如果你理解了AR的本质,那么你会发现Tango已经提供了实现AR的一切条件,设备自身的位置朝向信息,以及周围的环境信息。应用能得到这些数据,那么做AR就没有问题。

如果你想开发3D AR应用,那么应该采用 Unity +Tango的开发方式,因为Tango本身并不提供3D渲染的功能。

如果觉得本文对你有帮助,请关注、留言、点赞,相互分享才能持续进步!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,099评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,473评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,229评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,570评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,427评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,335评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,737评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,392评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,693评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,730评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,512评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,349评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,750评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,017评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,290评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,706评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,904评论 2 335

推荐阅读更多精彩内容