オブジェクト検出を有効にする
Lightship Object Detectionは、Lightshipのコンテクスト・アウェアネスシステムに200以上のクラスを追加することで、画像内のオブジェクトにセマンティックラベル付きの2Dバウンディングボックスを作成できる機能です。 オブジェクト検出では、バウンディングボックスを生成し、検出されたオブジェクトの信頼度を示すことで、周囲の現実世界を認識し、ARアプリに強力な次元を加えることができます。
この入門ガイドでは、以下の手順でこの機能を使用する方法を説明します。
- シーンにオブジェクト検出を追加する
- カメラが認識したオブジェクトをログに記録する
- 画面上のオブジェクトにリアルタイムにラベル付けする
オブジェクト検出クラスの詳細については、機能ページを参照してください。

前提条件
ARDKがインストールされたUnityプロジェクトと、基本的なARシーンが必要です。 詳しくは、ARDK 3のインストールおよび基本的なARシーンの設定を参照してください。
AR Object Detection Managerを追加する
AR Object Detection Manager を追加するには、次の手順を行います。
- 
Lightship のトップメニューを開き、 XR Plug-in Management を選択して、 Niantic Lightship SDK メニューを開きます。 オブジェクト検出が有効になっていることを確認します。 
- 
ARシーン](./../../setup.mdx#how-to-setup-an-ar-scene)の階層で、 XROriginとCamera Offsetを展開し、Main Cameraを選択します。
- 
Inspector で Add Component をクリックし、Main Cameraに AR Object Detection Managerを追加します。  
オブジェクト検出の結果を出力する
オブジェクト検出の出力データを確認するには、 ObjectDetectionsUpdated イベントを登録します。 このイベントでは、新しいオブジェクト検出結果がある場合にコールバックが出力されます。 オブジェクト検出によってARカメラの画像でオブジェクトが認識されると、イベントで結果のリストが返ります。このリストの各結果は、カメラ画像の特定の領域に対応しています。 各結果には、オブジェクトに対して複数の分類が予測されること があるため、複数のオブジェクトカテゴリーが含まれる場合があります。 結果は、信頼度の値でフィルタリングし、ソートすることで、最も可能性の高い分類に焦点を合わせることができます。
オブジェクト検出の出力をモニタリングするには、次の手順を行います。
- 
Hierarchy で右クリックし、 Create Empty を選択して、新しい GameObjectをシーンに追加します。LogResultsという名前を付けます。  
- 
LogResultsを選択した状態で、 Inspector で Add Component をクリックし、 New Script を追加します。LogResultsという名前を付けます。  
- 
LogResults.csをダブルクリックして開きます。
- 
AR Object Detection Managerのシリアライズフィールドを追加します。 このマネージャーを使用することで、機能の詳細を処理し、結果に集中することができます。
    using UnityEngine;
    using Niantic.Lightship.AR.ObjectDetection;
    public class LogResults : MonoBehaviour
    {
        [SerializeField]
        private ARObjectDetectionManager _objectDetectionManager;
- Start()メソッド内でマネージャーを有効にし、- OnMetadataInitializedイベントを登録します。 このイベントは、オブジェクト検出の処理が開始されたタイミングで呼び出されます。
private void Start()
    {
        _objectDetectionManager.enabled = true;
        _objectDetectionManager.MetadataInitialized += OnMetadataInitialized;
    }
- 機能が準備できたら、 ObjectDetectionsUpdatedイベントに登録して、結果を自動的に受け取ります。
private void OnMetadataInitialized(ARObjectDetectionModelEventArgs args)
    {
        _objectDetectionManager.ObjectDetectionsUpdated += ObjectDetectionsUpdated;
    }
- ObjectDetectionsUpdated()関数を作成し、結果を文字列として収集し、コンソールにログ出力します。
    private void ObjectDetectionsUpdated(ARObjectDetectionsUpdatedEventArgs args)
    {
        // 出力用の文字列を初期化
        string resultString = "";
        var result = args.Results;
        if (result == null)
        {
            return;
        }
        // 結果文字列をリセット
        resultString = "";
- 結果をループ処理します。
    // 結果をループ処理します。各結果には複数のカテゴリーが含まれる場合があります。
    for (int i = 0; i < result.Count; i++)
    {
        var detection = result[i];
        var categorizations = detection.GetConfidentCategorizations();
        if (categorizations.Count <= 0)
        {
            break;
        }
確率の閾値を指定しない場合、デフォルトでは信頼度スコアが 0.4 の結果のみがフィルタリングされます。
- 各結果には複数のオブジェクト・カテゴリーが含まれることがあるため、信頼度の高い順に一覧表示します。
    // 信頼度が高い順にカテゴリーを並べ替える
        categorizations.Sort((a, b) => b.Confidence.CompareTo(a.Confidence));
        // このオブジェクトが含まれている可能性がある各カテゴリーの一覧を作成
        for (int j = 0; j < categorizations.Count; j++)
        {
            var categoryToDisplay = categorizations[j];
            resultString += "Detected " + $"{categoryToDisplay.CategoryName}: " + "with " + $"{categoryToDisplay.Confidence} Confidence \n";
        }
    }
- 最後に、すべての結果とカテゴリーをログに出力します。
        // すべての結果をログに出力
        Debug.Log(resultString);
    }
- 終了時にクリーンアップを忘れずに行いましょう。
    private void OnDestroy()
    {
        _objectDetectionManager.MetadataInitialized -= OnMetadataInitialized;
        _objectDetectionManager.ObjectDetectionsUpdated -= ObjectDetectionsUpdated;
    }
クリックして LogResults スクリプト全体を表示
using UnityEngine;
using Niantic.Lightship.AR.ObjectDetection;
public class LogResults : MonoBehaviour
{
    [SerializeField]
    private ARObjectDetectionManager _objectDetectionManager;
    private void Start()
    {
        _objectDetectionManager.enabled = true;
        _objectDetectionManager.MetadataInitialized += OnMetadataInitialized;
    }
    private void OnMetadataInitialized(ARObjectDetectionModelEventArgs args)
    {
        _objectDetectionManager.ObjectDetectionsUpdated += ObjectDetectionsUpdated;
    }
    private void ObjectDetectionsUpdated(ARObjectDetectionsUpdatedEventArgs args)
    {
        // 出力用の文字列を初期化
        string resultString = "";
        var result = args.Results;
        if (result == null)
        {
            return;
        }
        // 結果文字列をリセット
        resultString = "";
        // 結果をループ処理します。各結果には複数のカテゴリーが含まれる場合があります。
        for (int i = 0; i < result.Count; i++)
        {
            var detection = result[i];
            var categorizations = detection.GetConfidentCategorizations();
            if (categorizations.Count <= 0)
            {
                break;
            }
            // 信頼度が高い順にカテゴリーを並べ替える
            categorizations.Sort((a, b) => b.Confidence.CompareTo(a.Confidence));
            // このオブジェクトが含まれている可能性がある各カテゴリーの一覧を作成
            for (int j = 0; j < categorizations.Count; j++)
            {
                var categoryToDisplay = categorizations[j];
                resultString += "Detected " + $"{categoryToDisplay.CategoryName}: " + "with " + $"{categoryToDisplay.Confidence} Confidence \n";
            }
        }
        // すべての結果をログに出力
        Debug.Log(resultString);
    }
    private void OnDestroy()
    {
        _objectDetectionManager.MetadataInitialized -= OnMetadataInitialized;
        _objectDetectionManager.ObjectDetectionsUpdated -= ObjectDetectionsUpdated;
    }
}
完成したスクリプトをプロジェクトに追加する
- 
Hierarchy で LogResultsを選択し、 Inspector でLogResultsコンポーネントの Object Detection Manager フィールドに Main Camera を割り当てます。  
- 
Unityエディターでプレイバ ックデータセットを使用してシーンを実行するか、モバイルデバイスでログコンソールを接続して実行してみましょう。 オブジェクト検出機能によって、カメラフィード内で検出されたクラスと信頼度の値が表示されます。   
バウンディングボックスを設定する
オーバーレイを作成してバウンディングボックスを表示することで、オブジェクト検出の結果を画面上にリアルタイムに表示することができます。 それぞれのバウンディングボックスは、左上隅を指す座標と、オブジェクト検出コードから得られるサイズで定義されます。 このオーバーレイをARカメラの背景に配置し、複数のバウンディングボックスを同時に表示できる再利用可能なプレハブを作成します。
- 
Hierarchyでメインシーンを右クリックし、UIにマウスオーバーしてCanvasを選択します。 
- 
Canvasを選択した状態で、 Inspector で Canvas Scalar コンポーネントを見つけます。 UI Scale ModeをSelect Scale With Screen Sizeに設定し、Matchを0.5に設定します。   
- 
Hierarchy で、 Canvas を右クリックして Create Empty を選択します。 新しいオブジェクトに BoundingBoxOverlayという名前を付けます。  
- 
BoundingBoxOverlayを選択した状態で、 Inspector でRect Transformの Anchor Presets を両軸で Stretch に設定し、 Shift キーと Alt キーを押しながらピボットと位置も設定します。  - Anchor Presets を Stretch に設定した後、 Rect TransformのLeft、Right、Top、Bottomの位置フィールドが変更された場合は、これらを再度ゼロにリセットします。
 
- Anchor Presets を Stretch に設定した後、 
- 
以下の手順で、バウンディングボックスプレハブを作成します。 - 
Hierarchy で、 BoundingBoxOverlayを右クリックして Create Empty を選択します。 新しいオブジェクトにRectObjectという名前を付けます。  
- 
RectObjectを選択した状態で、 Inspector でRect Transformの Anchor Presets を Bottom-Left に設定します。
- 
Rect Transformの Pivot をX:0, Y:1 に設定します。 
- 
位置の値を次のように設定します。 - Pos X: 0
- Pos Y: 1920
- Pos Z: 0
- Width: 1080
- Height: 1920
 
- 
Add Component をクリックし、 RectObjectに Image コンポーネントを追加します。
- 
Source Image フィールドで、検索ボックスを開き、アセットを検索します。 Backgroundアセットを見つけて選択します(Resources/unity_builtin_extra/にあるビルトインアセット)。
- 
Fill Center ボックスのチェックをオフにします。 
- 
Add Component をクリックし、 RectObjectに New script を追加します。 スクリプトに UIRectObject という名前を付けます。  
- 
UIRectObjectスクリプトをダブルクリックして開き、 内容を次のコードに置き換えて、バウンディングボックスがオブジェクトを正確に囲むようにします。
 
- 
クリックしてバウンディングボックスのコードを表示
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEditor;
    using UnityEngine;
    using UnityEngine.UI;
    [RequireComponent(typeof(RectTransform), typeof(Image))]
    public class UIRectObject : MonoBehaviour
    {
        private RectTransform _rectangleRectTransform;
        private Image _rectangleImage;
        private Text _text;
        public void Awake()
        {
            _rectangleRectTransform = GetComponent<RectTransform>();
            _rectangleImage = GetComponent<Image>();
            _text = GetComponentInChildren<Text>();
        }
        public void SetRectTransform(Rect rect)
        {
            _rectangleRectTransform.anchoredPosition = new Vector2(rect.x, rect.y);
            _rectangleRectTransform.sizeDelta = new Vector2(rect.width, rect.height);
        }
        public void SetColor(Color color)
        {
            _rectangleImage.color = color;
        }
        public void SetText(string text)
        {
            _text.text = text;
        }
        public RectTransform getRectTransform(){
            return _rectangleRectTransform;
        }
    }
- 
Hierarchy で、 RectObjectを右クリックして Create Empty を選択します。 新しいオブジェクトにCategory Textという名前を付けます。  - 
Inspector で、Shift キーと Alt キーを押しながら、Rect Transformの Anchor Presets を Stretchに設定して、ピボットと位置も設定します。 
- 
Height を 400 に設定します。 
- 
Add Component をクリックして、 Category Textに Text コンポーネントを追加します。
- 
Text フィールドに、 Label: Probなどのダミーテキストを追加します。
- 
Alignment を水平方向および垂直方向で中央揃えに設定します。 Best Fit にチェックを入れ、 Max Size を 100 に設定します。 Color を緑色に設定します。   
- 
Project タブ で、 Assets ディレクトリを右クリックし、 Create メニューを開いて Folder を選択します。 Prefabsという名前を付けます。
- 
RectObjectゲームオブジェクトを Inspector から Project タブの Prefab ディレクトリにドラッグして、バウンディングボックスのプレハブを作成します。  
 
- 
- 
Hierarchy で BoundingBoxOverlayを選択し、Inspector で Add Component をクリックして New Script を選択します。 スクリプトにDrawRectという名前を付けます。
- 
DrawRectスクリプトをダブルクリックして開きます。
- 
検出された各オブジェクトに対してインスタンス化するプレハブの型に SerializedFieldを追加します。 これをプールにキャッシュしてパフォーマンスを向上させます。
    public class DrawRect : MonoBehaviour
    {
        [SerializeField]
        private GameObject _rectanglePrefab;
        private List<UIRectObject> _rectangleObjects = new List<UIRectObject>();
        private List<int> _openIndices = new List<int>();
- 新しいバウンディングボックスを作成して、プールに追加する関数を追加します。 プレハブのプールを維持し、繰り返しの割り当てを避けるために再利用します。
    public void CreateRect(Rect rect, Color color, string text)
    {
        if (_openIndices.Count == 0)
        {
            var newRect = Instantiate(_rectanglePrefab, parent: this.transform).GetComponent<UIRectObject>();
            _rectangleObjects.Add(newRect);
            _openIndices.Add(_rectangleObjects.Count - 1);
        }
        // 最初のインデックスをキューとして扱う
        int index = _openIndices[0];
        _openIndices.RemoveAt(0);
        UIRectObject rectangle = _rectangleObjects[index];
        rectangle.SetRectTransform(rect);
        rectangle.SetColor(color);
        rectangle.SetText(text);
        rectangle.gameObject.SetActive(true);
    }
- すべてのバウンディングボックスを非表示にし、次の予測結果のた めにプールに戻す関数を追加します。
    public void ClearRects()
    {
        for (var i = 0; i < _rectangleObjects.Count; i++)
        {
            _rectangleObjects[i].gameObject.SetActive(false);
            _openIndices.Add(i);
        }
    }
クリックして DrawRect スクリプト全体を表示
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DrawRect : MonoBehaviour
{
    [SerializeField]
    private GameObject _rectanglePrefab;
    private List<UIRectObject> _rectangleObjects = new List<UIRectObject>();
    private List<int> _openIndices = new List<int>();
    public void CreateRect(Rect rect, Color color, string text)
    {
        if (_openIndices.Count == 0)
        {
            var newRect = Instantiate(_rectanglePrefab, parent: this.transform).GetComponent<UIRectObject>();
            _rectangleObjects.Add(newRect);
            _openIndices.Add(_rectangleObjects.Count - 1);
        }
        // 最初のインデックスをキューとして扱う
        int index = _openIndices[0];
        _openIndices.RemoveAt(0);
        UIRectObject rectangle = _rectangleObjects[index];
        rectangle.SetRectTransform(rect);
        rectangle.SetColor(color);
        rectangle.SetText(text);
        rectangle.gameObject.SetActive(true);
    }
    public void ClearRects()
    {
        for (var i = 0; i < _rectangleObjects.Count; i++)
        {
            _rectangleObjects[i].gameObject.SetActive(false);
            _openIndices.Add(i);
        }
    }
}
- 
Hierarchy で RectObjectを削除します。 これでBoundingBoxOverlayに子オブジェクトがなくなります。RectObjectは次のセクションでスクリプトによって動的に配置されます。  
- 
Inspector で RectObject プレハブを DrawRectコンポーネントの Rectangle Prefab フィールドに割り当てます。  
バウンディングボック ス検出スクリプトを追加する
最後のタスクは、Lightship Object検出機能からの結果をバウンディングボックスオーバーレイに渡すスクリプトを書きます。 このスクリプトは先に書いた LogResults クラスと似ているが、表示スペースを節約するために、このクラスは各結果に対して最も確信の持てる分類だけをラベル付けします。
- 
Hierarchyで右クリックし、Create Emptyを選択すると、シーンに新しいゲームオブジェクトが作成されます。 Sampleという名前を付けます。  
- 
Sampleを選択した状態で、Inspector で Add Component をクリックし、New Script を追加します。ObjectDetectionSampleという名前を付けます。
- 
ObjectDetectionSampleスクリプトをダブルクリックして開きます。
- 
検出閾値として、 AR Object Detection Manager、バウンディングボックスを画面に表示するクラスのフィールドを追加します:
    public class ObjectDetectionSample:MonoBehaviour
    {
        [SerializeField]
        private float _probabilityThreshold = 0.5f;
        [SerializeField]
        private ARObjectDetectionManager _objectDetectionManager;
        private Color[] _colors = new Color[]
        {
            Color.red,
            Color.blue,
            Color.green,
            Color.yellow,
            Color.magenta,
            Color.cyan,
            Color.white,
            Color.black
        };
        [SerializeField]
        private DrawRect _drawRect;
        private Canvas _canvas;
- 初期化と初期化解除のライフサイクルに関数を追加します。  AR Object Detection Managerに新しいオブジェクト検出結果があると、新しいObjectDetectionsUpdated関数が最新の結果とともに呼び出されます。
    private void Awake()
    {
        _canvas = FindObjectOfType<Canvas>();
    }
    public void Start()
    {
        _objectDetectionManager.enabled = true;
        _objectDetectionManager.MetadataInitialized += OnMetadataInitialized;
    }
    private void OnDestroy()
    {
        _objectDetectionManager.MetadataInitialized -= OnMetadataInitialized;
        _objectDetectionManager.ObjectDetectionsUpdated -= ObjectDetectionsUpdated;
    }
    private void OnMetadataInitialized(ARObjectDetectionModelEventArgs args)
    {
        _objectDetectionManager.ObjectDetectionsUpdated += ObjectDetectionsUpdated;
}.
- 次に、オブジェクトの検出結果とユーザーが画面に表示するものを結びつけるために、ObjectDetectionsUpdatedを追加します。 この関数は、以前のバウンディングボックスの結果のフレームをクリアすることから始まります。
    private void ObjectDetectionsUpdated(ARObjectDetectionsUpdatedEventArgs args)
    {
        string resultString = "";
        float _confidence = 0;
        string _name = "";
        var result = args.Results;
        if (result == null)
        {
            return;
        }
        _drawRect.ClearRects();
- 結果をループ処理します。 結果には、異なる信頼度の複数の分類が含まれることがあります。 ここでは、この関数を使用して、信頼度が最も高い分類を表示します。
    for (int i = 0; i < result.Count; i++)
    {
        var detection = result[i];
        var categorizations = detection.GetConfidentCategorizations(_probabilityThreshold);
        if (categorizations.Count <= 0)
        {
            break;
        }
        categorizations.Sort((a, b) => b.Confidence.CompareTo(a.Confidence));
        var categoryToDisplay = categorizations[0];
        _confidence = categoryToDisplay.Confidence;
        _name = categoryToDisplay.CategoryName;
- オブジェクトの最も確実な予測ができたら、CalculateRectを使ってそのバウンディングボックス領域をビューポート空間に変換します。 この例では、ARカメラの背景画像に合わせたキャンバスに結果が表示されます。 先ほどのDrawRectクラスは、新しい位置とラベルを持つRectObjectバウンディングボックスをアクティブにします。
        int h = Mathf.FloorToInt(_canvas.GetComponent<RectTransform>().rect.height);
        int w = Mathf.FloorToInt(_canvas.GetComponent<RectTransform>().rect.width);
        // 検出されたオブジェクトの周りの矩形を取得
        var _rect = result[i].CalculateRect(w,h,Screen.orientation);
        resultString = $"{_name}: {_confidence}\n";
        // 矩形を描画
        _drawRect.CreateRect(_rect, _colors[i % _colors.Length], resultString);
    }
クリックして、 ObjectDetectionSample スクリプト全体を表示
    using Niantic.Lightship.AR.ObjectDetection;
    using UnityEngine;
    public class ObjectDetectionSample: MonoBehaviour
    {
        [SerializeField]
        private float _probabilityThreshold = 0.5f;
        [SerializeField]
        private ARObjectDetectionManager _objectDetectionManager;
        private Color[] _colors = new Color[]
        {
            Color.red,
            Color.blue,
            Color.green,
            Color.yellow,
            Color.magenta,
            Color.cyan,
            Color.white,
            Color.black
        };
        [SerializeField]
        private DrawRect _drawRect;
        private Canvas _canvas;
        private void Awake()
        {
            _canvas = FindObjectOfType<Canvas>();
        }
        public void Start()
        {
            _objectDetectionManager.enabled = true;
            _objectDetectionManager.MetadataInitialized += OnMetadataInitialized;
        }
        private void OnDestroy()
        {
            _objectDetectionManager.MetadataInitialized -= OnMetadataInitialized;
            _objectDetectionManager.ObjectDetectionsUpdated -= ObjectDetectionsUpdated;
        }
        private void OnMetadataInitialized(ARObjectDetectionModelEventArgs args)
        {
            _objectDetectionManager.ObjectDetectionsUpdated += ObjectDetectionsUpdated;
        }
        private void ObjectDetectionsUpdated(ARObjectDetectionsUpdatedEventArgs args)
        {
            string resultString = "";
            float _confidence = 0;
            string _name = "";
            var result = args.Results;
            if (result == null)
            {
                return;
            }
            _drawRect.ClearRects();
            for (int i = 0; i < result.Count; i++)
            {
                var detection = result[i];
                var categorizations = detection.GetConfidentCategorizations(_probabilityThreshold);
                if (categorizations.Count <= 0)
                {
                    break;
                }
                categorizations.Sort((a, b) => b.Confidence.CompareTo(a.Confidence));
                var categoryToDisplay = categorizations[0];
                _confidence = categoryToDisplay.Confidence;
                _name = categoryToDisplay.CategoryName;
                int h = Mathf.FloorToInt(_canvas.GetComponent<RectTransform>().rect.height);
                int w = Mathf.FloorToInt(_canvas.GetComponent<RectTransform>().rect.width);
                // 検出されたオブジェクトの周囲の矩形を取得
                var _rect = result[i].CalculateRect(w,h,Screen.orientation);
                resultString = $"{_name}: {_confidence}\n";
                // 矩形を描画
                _drawRect.CreateRect(_rect, _colors[i % _colors.Length], resultString);
            }
        }
    }
- 
セットアップを完了するには、 ObjectDetectionSampleコンポーネントにオブジェクトを割り当てます:- Object Detection ManagerフィールドにMain Cameraを割り当てます。
- BoundingBoxOverlayを Draw Rect フィールドに割り当てます。
   
- Object Detection Managerフィールドに
結果例
これで、AR Playbackまたはモバイルデバイスを使ってオブジェクト検出をテストし、適切なクラスのオブジェクトにオーバーレイされたバウンディングボックスを確認できるはずです。
デフォルトの確率閾値は0.5で、これはオブジェクト検出アルゴリズムが少なくとも50%の一致の確信がある場合にバウンディングボックスを作成することを意味します。 Object Detection SampleコンポーネントのProbability Thresholdを増やしてみて、結果がどう変わるか見てみましょう。
