帶你認識Google 屌炸天的AR項目——Project 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渲染的功能。

如果覺得本文對你有幫助,請關注、留言、點贊,相互分享才能持續進步!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章