1. 程式人生 > >ARCore之路-計算機視覺之例項(三)

ARCore之路-計算機視覺之例項(三)

  前面我們已經編寫完了神經網路程式碼,雖然有些簡陋,但是麻雀雖小五臟俱全,這是一個完整的神經網路結構,我們可以應用這個神經網路到AR中,下面我將利用這個神經網路來做AR中的碰撞檢測(這裡的碰撞檢測是指使用者(手機終端)與ARCore檢測到的特徵點距離過近時發出警報以防止使用者與真實物體發生碰撞。當然,實現這個功能可以完全不用神經網路而採取直接計算,這裡只是為了演示需要,講解如何將神經網路運用到AR中去,同時加深對神經網路的理解)。
  我們的實現思路是:

  1. 構建一個兩層的神經網路。
  2. 對這個兩層的神經網路進行訓練。
  3. 從ARCore中獲取到特徵點,利用這個特徵點到使用者(手機終端)的距離,通過神經網路進行計算,如果特徵點到使用者(手機終端)的距離過近則發出聲音警報以提醒使用者。

一、編寫環境掃描程式碼

  在Project視窗中,在ARCoreML/Scripts 資料夾上右鍵,選擇Create ,新建一個C# Script,取名為EnvironmentalScanner.cs,這個程式碼用來掃描環境、提取特徵點、訓練神經網路、進行環境評估。先把所有程式碼寫出來,我們再逐行解釋。

DavidWang原創
[RequireComponent(typeof(AudioSource))]
public class EnvironmentalScanner : MonoBehaviour
{
    public Camera FirstPersonCamera;
    private NeuralNet net;
    private List<DataSet> dataSets;
    
    private float min = float.MaxValue;    
    private double[] output;
    private bool warning = false;
    private AudioSource audioSource;

    public void Awake()
    {        
        int numInputs, numHiddenLayers, numOutputs;
        numInputs = 1; numHiddenLayers = 4; numOutputs = 1;
        net = new NeuralNet(numInputs, numHiddenLayers, numOutputs);
        dataSets = new List<DataSet>();
    }
    // Use this for initialization
    void Start()
    {        
        dataSets.Add(new DataSet(new double[]{ 1,.1,0.0}, new double[] { 0.0,1.0,1.0 } ));
        net.Train(dataSets, .001);
        audioSource = GetComponent<AudioSource>();        
    }
    // Update is called once per frame
    void Update()
    {
        if (warning)
        {            
            audioSource.Play();
        }
        else
        {
            audioSource.Stop();
        }

        if (Session.Status != SessionStatus.Tracking)
        {
            return;
        }
        min = float.MaxValue;
        if (Frame.PointCloud.PointCount > 0 && Frame.PointCloud.IsUpdatedThisFrame)
        {
            for (int i = 0; i < Frame.PointCloud.PointCount; i++)
            {
                var rng = Mathf.Clamp01(((Vector3)Frame.PointCloud.GetPoint(i) - FirstPersonCamera.transform.position).magnitude);
                min = Mathf.Min(rng, (float)min);
            }
            output = net.Compute(new double[] { (double)min });            
            if(output.Length > 0)
            {                
                warning = output[0] > .001;
            }
            else
            {
                warning = false;
            }
        }
    }
}

  [RequireComponent(typeof(AudioSource))] 這是一個Unity Editor擴充套件指令,使用這個指令[RequireComponent(typeof(型別))]可以保證該指令碼被掛載時會將typeof(型別)的這個元件一併掛載,如果之前就有typeof(型別)元件,則不做任何操作,如果沒有typeof(型別)元件,則會自動掛載該元件,以避免裝配錯誤。因為我們需要AudioSource元件播放聲音,所以我們新增這個指令。
  接下來我們定義了若干變數,FirstPersonCamera這個需要將場景的攝像頭賦給它,這裡用來定位使用者(手機裝置)的位置以便與特徵點進行距離計算。然後我們還定義了神經網路以及其他的輔助變數。
  Awake()方法是Unity中的一個特殊方法,該方法執行在Start()方法前,它是在物件第一次變得活躍時被呼叫。Awake()與Start()方法執行先後上有所區別,Awake()它是在物件初始化時呼叫的,而Start()是物件在被渲染的第一幀前被呼叫。這種差異是微妙的,通常只有當您關心物件載入時間先後時才用考慮。接下來我們構建了一個輸入層是1,隱藏層為4,輸出層為1的神經網路。
  在Start()方法中,我們添加了訓練資料集,並對神經網路進行訓練。這裡我們使用的DataSet非常簡單,因為只有一個輸入和一個輸出,其訓練圖如下:

DavidWang原創

  隨後,我們將神經網路訓練成最小誤差為.001的神經網路。這裡我們還獲取了所需的AudioSource,並將其設定到私有的AudioSource變數中,因為我們後面會使用聲音來作為當用戶太靠近物體時的警告。
  在Update()方法中,我們根據使用者與特徵點的距離來決定是否播放警告聲。我們首先檢查warning標誌是否為true,如果是,我們播放一個聲音,否則我們停止播放;warning是一個標誌,他用神經網路輸出來控制的。接下來,我們首先確保當前幀正處於被跟蹤狀態,重置min,並從幀中獲取當前點雲。在if塊內,判斷當前幀中有已檢測到的特徵點,並且這些特徵點是被更新過的,否則我們什麼也做不了。在這些條件符合後,通過迴圈遍歷所有特徵點來計算當前距離使用者最近的特徵點到使用者的距離,然後使用神經網路net.Computer(最小點)來計算nn的輸出,並根據這個輸出這將warning設定為true或false。

二、配置實現

  在Unity中,在Hierarchy視窗根目錄下新建一個空物件,並命名為EnvironmentScanner,選擇這個物件,在Inspector視窗中為這個物件新增AudioSource元件,並將我們準備好的警示聲拖到AudioClip屬性上,同時取消Play On Awake多選框以防止自鳴。選擇 Add Component 新增我們剛編寫的EnvironmentScanner指令碼(或者將指令碼直接拖到這個Inspector視窗上),結果如下圖所示:

DavidWang原創

  好了,大功告成,開啟Build Settings對話方塊,確保我們剛才的場景已選擇,編譯,執行。
  至此,我們利用神經網路做了一個接近告警器,當用戶太接近一個物件時就會發出警報。如前所述,我們也可以完全不用神經網路來而採用更簡單的方法實現這個功能,但這個簡單的例子為我們提供了一個很好的基礎來理解神經網路、訓練、評估是如何工作的,也驗證了我們前面寫的神經網路的正確性,對下步利用神經網路進行更復雜的開發打下了很好的基礎。