HoloLens 2 QRコードトラッキング (追跡) サンプルを試してみる 【 Unity 】

# Overview
HoloLens 2 からサポートされている QR Code トラッキング ( HoloLens 1st gen 非対応 ) に関して調査する機会があったので、調べた内容をまとめておきます。

# Support Devices

| 機能 | HoloLens (1st gen) | HoloLens 2 | Immersive Headset (没入型HMD) |
| --- | --- | --- | --- |
| QRコードの検出 | × | 〇 | 〇 | 

没入型 Windows Mixed Reality (WMR) ヘッドセット と デスクトップPC を使った QRコード(追跡)トラッキングは、 __Windows 10 Version 2004 以降__ で利用することができます。

Microsoft.MixedReality.QRCodeWatcher.IsSupported() API を使って、使用デバイスでQRコード(追跡)トラッキングが可能かどうか判定することができます。

# Detecting QR codes in Unity / QRコードの検出

QRコード検出を行うためには、```webcam``` capability が必要です。※これは Unity もしくは Visual Studio で設定する必要があります。

### 【 メリット 】

QRコードの検出はデバイスの環境認識カメラ ( HoloLens 2 の場合、4つの環境認識カメラ ) で行われています。これに伴って、より広範囲の視野角 ( FOV ) で検出可能となり、 ( 写真/動画撮影用カメラを使用時と比べて ) バッテリーの寿命を延ばすことができます。

__QRコード検出APIは Unity上でMRTKに依存することなく使用することも可能です。__
これを実現するためには、NuGet for Unity を使って、対象の NuGet パッケージをインストールしなければいけません。QR code detection ( QRコード検出 ) のための Nuget パッケージは[こちら](https://nuget.org/Packages/Microsoft.MixedReality.QR)からダウンロードすることができます。

### 【 デメリット 】
デバイス左右に各2つ、計4つの環境認識カメラを使用してQRコードを検出するため、QRコードのサイズがある程度大きくないと認識精度が上がらないというデメリットもあります。

ホロラボ CEO の中村薫さんも Twitter で言及されていたので、補足情報として引用させていただきます。ありがとうございます。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">HoloLens 2のQRトラッキング、環境認識カメラを使うのでフレームレートに影響をおよぼさない、QRコードのコード自体を検出してるので画像での認識のように似た画像で誤検出しない、とかがメリット。<br>デメリットは、左右で魚眼の環境認識カメラを使ってるのでマーカーにある程度のサイズが必要。</p>&mdash; 中村 薫 (@kaorun55) <a href="https://twitter.com/kaorun55/status/1310165989321891841?ref_src=twsrc%5Etfw">September 27, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 公式サンプル

公式ドキュメント上に MRTKを使った Unity 向けのサンプル ( GitHub ) が公開されていました。

GitHub ページ : [QRTracking/SampleQRCodes](https://github.com/chgatla-microsoft/QRTracking/tree/master/SampleQRCodes)

今回はこちらのサンプルを動作させる手順についてご紹介したいと思います。

### 概要 / Overview

QRコードを検出した際、QRコードの上に白い四角のCGが表示されます。
その他にQRコードから読み取った関連情報も表示されます。

- __GUID__ ( Globally Unique Identifier : グローバル識別子 )
- __Physical size__
- __Timestamp__
- __decode data__

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/a3331ca6-cfd2-8196-15f1-fd5bc1fa995e.png" width="650">

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Microsoft HoloLens 2 <br>QR Code 検出サンプルを<br>試してみた！<br><br>比較的広い範囲トラッキングできるのは、<br>写真/動画撮影用カメラではなく、<br>環境認識用のカメラを使用しているため。<br>( FOV 拡大 + バッテリー寿命も延びた )<br><br>📃公式ドキュメント<a href="https://t.co/lPeUHusDK2">https://t.co/lPeUHusDK2</a><a href="https://twitter.com/hashtag/HoloLens2?src=hash&amp;ref_src=twsrc%5Etfw">#HoloLens2</a> <a href="https://twitter.com/hashtag/QRCode?src=hash&amp;ref_src=twsrc%5Etfw">#QRCode</a> <a href="https://t.co/4MccVuop0G">pic.twitter.com/4MccVuop0G</a></p>&mdash; 堀尾風仁 Futo Horio (@Futo_Horio) <a href="https://twitter.com/Futo_Horio/status/1310161597256491009?ref_src=twsrc%5Etfw">September 27, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 検証環境

- 開発用PC ( Windows 10 Pro / ビルド番号 : 19041.207 )
  - Unity 2019.4.11f1
  - Visual Studio 2019 ( 16.6.2 )
  - Windows SDK 10.018362.0

- Microsoft HoloLens 2 ( OSビルド番号 : 10.0.19041.1106 )

# 手順解説

##### 1. GitHub から サンプルプロジェクト を Clone します。

```
git clone https://github.com/chgatla-microsoft/QRTracking.git
```

##### 2. Unity Hub で対象プロジェクトを追加 ( ADD ) します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/aa64533e-84f5-6552-4aab-28bbde5d0ff2.png" width="800">

2020年9月28日現在、``Unity 2019.4.0f1`` を使用したプロジェクトファイルとなっています。本記事では、Unity 2019.4.11f1 (LTS) で代替し、検証を進めることとします。

##### 3. 対象プロジェクトを Unity で開きます。

```QRTracking > SampleQRCodes ディレクトリ```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/a755f2c7-de05-2ae1-84f9-cf491dce593e.png" width="600">

##### 4. 対象シーン ( QRCodesSample.unity ) を開きます。

```Assets > Scenes > QRCodesSample.unity``` 

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/7e3a98ec-15a4-c371-1d71-c953badac44b.png" width="600">

以下、MRTK 基本コンポーネントの他に ```Axis```, ```QRCodesManager``` という ```GameObject``` が
ヒエラルキー内に存在していることを確認できると思います。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/7c073460-4706-73e0-bff3-91b9ff029fbe.png" width="600">

```Axis``` : QRコードを検出した際に表示する3軸 (x,y,z) のプレハブ
```QRCodesManager``` : QR Code を検出するためのスクリプト (2つ) がアタッチされたゲームオブジェクト

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/39f2b262-44ec-782c-9d11-a0f9f4b81c40.png" width="400">

| クラス名 | 概要 |
| :--- | :--- | 
| __QRCodesManager__ | QR Code のトラッキング状況などを管理するクラス<br/>__Auto Start QR Tracking__ チェックボックスで<br/> QRコードトラッキング 自動開始有無を指定できます。 |
| __QRCodesVisualizer__ | トラッキング済みの QR Code を可視化するためのクラス | 


##### 5. ビルドプラットフォームを UWP に切り替えます。

ショートカット : [ Ctrl + Shift + B ] で Build Settings を開きます。
Platform [ ```Universal Windows Platform``` ] を選択し、```Switch Platform``` ボタンを押下します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/890d0671-70db-95bf-3636-0f536caa4fcc.png" width="500">

##### ターゲットプラットフォーム : UWP でビルドを実行します。

※ Scenes In Build リスト内で対象シーンにチェックが入っていることを確認してください。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/17cb5394-e19a-009e-a3ff-60212e20cf5d.png" width="500">


##### Unity で Export したソリューションファイル ( .sln ) を Visual Studio 2019 で開きます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/3cfa7a80-e4eb-f278-01fa-01c6422453d3.png" width="500">

以上でサンプルを試す手順は完了です。


## ベストプラクティス
HoloLens 2 で QR Code を扱う際の注意点、ベストプラクティスの抄訳を以下まとめておきます。英語を読める方は公式ドキュメントをお読みになられることをお勧め致します。

### 1. QRコード周りのスペース / <font color="#c0c0c0">Quit zones around QR Codes</font>
QRコードを正しく読み取るためには、__QRコード4つの側面全てで余白が必要__となります。

__余白__ には印刷された他のコンテンツが含まれてはならず、__QRコード内の (一番小さい) 黒い四角4つ分の広さ、もしくはそれ以上の大きさ__が求められます。

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/0607ac57-e364-6450-b745-cc22a78c28dd.png" width="300">

> 「[QR Code.com](https://www.qrcode.com/en/howto/code.html)」 より画像を引用

( 詳しくはQRコードの仕様は [QR Codes.com](https://www.qrcode.com/en/howto/code.html) をご参照ください。)

---

### 2. 照明 と 背景 / <font color="#c0c0c0">Lighting and backdrop</font>

QRコードの検出の精度は、様々な照明や背景に影響を受けやすい性質があります。

__特に明るい照明の場所__ では、灰色の背景に黒色のQRコードを印刷するようにしてください。
それ以外の場合は、白色の背景に黒色のQRコードを印刷してください。

__QRコードを配置する環境が特に暗い場合、検出率が低い場合__ は、灰色の背景に黒色のQRコードを試してください。( QRコードの検出率が低い場合も同様 ) QRコードを配置する場所が比較的明るい場合は、通常の白背景に黒色のQRコードで問題無く動作するはずです。

---

### 3. QRコードのサイズ / <font color="#c0c0c0">Size of QR codes</font>

__Windows Mixed Reality (WMR) デバイス__ では、__1辺が5cm未満の QRコードを検出できません。__

QRコードの一辺の長さが 5cm ~ 10cm の場合、QRコードを検出するためにかなり近づく必要があります。またこの大きさのQRコードを認識するためには、より長い時間が必要となります。QRコードを検出する正確な時間は、QRコードのサイズだけでなく、QRコードと (デバイスを装着した) ユーザーの距離によっても異なります。QRコードに近づくと、QRコードサイズの問題を解消することができます。

---

### 4. QRコード読み取り時の距離と角度 / <font color="#c0c0c0">Distance and angular position from the QR code</font>
( QRコード認識に使用されている ) 環境認識カメラでは、特定のレベルの詳細しか検出することができません。QRコードの1辺の長さが10cm未満の非常に小さいQRコードの場合、QRコードにかなり近づく必要があります。<font color="red">__1辺が10cm ~ 25cm の QRコード (バージョン1) を使用した場合、最小検出距離は 15cm ~ 50cm の範囲となります。__</font>

QRコードのサイズと検出距離は直線的に増加していきます。

__QRコード検出は、±45度の範囲で動作が保証されています。__これはQRコードを検出するために必要となる適切な解像度を確保するためです。

---

### 5. QRコードを含むロゴ / <font color="#c0c0c0">QR codes with logos</font>
ロゴの中に含まれるQRコードは検出テストが行われておらず、<font color="red">__現在サポート対象外__</font> となっています。

---

### 6. QRコードデータの管理 / <font color="#c0c0c0">Managing QR code data</font>
Windows Mixed Reality (WMR) デバイスはドライバー内のシステムレベルでQRコードを認識します。デバイスを再起動した際には、検出したQRコードは無くなり、次回以降新しいオブジェクトとして認識されます。

アプリで特定のタイムスタンプより古いQRコードを無視する構成にすることを推奨します。
現在、この __QR API__ では__QRコード読取履歴の削除はサポートされていません。__

---

### 7. QRコードの配置場所 / <font color="#c0c0c0">QR code placement in a space</font>
QRコードを配置する場所と方法についての推奨事項は、公式ドキュメント「[Environment considerations for HoloLens](https://docs.microsoft.com/en-us/hololens/hololens-environment-considerations?WT.mc_id=MR-MVP-5003868)」をご覧ください。

---

# Reference
- [QR code tracking (英語)](https://docs.microsoft.com/en-us/windows/mixed-reality/qr-code-tracking?WT.mc_id=MR-MVP-5003868)

- [QRコードの追跡 (日本語)](https://docs.microsoft.com/ja-jp/windows/mixed-reality/qr-code-tracking?WT.mc_id=MR-MVP-5003868)