本文へスキップ
バージョン: 3.5

オブジェクト検出を有効にする方法

Lightship Object Detectionは、Lightshipのコンテキスト認識システムに200以上のクラスを追加し、画像内のオブジェクトの周囲にセマンティックにラベル付けされた2Dバウンディングボックスを可能にします。 バウンディングボックスと検出信頼度を提供することで、オブジェクト検出は、あなたの周りの物質世界をインテリジェントに認識し、ARアプリに強力な次元を追加します。

このハウツーは、あなたがこの機能を使い始めるためのものです:

  • シーンにオブジェクト検出を追加する
  • カメラに映った被写体のログ
  • 画面上のオブジェクトにリアルタイムでラベリング

オブジェクト検出クラスの詳細については、機能ページを参照してください。

Object detection demonstration graphic

前提条件

ARDKをインストールしたUnityプロジェクトと、基本的なARシーンが必要です。 詳しくは、ARDK 3のインストールおよびARシーンの設定を参照してください。

ARオブジェクト検出マネージャの追加

AR Object Detection Manager**を追加する:

  1. Lightship**トップメニューを開き、XR Plug-in Managementを選択し、Niantic Lightship SDKメニューを開きます。 オブジェクト検出が有効になっていることを確認する。

  2. ARシーン階層で、XROriginCamera Offsetを展開し、Main Cameraを選択します。

  3. Inspector**で、Add Componentをクリックし、メインカメラに「AR Object Detection Manager」を追加します。

    An AR Object Detection Manager added as a component of the Main Camera

オブジェクト検出結果の印刷

Object Detection が提供するデータを見るには、ObjectDetectionsUpdated イベントに登録する。 これは、新しいオブジェクト検出結果があったときにコールバックを出力する。 オブジェクト検出がARカメラ画像内の何かを認識した場合、イベントは結果のリストを返し、各結果はカメラ画像の領域に対応する。 オブジェクト検出がオブジェクトの複数の可能な分類を予測した場合、各結果は複数のオブジェクトカテゴリを含む可能性がある。 最も可能性の高い分類に焦点を当てるために、結果を信頼値でフィルタリングして並べ替えることができます。

物体検出出力をモニターする:

  1. Hierarchy**で右クリックし、Create Emptyを選択すると、新しいGameObjectがシーンに追加されます。 名前を LogResults とする。

    LogResults in the scene hierarchy
  2. LogResultsを選択した状態で、**Inspector** で **Add Component** をクリックし、**New Script** を追加します。 名前をLogResults` とする。

    LogResults with the new script added
  3. LogResults.cs`をダブルクリックして開く。

  4. ARオブジェクト検出マネージャ`のシリアライズフィールドを追加する。 マネージャーは、私たちが結果に集中できるように、機能実行に関する詳細を世話する。

    using UnityEngine;
using Niantic.Lightship.AR.ObjectDetection;

public class LogResults : MonoBehaviour
{
[SerializeField]
private ARObjectDetectionManager _objectDetectionManager;
  1. Start()が実行されたら、マネージャを有効にして OnMetadataInitialized` イベントを登録する。 オブジェクト検出が処理を開始したときに発火する。
private void Start()
{
_objectDetectionManager.enabled = true;
_objectDetectionManager.MetadataInitialized += OnMetadataInitialized;
}.
  1. 機能の準備ができたら、ObjectDetectionsUpdatedイベントに登録して、自動的に結果を受け取るようにする。
private void OnMetadataInitialized(ARObjectDetectionModelEventArgs args)
{
_objectDetectionManager.ObjectDetectionsUpdated += ObjectDetectionsUpdated;
}.
  1. ObjectDetectionsUpdated()`という関数を作り、結果を文字列にしてコンソールに記録する。
    private void ObjectDetectionsUpdated(ARObjectDetectionsUpdatedEventArgs args)
{
// 出力文字列を初期化する
string resultString = "";
var result = args.Results;

if (result == null)
{
return;
} // 結果文字列をリセットする。

// 結果をリセットする 文字列
resultString = ""
  1. 結果をループする。
    // 結果を繰り返し処理する。
for (int i = 0; i < result.Count; i++)
{
var detection = result[i];
var categorizations = detection.GetConfidentCategorizations();
if (categorizations.Count <= 0)
{
break;
}.
信頼度によるフィルタリング

確率のしきい値が指定されない場合、この関数はデフォルトで0.4の信頼度スコアのフィルタリングを行います。

  1. 各結果には複数のオブジェクト・カテゴリーが含まれることがあるので、信頼度の高いものから低いものへとリストアップする。
    //
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} 信頼性 \n";
}.
}
  1. 最後に、見たすべての結果とカテゴリーを記録する。
        // 全ての結果をログに記録
Debug.Log(resultString);
}.
  1. 最後に後片付けをお忘れなく!
    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;
} // 結果文字列をリセットする。

// 結果をリセットする string
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 += "検出された " + $"{categoryToDisplay.CategoryName}: " + "with " + $".{categoryToDisplay.Confidence} 信頼性 \n";
}.
}

// 全ての結果をログ
Debug.Log(resultString);
}


private void OnDestroy()
{
_objectDetectionManager.MetadataInitialized -= OnMetadataInitialized;
_objectDetectionManager.ObjectDetectionsUpdated -= ObjectDetectionsUpdated;
}.
}

完成したスクリプトをプロジェクトに追加する

  1. HierarchyLogResultsを選択し、InspectorLogResults ComponentのObject Detection ManagerフィールドにMain Camera**を割り当てます。

    LogResults with the Object Detection Manager field assigned
  2. Unityエディタでplayback datasetを使って、またはモバイルデバイスでロギングコンソールを接続してシーンを実行してみてください。 オブジェクト検出では、カメラフィードで検出されたクラスと信頼値が表示されます。

    The console output after running object detection on a dataset in the Editor

バウンディング・ボックスの設定

バウンディングボックスを表示するオーバーレイを作成することで、オブジェクト検出結果を画面上にライブ表示することができる。 それぞれのバウンディングボックスは、左上隅を指す座標と、オブジェクト検出コードから得られるサイズで定義されます。 このオーバーレイをARカメラ背景の上に配置し、複数のバウンディングボックスを一度に表示するために再利用できるプレハブを作成します。

  1. Hierarchyでメインシーンを右クリックし、UIにマウスオーバーしてCanvasを選択します。

  2. キャンバスを選択した状態で、インスペクタでキャンバススケーラーメニューを見つけます。 Scale With Screen Sizeを選択し、Match0.5**に設定します。

    Canvas with fields configured
  3. 階層**で、キャンバスを右クリックし、空の作成を選択します。 新しいオブジェクトの名前を BoundingBoxOverlay とする。

    BoundingBoxOverlay in the hierarchy
  4. BoundingBoxOverlayを選択した状態で、**Inspector**で、**Shift**と**Alt**を押しながら、両軸のRect Transform` Anchor PresetsStretchに設定し、ピボットと位置も設定します。

    Setting the Anchor Presets of BoundingBoxOverlay to stretch for X and Y
    1. Anchor Presets** を Stretch に設定した後、Rect TransformLeft, Right, Top, Bottom の位置フィールドが変更されていれば、再度ゼロにします。
  5. バウンディングボックスプレハブを作成します:

    1. Hierarchy**でBoundingBoxOverlayを右クリックし、Create Emptyを選択します。 新しいオブジェクトの名前を RectObject とする。

      RectObject in the hierarchy
    2. RectObjectを選択した状態で、**Inspector** でRect Transform` Anchor PresetsBottom-Left に設定します。

    3. Rect TransformのPivotをX:0, Y:1に設定します。

    4. ポジションの値は以下のように設定する:

      • Xポジション:0
      • ポスY:1920
      • ポジション Z: 0
      • 1080
      • 身長1920
    5. Add Componentをクリックし、RectObjectImage**コンポーネントを追加します。

    6. ソース画像**フィールドで、アセットを検索するために検索ボックスを開きます。 Backgroundアセットを探して選択します(これは Resources/unity_builtin_extra/` にある組み込みアセットです)。

    7. センターを埋める**のチェックを外す。

    8. Add Componentをクリックし、RectObjectNew script**を追加します。 スクリプトに UIRectObject という名前を付ける。

      RectObject with fields configured
    9. 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;
}.
}
  1. Hierarchy**でRectObjectを右クリックし、Create Emptyを選択します。 新しいオブジェクトの名前を Category Text とする。

    Category Text in the hierarchy
    1. Inspectorで、矩形変形Anchor PresetsStretchに設定し、ShiftAlt**を押しながらピボットと位置も設定します。

    2. 高さ400**に設定する。

    3. Add Componentをクリックして、Category TextText**コンポーネントを追加します。

    4. Text**フィールドに、Labelのようなフィラー・テキストを追加する:Prob`.

    5. Alignmentを水平方向と垂直方向の中央に設定する。 Best Fitをチェックし、Max Size100に設定します。 色**を緑に設定する。

      Category Text with fields configured
    6. Projectタブで、Assetsディレクトリを右クリックし、Createメニューを開いてFolder**を選択します。 名前はPrefabs

    7. RectObject`ゲームオブジェクトをInspectorからProjectタブのPrefabディレクトリにドラッグして、バウンディングボックスのプレハブを作成します。

      The final RectObject prefab in the Project tab
  2. Hierarchy**で、BoundingBoxOverlayを選択し、Inspectorで、Add Componentをクリックし、New Scriptを選択します。 スクリプトの名前を DrawRect とする。

  3. DrawRect`スクリプトをダブルクリックして開く。

  4. 検出されたオブジェクトごとにインスタンス化するプレハブのタイプに対応する SerializedField を追加します。 パフォーマンスを向上させるために、それらをプールにキャッシュする。

    public class DrawRect : MonoBehaviour
{
[SerializeField]
private GameObject _rectanglePrefab;

private List<UIRectObject> _rectangleObjects = new List<UIRectObject>();
private List<int> _openIndices = new List<int>()
  1. 新しいバウンディング・ボックスを作成し、プールに追加する関数を追加する。 私たちはプレハブのプールを保持し、繰り返しの割り当てを避けるためにそれらを再利用します。
    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);
}
  1. すべてのバウンディングボックスを非表示にし、次の予測結果のプールに戻す関数を追加する。
    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);
}.
}
}
  1. 階層**で、RectObjectを削除する。 BoundingBoxOverlayは子オブジェクトを持たないようになりました。 RectObjectは次のセクションでスクリプトによって動的に配置される。

    The Hierarchy after deleting the original RectObject
  2. Inspector**で、RectObject プレハブを DrawRect コンポーネントの Rectangle Prefab フィールドに割り当てます。

    The final BoundingBoxOverlay

バウンディングボックス検出スクリプトの追加

最後のタスクは、Lightship Object検出機能からの結果をバウンディングボックスオーバーレイに渡すスクリプトを書きます。 このスクリプトは先に書いた LogResults クラスと似ているが、表示スペースを節約するために、このクラスは各結果に対して最も確信の持てる分類だけをラベル付けします。

  1. Hierarchyで右クリックし、Create Emptyを選択すると、シーンに新しいゲームオブジェクトが作成されます。 それを Sample と名付けます。

    Sample in the scene hierarchy
  2. Sample を選択した状態で、InspectorAdd Component をクリックし、New Script を追加します。 これを ObjectDetectionSample と名付けます。

  3. ObjectDetectionSampleスクリプトをダブルクリックして開きます。

  4. 検出閾値として、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;
  1. 初期化と初期化解除のライフサイクルに関数を追加します。 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;
}.
  1. 次に、オブジェクトの検出結果とユーザーが画面に表示するものを結びつけるために、ObjectDetectionsUpdatedを追加します。 この関数は、以前のバウンディングボックスの結果のフレームをクリアすることから始まります。
    private void ObjectDetectionsUpdated(ARObjectDetectionsUpdatedEventArgs args)
{
string resultString = "";
float _confidence = 0;
string _name = "";
var result = args.Results;
if (result == null)
{
return;
}.

_drawRect.ClearRects()
  1. 結果をループする。 ある結果が、異なる信頼レベルで複数の分類を持つこともある。 今のところ、この関数は信頼値が最も高いものを表示する。
    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;
  1. オブジェクトの最も確実な予測ができたら、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); { 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);
}.
}
}
  1. セットアップを完了するには、ObjectDetectionSampleコンポーネントにオブジェクトを割り当てます:

    1. Object Detection ManagerフィールドにMain Cameraを割り当てます。
    2. BoundingBoxOverlayDraw Rect フィールドに割り当てます。
    The Sample object with fields configured

結果例

これで、AR Playbackまたはモバイルデバイスを使ってオブジェクト検出をテストし、適切なクラスのオブジェクトにオーバーレイされたバウンディングボックスを確認できるはずです。

確率の閾値

デフォルトの確率閾値は0.5で、これはオブジェクト検出アルゴリズムが少なくとも50%の一致の確信がある場合にバウンディングボックスを作成することを意味します。 Object Detection SampleコンポーネントのProbability Thresholdを増やしてみて、結果がどう変わるか見てみましょう。

An example of object detection in action