Niantic Lightship ARDK の画像検出機能を使用する
Niantic社が提供しているスマホ用のARアプリケーション開発キット、Lightship ARDKを使用し、画像検出を行う方法について説明します。
Niantic Lightship ARDKとは?
『 Ingress 』、『 Pokémon GO 』、『Pikmin Bloom』などでも使用しているNiantic社が提供するARアプリケーション開発キットになります。マルチプレイヤー、深度、物理、オクルージョン、セマンティックセグメンテーションなどの機能が提供されています。
開発環境と動作確認したデバイス
Unity Editor 2019.4 を使用してます。
今回、テストで使用したデバイスはiPhone 12 Proになります。
1. 画像検出用の画像をダウンロード
以下のサイトにある画像をダウンロード。
2. ダウンロードした画像の拡張子を変更します。
Lightship ARDKが提供しているARImageDetectionManagerを使い、検出する画像の登録を行います。ARImageDetectionManagerはJPEG画像をbytesにしたのTextAssetを使用するため、ダウンロードしたJPEG画像ファイルの拡張子を.bytesに変更します。
(参考)拡張子の変更方法
3. Niantic Lightship ARDK ダウンロード
以下から入手してください。今回、使用しているバージョンはv1.1.0になります。入手する際、Niantic Lightshipのアカウント登録が必要です。
4. Niantic Lightship ARDK インポート
UnityEditor のメニューにあるAssets → Import Package → Custom Package...を選び、ダウンロードした ardk-1.1.0.unitypackage をインポートします。
5. 新規でSceneを作成とMain Cameraの削除
新規でSceneを作成後、Main Cameraを削除します。
6. ARSceneManagerをヒエラルキーに追加
7. TextAsset用の画像ファイル(.bytes)をAssets配下に移動
ダウンロード後に.bytesに拡張子変更したファイルをAssets配下に移動します。(この例ではImage Tracking/imagesのフォルダを作成してます。)
8. Managerの作成
ヒエラルキーにGameObjectを作成。名前をManagerに変更後、ARImageDetectionManagerスクリプトを追加します。今回は1つの画像だけ検出するためImagesのSizeは1とします。Element 0 のImage As Bytesにダウンロード→.拡張を.bytesに変更したファイルをドラッグ&ドロップします。Nameは適当な文字列を入力。Physical Widthは検出する対象の実寸(横幅)を指定する必要があります。ここでは0.25(25cm)としています。
9. 画像検出時に表示するPlaneの作成
GameObjectを生成します。名前をImagePlaneに変更します。
ImagePlaneの中にPlaneを生成します。
Scaleは0.1とします。
Image PlaneをPrefabにします。(ヒエラルキーにあるImagePlaneを削除します。)
10. Exampleの作成
画像検出した場所にImage Planeの生成と表示を行うスクリプトを作成します。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Niantic.ARDK.AR;
using Niantic.ARDK.AR.Configuration;
using Niantic.ARDK.AR.Anchors;
using Niantic.ARDK.AR.ARSessionEventArgs;
using Niantic.ARDK.AR.ReferenceImage;
using Niantic.ARDK.Extensions;
using Niantic.ARDK.Utilities;
using Niantic.ARDK.Utilities.Collections;
public class DetectingImageExample: MonoBehaviour
{
[SerializeField]
private GameObject _plane = null;
private Dictionary<Guid, GameObject> _detectedImages = new Dictionary<Guid, GameObject>();
// Start is called before the first frame update
void Start()
{
ARSessionFactory.SessionInitialized += SetupSession;
}
// Update is called once per frame
void Update()
{
}
private void SetupSession(AnyARSessionInitializedArgs arg)
{
var session = arg.Session;
session.SessionFailed += args => Debug.Log(args.Error);
session.AnchorsAdded += OnAnchorsAdded;
session.AnchorsUpdated += OnAnchorsUpdated;
session.AnchorsRemoved += OnAnchorsRemoved;
}
private void OnAnchorsAdded(AnchorsArgs args)
{
foreach (var anchor in args.Anchors)
{
if (anchor.AnchorType != AnchorType.Image)
{
continue;
}
var imageAnchor = (IARImageAnchor) anchor;
var imageName = imageAnchor.ReferenceImage.Name;
var newPlane = Instantiate(_plane);
_detectedImages[anchor.Identifier] = newPlane;
UpdatePlaneTransform(imageAnchor);
}
}
private void OnAnchorsUpdated(AnchorsArgs args)
{
foreach (var anchor in args.Anchors)
{
if (!_detectedImages.ContainsKey(anchor.Identifier))
{
continue;
}
var imageAnchor = anchor as IARImageAnchor;
UpdatePlaneTransform(imageAnchor);
}
}
private void OnAnchorsRemoved(AnchorsArgs args)
{
foreach (var anchor in args.Anchors)
{
if (!_detectedImages.ContainsKey(anchor.Identifier))
{
continue;
}
Destroy(_detectedImages[anchor.Identifier]);
_detectedImages.Remove(anchor.Identifier);
}
}
private void UpdatePlaneTransform(IARImageAnchor imageAnchor)
{
var identifier = imageAnchor.Identifier;
_detectedImages[identifier].transform.position = imageAnchor.Transform.ToPosition();
_detectedImages[identifier].transform.rotation = imageAnchor.Transform.ToRotation();
var localScale = _detectedImages[identifier].transform.localScale;
localScale.x = imageAnchor.ReferenceImage.PhysicalSize.x;
localScale.z = imageAnchor.ReferenceImage.PhysicalSize.y;
_detectedImages[identifier].transform.localScale = localScale;
}
}
SetupSessionでARSessionの初期化を行います。画像が検出されるとOnAnchorsAddedが呼び出されます。OnAnchorsAddedでアンカーのタイプをチェックを行います。画像であれば画像のアンカーを使い、検出処理を行います。
ヒエラルキー上でGameObjectを生成します。名前はExampleとします。このExampleに先程、作成したスクリプトを追加します。PlaneにはPrefabのImagePlaneを設定します。
11. ビルド&実行
実行するとカメラ画像が表示されます。画像に近づけると画像の前にPlaneが表示されます。
まとめ
あくまで画像を検出する機能であるため、スムーズに画像のトラッキングは行われません。ARImageAnchorでなくARAnchorを使用することでスムーズで且つ安定するとドキュメントに記載していましたが、実際はARAnchorもARImageAnchorもあまり変わりなかったです。
参考
最後に
Niantic Lightship ARDK のブログ記事
この記事以外にNiantic Lightship ARDKのブログ記事を投稿しています。
OnePlanet XR
OnePlanet XR はAR/MR技術に専門特化したコンサルティングサービスです。豊富な実績を元に、AR/MR技術を活用した新たな事業の立ち上げ支援や、社内業務のデジタル化/DX推進など、貴社の必要とするイノベーションを実現いたします。
ご相談から受け付けております。ご興味ございましたら弊社までお問い合わせください。
OnePlanet Tech Magazine
様々な技術記事を定期的に投稿しています。