おもちゃラボ

Unityで遊びを作っていきます

【AR Foundation】Point Cloudの保存と表示

この記事では、AR Foundationで検出される特徴点群(Point Cloud)を表示する方法と、各特徴点の座標を調べたり、保存したりする方法を紹介します。特徴点を保存しておけば、次図のように、後から特徴点群として表示することもできます。

f:id:nn_hokuson:20200903200034j:plain

AR Foundationの基礎になっているARKitについては「swiftで作る ARKit超入門」がオススメです!こちらも、ぜひご参照ください。
booth.pm

今回の目次は次のとおりです。

プロジェクトの作成と準備

AR Foundationを使ったプロジェクトの作り方と、その準備についてはこちらの記事に詳しく説明しています。

nn-hokuson.hatenablog.com

ここではAR SessionとAR Session Originオブジェクトを配置し終えたところからスタートしたいと思います。

特徴点を表示する

AR Foundationを使って特徴点を表示するには、AR Point Cloud Managerを使用します。このAR Point Cloud ManagerのPrefabに特徴点を表示するPoint Cloud Prefabを指定することで、特徴点を可視化できます。

Point Cloud PrefabにはPoint Cloudスクリプトがアタッチされており、このスクリプトのpositions(Vector3の配列)に検出した全ての特徴点の座標が入っています。

f:id:nn_hokuson:20200903205539p:plain

それではまず、Point Cloud Prefabを作成して、Point Cloud Managerに登録しましょう。
ヒエラルキーウインドウの「+」→「XR/AR Default Point Cloud」を選択して下さい。作成したオブジェクトをプロジェクトウィンドウにドラッグ&ドロップします。ヒエラルキーウインドウのAR Default Point Cloudは不要ですので削除しておきましょう。

f:id:nn_hokuson:20200903201757j:plain:w450

次に、作成したPrefabをAR Point Cloud ManagerのPoint Cloud Prefabの欄にドラッグ&ドロップして下さい。

f:id:nn_hokuson:20200903201929j:plain

これで特徴点を表示する準備はできました。ビルドしてカメラを動かすと、黄色い特徴点が検出されます。

f:id:nn_hokuson:20200903204550j:plain:w450

特徴点の座標を保存する

次に、検出した全ての特徴点の座標を保存してみましょう。ここでは画面をタッチすると、検出した特徴点の座標をCVS形式で保存するようにします。

上図で説明したように、検出した特徴点の座標はPoint CLoudスクリプトのpositions配列に格納されています。これを取り出して、ファイルに保存するスクリプトを作りましょう。

SaveControllerというC#ファイルを作成して、次のスクリプトを入力して下さい。

using System;
using System.Collections.Generic;
using UnityEngine.XR.ARSubsystems;
using System.IO;

namespace UnityEngine.XR.ARFoundation
{
    public class SaveController : MonoBehaviour
    {
        ARPointCloud m_PointCloud;
        Dictionary<ulong, Vector3> m_Points = new Dictionary<ulong, Vector3>();

        void Awake()
        {
            m_PointCloud = GetComponent<ARPointCloud>();
        }

        void OnPointCloudChanged(ARPointCloudUpdatedEventArgs eventArgs)
        {
            if (!m_PointCloud.positions.HasValue)
                return;

            var positions = m_PointCloud.positions.Value;

            if (m_PointCloud.identifiers.HasValue)
            {
                var identifiers = m_PointCloud.identifiers.Value;
                for (int i = 0; i < positions.Length; ++i)
                {
                    m_Points[identifiers[i]] = positions[i];
                }
            }
        }

        void SavePoints()
        {
            string filePath = Application.persistentDataPath + "/points.txt";
            Debug.Log("file save at " + filePath);

            using (StreamWriter sr = File.CreateText(filePath))
            {
                foreach (var kvp in m_Points)
                {
                    Vector3 p = kvp.Value;
                    sr.WriteLine(p.x.ToString("F3") + "," + p.y.ToString("F3") + "," + p.z.ToString("F3"));
                }
            }

        }

        private void Update()
        {
            if (Input.GetMouseButtonDown(0))
            {
                SavePoints();
            }
        }

        void OnEnable()
        {
            m_PointCloud.updated += OnPointCloudChanged;
        }

        void OnDisable()
        {
            m_PointCloud.updated -= OnPointCloudChanged;
        }
    }
}

このスクリプトでは、特徴点が新たに追加された場合にOnPointCloudChangedメソッドが呼ばれるようにしています。OnPointCloudChangedメソッドではPoint Cloudスクリプトの持つpositionsから座標を取り出して、一旦、m_Pointsに追加しています。

画面をタップするとSavePointsメソッドが実行されます。SavePointsメソッドではm_Pointsから特徴点の座標を取り出して、ファイルに保存しています。保存先はApplication.persistentDataPathを指定しています。これにより、iPhone内の/var/mobile/Applications/XXXXXXXX/Documentsフォルダにデータが保存されます。

作成したSaveControllerスクリプトをAR Default Point Cloud Prefabにドラッグ&ドロップしてアタッチして下さい。

f:id:nn_hokuson:20200903202110j:plain:w600

これで、特徴点を保存するアプリができました。ビルドしてある程度特徴点を検出したら、画面をタップして特徴点の座標をファイルに保存して下さい。

保存した特徴点を可視化する

保存したファイルを取り出す

保存したファイルはiPhoneの/var/mobile/Applications/XXXXXXXX/Documentsフォルダに入っています。iPhoneのアプリ内に保存したデータを取り出すにはXcodeを使う必要があります。

MacとiPhoneを接続してXcodeを起動し、メニューバーからWIndow→Devices and Simulatorsを選択します。今回作成したアプリを選択して、画面したの歯車ボタンから「Download Container 」を選択します。

f:id:nn_hokuson:20200903202358j:plain:w600

○○○.xcappdataという名前で保存されるので右クリック→「パッケージの内容を表示」を選択して下さい。

f:id:nn_hokuson:20200903202502p:plain:w400

「パッケージの内容を表示」を選択するとFinderが開きます。AppData/Documents/の中にあるpoints.txtが保存したデータになります。

f:id:nn_hokuson:20200903202513p:plain:w600

保存したデータを可視化する

保存した特徴点のデータを可視化するため、新しくシーンを作っておきましょう。シーンができたら、ヒエラルキーウインドウから「+」→「XR/AR Default Point Cloud」を選択して下さい。

今回はこのオブジェクトのParticle Systemだけを使って特徴点を表示するので、AR Point CloudとAR Point Cloud Particle Visualizerのチェックは外しておきます。

f:id:nn_hokuson:20200903202937j:plain

次に特徴点を可視化するスクリプトを作成します。DataVisualizerという名前のC#スクリプトを作成して、次のスクリプトを入力して下さい。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;

public class DataVisualizer : MonoBehaviour
{
    ParticleSystem m_ParticleSystem;
    ParticleSystem.Particle[] m_Particles;

    [SerializeField] TextAsset data;
    List<Vector3> positions = new List<Vector3>();

    void Start()
    {
        m_ParticleSystem = GetComponent<ParticleSystem>();

        StringReader reader = new StringReader(data.text);
        while (reader.Peek() != -1)
        {
            string line = reader.ReadLine();
            string[] str = line.Split(',');
            float x = float.Parse(str[0]);
            float y = float.Parse(str[1]);
            float z = float.Parse(str[2]);
            positions.Add(new Vector3(x, y, z));
        }

        int numParticles = positions.Count;

        m_Particles = new ParticleSystem.Particle[numParticles];
        for (int i = 0; i < positions.Count;i++)
        {
            m_Particles[i].startColor = m_ParticleSystem.main.startColor.color;
            m_Particles[i].startSize = m_ParticleSystem.main.startSize.constant;
            m_Particles[i].position = positions[i];
            m_Particles[i].remainingLifetime = 1f;
        }

        m_ParticleSystem.SetParticles(m_Particles, numParticles);

    }
}

このスクリプトでは、CVS形式で記述された座標を読み出し、パーティクルを使って可視化しています。座標のリストをパーティクルとして表示するには、保存された座標の個数ぶん、ParticleSystem.Particle型の配列(m_Particles)としてパーティクルを生成して、それぞれのパーティクルの座標や色を設定しています。

スクリプトを保存できたらAR Default Point CloudオブジェクトにDataVisualizerスクリプトをアタッチして下さい。

f:id:nn_hokuson:20200903203153j:plain

最後に、先程取り出したデータをUnityのプロジェクトウィンドウに追加し、それをDataVisualizerのData欄にドラッグ&ドロップします。

f:id:nn_hokuson:20200903203252j:plain:w500

実行して保存した特徴点が表示されていることを確認して下さい。下図はPost Processing StackのBloomを使ってちょっときれいに加工しています(笑)

f:id:nn_hokuson:20200903200034j:plain

booth.pm