🎆

ARFoundationを使って点群データ/PointCloudを計測する

2021/07/25に公開

PointCloudについて

ARといえば点群、点群といえばARです。
我らが ARFoundation にも当然ながら点群をスキャンする機能があります。

YouTubeのvideoIDが不正ですhttps://youtu.be/ml9qVRdEH4k?t=26

動画中の黄色い点が点群を構成する特徴点です。

この特徴点の検出精度が高ければ高いほどきれいに空間がスキャンできているはずですが、スマートフォン上で動かしているだけではそれがどれほどの精度で取れているのかわかりません。
というわけで今回はARFoundationのARPointCloudManagerの機能を使って、スマートフォンでスキャンした点群データをUDPで送信してエディタ上に表示する、ということをやりたいと思います。

概要

今回の概要はこんな感じです。この記事はこの粒度で進みます。

リポジトリはこちら。
https://github.com/nekomimi-daimao/PointCloudViewer

環境

platform version
Unity 2021.1.15f1
ARFoundation 4.1.7

機能

データ

デバイス-ビューア間では以下のデータをやりとりしています。
特徴点の1つ1つがIdentifiedPointで、それをIdentifiedPointArrayにまとめて送信。
DevicePoseはビューア上で確認するために送信しています。

IdentifiedPoint

名前 意味
Identify 特徴点の識別子
Confidence 確度
Position 特徴点の座標
CameraPosition カメラの座標
CameraRotation カメラの傾き

IdentifiedPointArray

名前 意味
Array IdentifiedPoint[]
Time 送信時の時間

DevicePose

名前 意味
Position カメラの座標
Rotation カメラの傾き

他にもPingを送信してコネクション確立とかやってますが本筋ではないので割愛。

ちなみに送信するデータをMessagePackで変換かけてるのは、通信量を節約したとかではなく、C#標準のUDPはbyte配列しか送れないので、データのシリアライズ/デシリアライズを自前で考えるのがめんどくさかったからです。なんにせよ、頻繁に送信するデータなので圧縮しておくにこしたことはないと思います。

デバイス

まずはスキャンするデバイス側です。

Assets/Scenes/Device.unity

空間上に検知した点群を白いSphereで表示します。表示されている光の三原色のアンカーはそのままUnityのXYZで、デバイスが認識している空間の原点です。上の数字はカメラの座標です。
裏でせっせと点群やカメラの座標を送信していますが、デバイス側でできることはひたすら動かして点群をスキャンすることだけです。[1]

ビューア

デバイスから送られてきた点群を表示するビューアです。

Assets/Scenes/Viewer.unity

Hierarchyを基準に機能を解説します。

PointDataSupplier

点群の情報を生成する部分です。

  • Mock
    デバッグ用に適当な情報を生成します。ContextMenuからSupplyを実行してください。
  • UDP
    デバイスから送信されてきた点群の情報を受信します。
  • CSV
    CSVに点群の情報を保存/読込する機能です。floatの浮動小数点の関係でパースすると値が変わったりしますが誤差の範疇ということで……。

PointRoot.PointViewScheme

点群を表示する部分です。

  • Scheme
    点群を以下の情報によって色分けします。
名前 意味
White
Distance カメラと点群の距離
Confidence 確度
  • Distance
  • Confidence
    表示する点群をフィルタリングします。Distanceの単位はメートル、Confidenceの範囲は0〜1です。

AnchorWithMemo

DevicePoseを反映して動きます。

実行

スマートフォンとエディタでそれぞれ実行するとこんな感じになります[2]。白いSphereの1つ1つが点群情報です。
UDPを介しているので同じLANに繋いでおく必要があります。
これは視点が真上からで、アンカーの青軸がZ=正面です。
部屋を歩き回ってスキャンできているのがわかると思います。

分析

散布図

値をフィルタリングすることで、表示される点群の精度を上げていきたいと思います。
今回使用したのはAndroidのMoto G7 Plusです。普段遣いには十二分ですが、今時のARやれと言われるとちょっと苦しいかも……という感じ。

とりあえず生データをGoogleスプレッドシートにそのまま打ち込んでカメラからの距離 × Confidenceで散布図を作ってみます。
左がみっっっっちり詰まってますが、25mどころか40m近くでもConfidenceが0.75あったりして明らかに変な値が混ざってます。そんなに部屋広くないよ!

ひとまずそれっぽい5mで足切りしてみます。
ほんとならここから間引いて分布を見るのが正しいんでしょうが、つらいのでしません。4m/0.5ぐらいがだいたいの妥当な数字でしょうか。
1m以遠から点群のスキャンが開始されるのは、動かしていたときの感覚と合っています。近すぎて差分が取りづらいとかズレが大きすぎるとかたぶんそんな感じ。

フィルタリング

カメラからの距離4m以内、Confidenceが0.5以上でフィルタリングした結果です。色はConfidenceで色付けしてます。
最初に注目しているのがカーテンで、回転した後の次がテレビです。知ってるとそれっぽく取れてます。

まとめ

というわけで、ARFoundationを使って点群をスキャンする方法でした。
点群と言いつつもARPointCloudManagerから出てくる情報はXYZだけで色情報のRGBは入っていません。精度も正直どうかなって感じでしたが、これはARFoundationの主軸がリアルタイム性にあるからかなと思っています。あと使用したAndroidの性能。

ここまでやっておいて手のひらを返すのもなんですが、スマートフォンできれいに点群を測定したければLiDARを積んだiOSでストアからアプリ落としてきてスキャンすればいいと思います。持ってないので使ったことないですがきれいにとれるはず。

ARFoundationHololens2MagicLeapにもに対応しているので[3]、そちらを使うならもっと細かくきれいに取れると思います。点群が増える分、ビューアの描画負荷がだいぶ厳しいことになると思いますが……。

実際のARアプリ開発では点群ではなくそれを元に生成されるMeshに対してあれこれしますが、生の点群を今のARFoundationを使って眺めてみたかったのでやりました。戦闘機を真似て紙飛行機を折るが如き試作でしたが、とりあえずやってみたいことをやってみたので満足です。

おしまい。

覚書

  • トラッキング外れのことを考えてDeviceではAnchorを設置するべき
  • AndroidにもMeshingほしい……。
  • iOSでビルド試してない[4]
  • ビューアの点群のDrawCallが厳しいので公式サンプルのようにシェーダでなんとかするべき
  • Contributeせずに言うのもなんだけどUnity公式のサンプルは悉く信用ならない
  • SerializeFieldをDIとして使うのはさすがに厳しくて設計がぐだぐだになった
  • テスト素直に書けばよかった
  • gitmoji楽しいけどなんか項目はweb向けなきがする
  • ノリでURP入れたけどShaderGraphわからん[5]

参考

https://docs.unity3d.com/Packages/com.unity.xr.arfoundation@4.1/manual/index.html
https://github.com/Unity-Technologies/arfoundation-samples
https://nn-hokuson.hatenablog.com/entry/2020/09/03/205929
https://www.jyuko49.com/entry/2020/05/17/211358
https://garafu.blogspot.com/2015/08/udpclient.html
https://www.kemomimi.dev/unity/658/
https://caitsithware.com/wordpress/archives/1389
https://befool.co.jp/blog/8823-scholar/unirx-from-event-args/

脚注
  1. アプリは操作できるなどというナイーヴな考え方は捨てろ。 ↩︎

  2. https://twitter.com/CatEarEvilKing/status/1419055392944836611 twitterで動画を貼ったんですがgifのほうがきれい…… ↩︎

  3. 使う理由が正直見当たらないけど ↩︎

  4. Appleアカウントのパスワード忘れた ↩︎

  5. でも生シェーダ書くのはもっといや ↩︎

Discussion