![見出し画像](https://assets.st-note.com/production/uploads/images/70770977/rectangle_large_type_2_03b2a11d655078a43ab2969497938e87.png?width=1200)
Niantic Lightship ARDK セマンティック セグメンテーションを使ってタップした所から空、地面、建物、水面などの情報を取得する方法
おさらい
Niantic Lightship ARDK や セマンティック セグメンテーションについて、以下の記事でまとめております。
今回は...
セマンティック セグメンテーションの機能を使い、タップした箇所から空、地面、人工地盤、水、建物、葉(木なども含む)芝生を検出するアプリケーションを作成します。
1. Niantic Lightship ARDK ダウンロード
以下から入手してください。今回、使用しているバージョンはv1.1.0になります。入手する際、Niantic Lightshipのアカウント登録が必要です。
2. Niantic Lightship ARDK インポート
UnityEditor のメニューにあるAssets → Import Package → Custom Package...を選び、ダウンロードした ardk-1.1.0.unitypackage をインポートします。
3. 新規でSceneを作成とMain Cameraの削除
新規でSceneを作成後、Main Cameraを削除します。
4. ARSceneManagerをヒエラルキーに追加
5. ARSceneManagerをUnpack Prefab Completely
6. ARDepth Manager と ARSemanticSegmentationManager の追加
ARSceneManagerの子コンポーネント、ARSceneCameraにARDepthManager と ARSemanticSegmentationManager のスクリプトを追加。
7. Semantic Segmentationの情報を表示するUIの作成
タップした場所から検出されたSemantic Segmentationの情報を表示するためのUIを作成します。
Canvas
Text
CanvasとTextを設置します。(Textのタップイベントを無効化にするため、Raycast TargetのチェックボックスをOFFにしています。)
Image
タップした場所を表示するImageも設置します。(Imageのタップイベントを無効化にするため、Raycast TargetのチェックボックスをOFFにしています。)
Dropdown
今回、タップした場所からSemantic Segmentationの情報を取得する処理ロジックを2つ使用して検証します。
1つ目はSemanticBufferProcessor.GetChannelNamesAt(x, y)です。該当の位置から検出された情報(空や地面など)を文字列による配列で返却されます。
2つ目はSemanticBufferProcessor.DoesChannelExistAt(x, y, channelName)です。該当の位置から検出された情報(空や地面など)が第3引数のチャンネル名(skyやgroundなど)に合致しているか否かを真偽値として返却されます。
上記のいずれかの検出方法をDropdownで切り替えるようにします。
8. Semantic Segmentationの検出処理
Semantic Segmentationの検出処理を実装します。Semantic SegmentationというGame Objectを作成後、Semantic Segmentationというスクリプトを作成し、コンポーネントとして追加します。(スクリプトは以下。SerializeFieldに設定するUIやObjectは上の画像を参考にしてください。)
using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using Niantic.ARDK.Extensions;
using Niantic.ARDK.Utilities;
public class SemanticSegmentation : MonoBehaviour
{
[SerializeField]
private ARSemanticSegmentationManager _semanticManager;
[SerializeField]
private Text _textChannelName;
[SerializeField]
private GameObject _imageTapObj;
[SerializeField]
private Dropdown _dropDownChannel;
// Update is called once per frame
void Update()
{
if (PlatformAgnosticInput.touchCount <= 0 || IsOverGameObject()) {
return;
}
var touch = PlatformAgnosticInput.GetTouch(0);
if (touch.phase == TouchPhase.Began)
{
var names = "";
switch(_dropDownChannel.value)
{
case 0:
names = ChannelNames(touch);
break;
case 1:
names = ChannelNamesExist(touch);
break;
}
if (String.IsNullOrWhiteSpace(names))
{
names = "Not Found";
}
_textChannelName.text = names;
}
}
string ChannelNames(Touch touch)
{
int x = (int)touch.position.x;
int y = (int)touch.position.y;
string[] channelsNamesInPixel = _semanticManager.SemanticBufferProcessor.GetChannelNamesAt(x, y);
var sb = new StringBuilder();
foreach (var i in channelsNamesInPixel)
{
sb.Append(i);
sb.Append(" ");
}
var names = sb.ToString();
_imageTapObj.transform.position = new Vector3(x, y, 0);
return names;
}
string ChannelNamesExist(Touch touch)
{
int x = (int)touch.position.x;
int y = (int)touch.position.y;
var sbp = _semanticManager.SemanticBufferProcessor;
var channelNames = sbp.Channels;
var sb = new StringBuilder();
for (int i = 0; i < channelNames.Length; i++)
{
if (sbp.DoesChannelExistAt(x, y, channelNames[i]))
{
sb.Append(channelNames[i]);
sb.Append(" ");
}
}
var names = sb.ToString();
_imageTapObj.transform.position = new Vector3(x, y, 0);
return names;
}
bool IsOverGameObject()
{
if (EventSystem.current.IsPointerOverGameObject())
{
return true;
}
if (Input.touchCount > 0 && EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))
{
return true;
}
return false;
}
}
9. ビルド&実行
タップした場所の情報をテキストで表示されます。上記の場合、タップした場所からgroundとartifical_groundの2つの情報が取得されました。
木や木の葉、植木などはfoliageの検出される事が多いです。
芝生や草原はgrassだけでなく、groundも同時に検出される事がほとんどです。
空や雲はskyとして認識され、建物全般はbuildingとして認識されます。画像はないようですが、川や噴水はwaterと認識されます。(コップやペットボトルや洗面台に溜まった水だとwaterとして認識することはないと思います。)
検証結果
SemanticBufferProcessor.GetChannelNamesAtを使用した場合、grassやartifical_groundのみ返却されることは、ほとんどなく、groundが含まれている事がほとんどでした。grassやartifical_groundが含まれた配列には、配列の0番目の要素にgroundが格納されている事がほとんどでした。
grassやartifical_groundをピンポイントで条件判定を行いたい場合は、SemanticBufferProcessor.DoesChannelExistAtでgrassやartifical_groundの存在チェックを行った方が良いと思います。
参考
Niantic の セマンティックセグメンテーションは独自のものだと思いますが、通常、COCOの構造と類似していることが多いとアドバイスを頂きました。
https://discord.com/channels/920503716027711528/923250546763264082/931930142811512952
最後に
OnePlanet XR
OnePlanet XR はAR/MR技術に専門特化したコンサルティングサービスです。豊富な実績を元に、AR/MR技術を活用した新たな事業の立ち上げ支援や、社内業務のデジタル化/DX推進など、貴社の必要とするイノベーションを実現いたします。
ご相談から受け付けております。ご興味ございましたら弊社までお問い合わせください。
OnePlanet Tech Magazine
様々な技術記事を定期的に投稿しています。