この記事では、AR Foundationで検出される特徴点群(Point Cloud)を表示する方法と、各特徴点の座標を調べたり、保存したりする方法を紹介します。特徴点を保存しておけば、次図のように、後から特徴点群として表示することもできます。
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の配列)に検出した全ての特徴点の座標が入っています。
それではまず、Point Cloud Prefabを作成して、Point Cloud Managerに登録しましょう。
ヒエラルキーウインドウの「+」→「XR/AR Default Point Cloud」を選択して下さい。作成したオブジェクトをプロジェクトウィンドウにドラッグ&ドロップします。ヒエラルキーウインドウのAR Default Point Cloudは不要ですので削除しておきましょう。
次に、作成したPrefabをAR Point Cloud ManagerのPoint Cloud Prefabの欄にドラッグ&ドロップして下さい。
これで特徴点を表示する準備はできました。ビルドしてカメラを動かすと、黄色い特徴点が検出されます。
特徴点の座標を保存する
次に、検出した全ての特徴点の座標を保存してみましょう。ここでは画面をタッチすると、検出した特徴点の座標を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にドラッグ&ドロップしてアタッチして下さい。
これで、特徴点を保存するアプリができました。ビルドしてある程度特徴点を検出したら、画面をタップして特徴点の座標をファイルに保存して下さい。
保存した特徴点を可視化する
保存したファイルを取り出す
保存したファイルはiPhoneの/var/mobile/Applications/XXXXXXXX/Documentsフォルダに入っています。iPhoneのアプリ内に保存したデータを取り出すにはXcodeを使う必要があります。
MacとiPhoneを接続してXcodeを起動し、メニューバーからWIndow→Devices and Simulatorsを選択します。今回作成したアプリを選択して、画面したの歯車ボタンから「Download Container 」を選択します。
○○○.xcappdataという名前で保存されるので右クリック→「パッケージの内容を表示」を選択して下さい。
「パッケージの内容を表示」を選択するとFinderが開きます。AppData/Documents/の中にあるpoints.txtが保存したデータになります。
保存したデータを可視化する
保存した特徴点のデータを可視化するため、新しくシーンを作っておきましょう。シーンができたら、ヒエラルキーウインドウから「+」→「XR/AR Default Point Cloud」を選択して下さい。
今回はこのオブジェクトのParticle Systemだけを使って特徴点を表示するので、AR Point CloudとAR Point Cloud Particle Visualizerのチェックは外しておきます。
次に特徴点を可視化するスクリプトを作成します。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スクリプトをアタッチして下さい。
最後に、先程取り出したデータをUnityのプロジェクトウィンドウに追加し、それをDataVisualizerのData欄にドラッグ&ドロップします。
実行して保存した特徴点が表示されていることを確認して下さい。下図はPost Processing StackのBloomを使ってちょっときれいに加工しています(笑)
booth.pm