Azure Mixed Reality の新サービス「Azure Object Anchors」を使う

# 新しいAzure Mixed Reality サービスを利用可能に

<iframe width="560" height="315" src="https://www.youtube.com/embed/xRuKztO-Obo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

Ignite 2021で発表になった「Azure Object Anchors」のプレビュー提供開始の情報。空間を扱うMixed Realityのサービスをサポートする新しいサービスとしても非常に強力で多くの活用方法が期待できるサービスといえると思います。
今回は実際に現実の物体をアンカーとして活用するための確認としてAzure Object AnchorsのQuick Startの設定方法とAzure Object Anchors SDkの情報について共有したいと思います。

## その前に空間を扱うMixed Reality サービス

Azure Object Anchorsを含めてMicrosoft空間を扱うMixed Realityサービスについてはいくつかあります。どれも重要な技術なので紹介しておきますね。

* [Azure Spatial Anchors(HoloLens 1/2, Android, iOS)](https://docs.microsoft.com/ja-jp/azure/spatial-anchors/)<BR>
現実空間の特徴と利用した空間アンカーを管理するサービス。空間情報＋アンカー以外に以下の情報も保持可能
<ul><li>センサー情報（GPS, Wi-fi, Bluetooth）</li>
<li>付加情報(String型のDictionary)</li></ul>
* [Azure Object Anchors(HoloLens 2)](https://docs.microsoft.com/ja-jp/azure/object-anchors/)<br>
現実の物体をアンカーとして利用できるサービス。現実の物体はあらかじめ3Dモデルとして学習させておく必要がある。
* [World Locking Tool(HoloLens 1/2, Android, iOS)](https://microsoft.github.io/MixedReality-WorldLockingTools-Unity/README.html)<br>
現実空間とデジタル情報の位置合わせをより広域で高精度に利用するためのライブラリ。デバイスに搭載されたセンサーでは有効範囲（見渡せる範囲）以上遠くにあるデジタルコンテンツは現実空間とずれる傾向がある。これを安定させるためのアンカー制御を自動化できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/809db02a-ca82-cfd9-9a9e-c65316492189.png)
上記の図はそれぞれのサービスやライブラリがどのような関係にあるかを模式的に表現した図です。Mixed Realityにおいてどのように空間情報を扱いたいかによって利用するサービスが変わります。

## Azure Object Anchorsの概要

そんなMixed Realityに必要な空間を活用サービスの中でIgnite 2021でプレビュー提供がアナウンスされたAzure Object Anchorsを紹介したいと思います。
Azure Object Anchorsは一言でいえば ***「現実の物体を基準点（アンカー）として活用するサービス」*** になります。
以下の写真は実際にAzure Object Anchorsを利用して現実空間に存在する「バランスボール」をアンカーとして紐づけた際のスクリーンショットになります。
現実空間をHoloLens 2でスキャンしその情報の中から、物体の形状が一致する部分を検索し合致する場所の正確な位置と向き(6Dof)を推定することが可能です。
なお、バランスボールを使う場合は位置を正確に把握することは可能なのですが方向については不定になります。球体のためどこが正面かを推定できないためです。

![20210323_174110_HoloLens.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/e50c04c4-b7e1-4399-a65e-aef046b2ada6.jpeg)

### 物体の検出の仕組み

Azure Object Anchorsを利用することで現実の物体を検出することが可能です。基準となる物体を把握するためにAzure Object Anchorsでは現実の物体と同形状の3Dモデルから学習済みファイル(.ou)を生成する必要があります。学習済みモデルの生成についてはAzure Object Anchors SDKを利用することで簡単に登録することが可能です。

#### ３Dモデルデータの取り込みについて

現実の物体と同じ3Dモデルについては、3DモデリングツールやCAD等色々活用することが可能ですが、利用できる情報についてはいくつかの制約事項があります。制約を守らなくても検出自体は可能ですが、精度は悪くなります。3Dモデルを用意する場合は以下の情報を参考に用意してくさだい。
詳しい情報は[公式ドキュメント:推奨する運用方法 - ベスト プラクティス - データの取り込み](https://docs.microsoft.com/ja-jp/azure/object-anchors/best-practices#ingestion)を参照してください。

| 属性 | 説明 |
|:-:|:--|
| フォーマット | .glb, .gltf, .ply, .fbx, .obj   |
| 物体サイズ  | 1m～10mの範囲内が一番検出しやすい  |
| 適切なスケール   | センチメートル, デシメートル, フィート, インチ, キロメートル, メートル, ミリメートル, ヤード  |
| オブジェクトの重力方向  | オブジェクトの下向き-Y の場合は、(0, -1, 0)  |
【注意点】
サイズが大きく、LOD (詳細レベル) が高いモデルの処理には時間がかかる可能性あり。

### 物体の検出について

物体の検出についてもいくつか注意事項、制約が存在します。詳しい情報は[公式ドキュメント:推奨する運用方法 - ベスト プラクティス - 検出](https://docs.microsoft.com/ja-jp/azure/object-anchors/best-practices#detection)を参照してください。
    

* 検索領域の指定が必要<br/>検索領域の形状は、直方体, 球, 視錐台, それらを組み合わせたもの。 誤検出を回避するためには、対象を覆う十分な大きさの検索領域を設定することが推奨。<br/><br/>
* 作業空間の近くにあるホログラムを削除。<br/>
作業場所の過去の情報から余計なオブジェクト残っている場合は表示に悪影響があるため、環境としてクリーンにしておくことで視覚化で混乱を生じないようにすることができます。<br/><br/>
* アプリを起動する前の空間スキャンの実地<br/>
検出する物体から約1～2メートル程離れたところからデバイスを装着し対象オブジェクトの周りをゆっくりと 1、2 回まわることで予め空間をスキャンする。<br/>これは現在の空間状況を更新することで誤検出や待機時間を削減する効果があります。実施することによりAzure Object Anchors 検出の待機時間も大幅に (30 秒から 5 秒) 短縮されます。<br/><br/>
* オブジェクトの質感によっては様々な方向から空間スキャンを実施しておく必要がある<br/>
暗色や光沢のある表面が反射するオブジェクトの場合は、近づいたり、様々な角度、位置から物体の表面を認識しておく必要があります。これによって検出率に影響が出るとのこと。<br/><br/>
* 向きが反転したり、モデルが傾いているなど姿勢が正しくなかったりして、物体検出が正しく行われていない場合は、空間マッピングを視覚化する必要があります。 多くの場合、誤った結果は、サーフェスの再構築が適切に行われていない、または不完全であることが原因です。 ホログラムを削除し、オブジェクトをスキャンし、アプリで物体検出を再実行できます。<br/><br/>
* 検出がうまくいかない場合はランタイムSDKのパラメータ調整を実施<br/>
タイム SDK には、ユーザーが検出を微調整するためのパラメーターがあります(後述)。 大抵は変更しなくても十分機能しますが、うまくいかない場合は以下の情報をもとに調整する。
<ul>
<li>物理オブジェクトが大きい、暗色、または光沢がある場合は、表面のカバー率（一致度）の閾値を下げる</li>
<li>自動車のような大きなオブジェクトでは、スケール変更を考慮する</li>
<li>オブジェクトが傾斜地にある場合、オブジェクトのローカルの垂直方向と重力の間で確度のずれを考慮する。</li>
</ul>

## Azure Object Anchorsの利用

Azure Object Anchorsの利用については大きく次の2段階の作業があります。

* 現実の物体と一致する3Dモデルの作成とAzure Object Anchorsへの登録
* 現実空間の中で学習済みのモデルと一致する物体を検出

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/68594f6c-691d-3d4e-b14a-e8297883b392.png)

Quick Startではこの2つの手順を別のアプリで実現しています。実際のところAPIは公開されているので手作業の部分をいくつか省略は可能です。
まずは、Quick Startで現実の物体を検出するまでを試してその仕組みの理解を進めましょう

## Quick Startの実施手順

Quick Startを活用して実際に現実の物体をアンカーとして活用してみましょう。

### 必要なもの

Azure Object Anchorsを利用するにあたってかのものが必要になります。

* 検出する物体とその3Dモデル
* HoloLens 2
* 開発環境のソフトウェア一式

検出する物体とその3Dモデルがないことには始まりません。といってもそう都合よく物があるとは限りませんよね。
取り合えず家にあるシンプルな形状のものを利用しましょう。例えば、例にも挙げているようなバランスボールや段ボールといったものです。
こういった球体や直方体は3Dモデリングツールでは標準的なメッシュ情報としてそのまま利用できるので簡単にモデリングできます。
ただ、バランスボールのようなどの向きから見ても同じ形状に見えてしまうものは現実空間上の位置は検出できますが方向は検出できないため注意が必要です。
できれば、縦に長い段ボールなどがちょうどいいかもしれません。大きさは1mに近い方がうまくいきやすいと思います。

### 開発環境

開発環境といて用意したものは以下の通りです。

 * Unity 2019.4.19f1
 * [Windows 10 SDK(10.0.18362.0)](https://developer.microsoft.com/ja-jp/windows/downloads/windows-10-sdk/)
 * [Blender 2.92](https://www.blender.org/download/)
 * Visual Studio 2019(16.8.3)
 * [MR Feature Tool(1.0.2103.3-Beta)](https://www.microsoft.com/en-us/download/details.aspx?id=102778)
     * .NET 5.0 Desktop Runtime (v5.0.4)

Blenderは現実の物体をモデリングするために使います。それ以外は通常のHoloLens 2の開発環境と変わりません。
まずは3Dモデルの作成とAzure Object Anchorsの登録から始めましょう。

### Azure Object Anchorsサービスの登録
まずはAzureポータルでAzure Object Anchorsサービスを登録しましょう。手順については以下の通りですが[公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/object-anchors/quickstarts/get-started-model-conversion#create-an-object-anchors-account)にも同じ内容が紹介されています。
Azureポータルにアクセスしメニューから[リソースの作成]を選択しAzure Object Anchorsで検索します。見つかったら選択し作成に進みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/4bff1c93-76d5-f920-6014-e95bfbe2b685.png)

以下の4つを設定しAzure Object Anchorsサービスを作成します。

* リソース名
* サブスクリプション
* リソースグループ
* 場所（East US 2固定）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/7f1f2646-e021-0734-1562-c3812ceba52a.png)

作成したAzure Object Anchorsのリソースに移動します。概要の中の「アカウント ドメイン」、「アカウント ID」をメモに控えておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/8aa2c7e9-fa61-7c07-6dc4-c3986dbf5cf0.png)

アクセスキーを選択し[主キー]の値も控えておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/4fa81d5c-f6e1-7483-f624-a332c5725fe9.png)

以上で、Azure Object Anchorsのサービスの準備は完了です。
次に3Dモデルの作成を進めます。

### 3Dモデルの作成～Azure Object Anchorsへの登録

3Dモデルの登録については「[公式ドキュメント - クイック スタート: 3D モデルから Object Anchors モデルを作成する](https://docs.microsoft.com/ja-jp/azure/object-anchors/quickstarts/get-started-model-conversion)」に書いている通りで実施可能です。一度目を通しておくといいと思います。

#### 3Dモデルを作成する

最初に現実の物体にあう3Dモデルを作成します。Blenderを起動します。今回はバランスボールを検出するために球体の3Dモデルを作成します。
まずは起動時に原点にあるCubeを削除しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/aa3a753d-a69f-d03c-7ee4-115efa16297a.png)

球体を出力します。球体はShift+Aでメニューを表示し[メッシュ]-[UV球]を選択します。
今回使ったバランスボールは直径が約65cmのものだったので、3Dモデルの寸法を実物を合わせておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/ee9bca28-e2d1-ede5-4d80-94104cadddae.png)

これでモデルの作成は完了です。このあとAzure Object Anchorsに登録するためにエクスポートします。
球体を選択状態にしたままで、[ファイル]-[エクスポート]-[FBX(.fbx)]を選択しダイアログを表示します。
以下のパラメータを確認し任意のファイル名でエクスポートを実施します。

* 選択したオブジェクトをチェック
* オブジェクトタイプはメッシュのみ選択
* スケールは1.00
* スケールを適用はすべてFBX
* 前方 -zが前方
* 上 Yが上
* 単位を適用にチェック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/7040f1a4-3b29-ac12-3ea1-444dfbf80fc7.png)

これで、直径65cmの球体のモデルがエクスポートできます。スケールやサイズの設定が間違っていると物体の検出に失敗したりします。
以下はスケールを間違ったときの結果です。このような感じでずれてしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/421721b6-eba7-a961-fbc5-31ecaa881233.png)

FBXをエクスポートしたら次はAzure Object Anchorsのサンプルコードを取得し、3Dモデルの登録準備を行います。

#### Azure Object Anchorsのサンプルコードを取得

サンプルコードはgitで公開されているので以下のコマンドでサンプルコードを取得します。

```
git clone https://github.com/Azure/azure-object-anchors.git

cd ./azure-object-anchors
```

フォルダ構成は以下のようになっており、まずはconversionフォルダ内の資産で3Dモデルの登録を行います。

```
azure-object-anchors
    \---quickstarts
        +---apps
        \---conversion
```

#### Configurationツールをビルドして3Dモデルを登録する

conversionフォルダ内のソリューションファイルを開きVisual Studioを起動します。
起動後プロジェクト内の[Configuration.cs]を開き先ほど控えておいたAzure Object Anchorsの接続情報を入力します。なお、直接書かなくてもjsonファイルを用意してコマンドライン引数で指定することで登録することも可能です。

```csharp:Configuration.cs
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

using System;
using System.Numerics;
using Azure.MixedReality.ObjectAnchors.Conversion;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

namespace ConversionQuickstart
{
    public class Configuration
    {
        // Azure Object Anchors account identifier
        public string AccountId = "set me";

        // Azure Object Anchors account primary key
        public string AccountKey = "set me";

        // Azure Object Anchors account domain
        public string AccountDomain = "set me";

...
```

変更したらビルドを実行します。ビルドに成功したらexeを実行しましょう。
exeは登録するモデルのパスを引数に取ります。

```
cd [ビルド後のフォルダ]

ConversionQuickstart.exe [fbxのファイル名]
```
実行すると以下のように経過が表示され処理が正常に完了するとfbxを格納したフォルダの中に[fbxのファイル名]-[GUID].ouというファイルが生成されます。
このファイルがモデル学習済みのファイルで後でHoloLens 2用のアプリで利用します。

```
>ConversionQuickstart.exe D:\AOA_Model\sphere.fbx
Asset   : D:\AOA_Model\sphere.fbx ← 登録する3Dモデルファイル
Gravity : <0, -1, 0> ← オブジェクトの重量方向（blenderでの出力時に+Y方向を上にしたので-Yが重力方向になる。）
Unit    : Meters ← オブジェクトの寸法単位
Attempting to upload asset...
Attempting to create asset conversion job...
Successfully created asset conversion job. Job ID: 491ceca3-69f5-4b82-ad47-209900761f98
Waiting for job completion...

Asset conversion job completed successfully.
Attempting to download result as 'D:\AOA_Model\sphere_491ceca3-69f5-4b82-ad47-209900761f98.ou'...
Success!
```
ouファイルに格納されている情報はAzure Object Anchorsサービスで管理されています。もしなくした場合はAPI経由でGUIDを渡すことで情報を取得することが可能です。
Quick Startでは一度ouファイルをConversionQuickstart.exeで出力しHoloLensに登録していますが、HoloLensアプリの最初にGUID指定でデータをダウンロードしておくことも可能です。
ouファイルは利用するモデルによってサイズが変わるため、かなり大きなオブジェクトを対象にする場合は事前ダウンロードしておく方が待ち時間が減るなどはあると思います。

次にHoloLensにデプロイするアプリを作成しましょう。

### HoloLensアプリをデプロイする

HoloLens用のアプリは先ほどgitから取得したフォルダの[azure-object-anchors\quickstarts\apps\unity\mrtk]配下を利用します。HoloLensへデプロイするサンプルは素のHoloLensアプリとMRTKでUIがついているアプリの2種類あります。今回はUIがついている方を使っています。
フォルダの名前通り、プロジェクトにはMRTKの導入が必要になります。

#### MR Feature Tool で導入する

MRTKを導入するための方法はいくつかあるのですが、今回は最近提供された[MR Feature Tool](https://docs.microsoft.com/ja-jp/windows/mixed-reality/develop/unity/welcome-to-mr-feature-tool)でまとめて登録しましょう。[MR Feature Tool](https://docs.microsoft.com/ja-jp/windows/mixed-reality/develop/unity/welcome-to-mr-feature-tool)はMicrosoftのMixed Reality 関連のライブラリ群をUnityプロジェクトに導入するためのツールです。通常は手書きでPackages.jsonを変更する必要があるのですがこれを簡単にGUIで設定できるツールです。
まずはMR Feature Toolをダウンロードし、Zipファイルを展開します。なお実行時には.NET 5.0が必要になるので別途セットアップしておきましょう。

アプリを実行するとかっこいいロゴが出てくるので[Start]ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/57d6a4a4-0296-db1a-28dc-0bb8ed238f39.png)

次にUnityプロジェクトのパスを設定します。今回は「azure-object-anchors\quickstarts\apps\unity\mrtk」を指定します。
パスが正しければプロジェクトが利用するUnityのバージョンが表示されます。[Discover Features]を選択して次に移動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/17ad9787-d726-b8da-ff67-d9e1701178bd.png)

すると、Microsoftの様々な機能が一覧で表示されるので[Microsoft Azure Object Anchors]にチェックを入れてバージョンを[0.8.0]になっていることを確認して[Get Features]を押します。MRTKについてはUnityプロジェクトに設定済みのためチェックは不要です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/b8b80d29-f2b1-7da6-403d-63d77e17f2ee.png)

インポート対象とそれに依存するコンポーネントを確認することができます。Azure Object Anchorsが設定されていることを確認して[Import]をボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/ac4e16ba-1e06-ed99-27c0-754b2965344d.png)

変更後のマニフェストファイルとダウンロードされるモジュール名を確認することができます。[Approve]を押して設定を反映しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/b85027cc-d3f9-51b7-bb9e-deb68c4d96f2.png)

以上で必要なモジュールの設定は完了です。次にUnityを起動してプロジェクトファイルを読み込みます。

#### Unity でビルドを実施する

Unityでプロジェクトを開いた後[Project]タブの中から[Assets/MixedReality.AzureObjectAnchors/Scenes/AOASampleScene]を選択しシーンを開きます。


次にUWP形式でビルドを実施します。
[File] -> [Building Settings]をクリックします。 [Build Settings]ダイアログが表示されます。[Platform]を[Universal Windows Platform]を選択しし、 [Switch Platform]をクリックします。次のパラメータを変更しビルド設定を構成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/331f0a61-c802-9e86-82c6-669e9ac5d270.png)

[Build]をクリックします。出力フォルダーを選択すると、そのフォルダ配下にVS プロジェクトが生成されます。
次にVisual Studioを起動してHoloLensにデプロイします。

#### Visual StudioでHoloLensにデプロイする

Visual Studioでソリューションファイルを開きます。開いた後アーキテクチャをARM64に変更しHoloLensを有線接続、またはビルドマシンと同じネットワークにHoloLensを接続しデプロイを実施します。前者の場合は配置先を「デバイス」に、後者は「リモートマシン」を選択します。

### サンプルアプリをHoloLensで実行する

デプロイが完了したらいよいよアプリを実行します。その前に最初に作ったouファイルをアプリケーションで使えるようにします。

#### ouファイルのアップロード

HoloLensをUSB接続、もしくは同一ネットワークにある状態でデバイスポータルを起動します。起動後[System]-[File Explorer]を選択します。
パス：[User Folders\LocalAppData\AOAMRTKApp.X.X.X.X_arm64__XXXXX\LocalState\]へ移動し先ほど作ったouファイルをアップロードします。
もし上記パスにフォルダがない場合は一度HoloLensでアプリを起動してから実施してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/916b8693-717a-50b5-bd2c-278d39c80221.png)

#### アプリについて

Azure Object Anchorsはオフラインでも利用できます。今回のQuick Startのように事前にouファイルをダウンロードしてアプリに登録する場合スタンドアロンで実行できてしまいます。
アプリを起動すると正面に半透明の直方体が表示されています。この直方体はAzure Object Anchorsで現実の物体を検出する際の検索範囲になります。Azure Object Anchorsでは現実空間にエリアを設けてその範囲の空間で物体を検出するような仕組みになっています。直方体はエアタップで移動、各頂点をタップ&ホールドするとサイズを変更することができます。
まずは検出範囲の中に今回見つけ出すオブジェクトが入るように位置や大きさを調整します。
調整が済んだたら、どちらかの一方の手のひらを返してハンドメニューを表示します。
ハンドメニューにはいくつかのパラメータが設定できるのですが、特に複雑なオブジェクトでなければ調整せずに検出可能です。
ハンドメニューの中からStart Searchを押すと空間のスキャンが開始されます。
![mrtk-hand-menu-primary.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/094c2eaf-f20b-e54d-2160-55337f233fca.png)

検出範囲の物体検出を開始します。対象が見つかると現実の物体の表面に学習済みモデルのメッシュ情報が出力されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/01639c75-70d9-baa9-2752-12fcc760934e.png)