Azure Kinect SDK (v1.1.0) を使ってみた (導入 ～ Unity で使う)

## はじめに

TMCN さん主催の [Azure Kinect DK触ってみる会](https://tmcn.connpass.com/event/140547/) に参加して Azure Kinect DK の実機に触ることができました。

会では実際に SDK を使って何か自作のコードを動かすことを目標にしていましたが、一応何か動かすことまではできたので、忘れないうちに記事にまとめました。当面さわる機会もなさそうですし・・・

## 実施環境

下記環境で試しました

* Windows 10 (1903)
* Visual Studio 2019 (16.2.0)
* Unity 2019.1.11f1
* Azure Kinect SDK v1.1.0

今回は Camera のみで Body Tracking は試していません。

## 準備

Azure Kinect SDK のバイナリをダウンロード、インストールします。  

* [Azure Kinect SDK 1.1.0](https://www.microsoft.com/en-us/download/details.aspx?id=58386)

次に SDK のソースコードを GitHub から取得します。

* [microsoft/Azure-Kinect-Sensor-SDK](https://github.com/microsoft/Azure-Kinect-Sensor-SDK)

次項でソースコードから SDK のビルドを行います。だったら SDK のバイナリをインストールする必要ないのでは？と思ってしまうところですが、インストーラーには非オープンソースの必須 .dll が含まれているため、インストールはしておく必要があります。もちろんインストーラーで入れれば各種ツール類が入りますので、これらでまず動作確認をするべきでしょう。

## SDK をビルドする

いきなり Unity でやる、というのであれば本項は飛ばせますが、 Windows Forms / WPF 版のサンプルを試しておきたいところなので、まず SDK のビルドをお勧めします。

### C SDK をビルドする

C# プロジェクト (src\csharp\K4a.sln) のビルドをする際、 C ネイティブ側のビルド済バイナリを要求されます。おそらくインストーラーのバイナリを適切に配置しても解消すると思いますが、適切な配置がよくわからなかったのでソースからビルドします。

C SDK は CMake でのビルドになっています。が、 Windows の場合は Visual Studio の CMake サポート機能を使う事で別途 CMake をインストールしなくても Visual Studio のみでビルドする事が可能です。

(Visual Studio Installer の "個別コンポーネント - コンパイラ、ビルドツール、およびランタイム" の中)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211064/0384a3d0-bdba-57fd-81ee-e419b8d723fd.png)


1. Visual Studio 2019 を起動し、 "ローカルフォルダーを開く" を選択する  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211064/23dac601-5888-d85a-f10c-9e88b49df19d.png)
2. "Azure Kinect Sensor SDK" をチェックアウトしたフォルダーを選択します
3. 少し待ちます
4. 構成の種類が選べるようになったら "Win-x64-Release-Ninja" を選択します  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211064/64fad501-5149-bb21-b5da-2f69a22161b4.png)
5. ビルドします
6. インストールした Azure Kinect SDK から "depthengine_1_0.dll" (C:\Program Files\Azure Kinect SDK v1.1.0\sdk\windows-desktop\amd64\release\bin\depthengine_1_0.dll) を "build\Win-x64-Release-Ninja\bin" にコピーします

"Win-x64-Release-Ninja" は C# Wrapper で参照している構成なのでここではビルド対象にしていますが、他の構成は必要に応じて適宜ビルドしてください。

### C# Wrapper をビルドする

前項 "C++ SDK をビルドする" が完了していれば "src\csharp\K4a.sln" を開いてビルドすることができます。エラーは出ないはずです。

C# プロジェクトはコンパイル時にネイティブの DLL を参照することは原則ないので C++ ビルドがなくてもある程度はビルド通ります。が、それ以外の追加作業含めてビルドを通すようにするには C++ ビルドは必須です。

## Unity で使う

Unity では SDK に含まれている C# Wrapper をそのまま Unity で使う事ができます。

今回、下記のような配置にしてみました。

* Assets/K4A/Scripts ← SDK "src\csharp" 下の *.cs を丸ごとコピー
* Assets/K4A/Plugins/x86_64 ← k4a.dll と depthengine_1_0.dll をコピー

※ (2019/7/31 追記) ビルド済 DLL を使用する場合は GitHub のソースコード側とバージョンを合わせるように注意してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211064/586b3cca-2842-8356-bf52-5e450bb9ac24.png)

コードを書きます。

```csharp
using UnityEngine;
using KinectSensor = Microsoft.Azure.Kinect.Sensor;

public class KinectCapture : MonoBehaviour
{
    private KinectSensor.Device _device = null;

    private void Awake()
    {
        _device = KinectSensor.Device.Open();
        _device.StartCameras(new KinectSensor.DeviceConfiguration
        {
            ColorFormat = KinectSensor.ImageFormat.ColorBGRA32,
            ColorResolution = KinectSensor.ColorResolution.r720p,
            DepthMode = KinectSensor.DepthMode.NFOV_2x2Binned,
            SynchronizedImagesOnly = true,
        });
    }
}
```


実行をしてみると Device は取得できるのですが、 Device.StartCameras で失敗します。

これ、原因は "depthengine_1_0.dll がロードできない" ことでした。 depthengine_1_0.dll は k4a.dll からロードするので Unity のネイティブプラグインの DLL パスのルールではなく Windows のルールに従います。つまり Unity のルールに従った k4a.dll と同じ位置に配置してもロードされないわけです (ので depthengine_1_0.dll を置く意味はありませんでした) 。

面倒だったので、インストールした SDK のバイナリのフォルダ ("C:\Program Files\Azure Kinect SDK v1.1.0\sdk\windows-desktop\amd64\release\bin") にパスを通す事で解決しました。

**(2019/8/10 追記)
手元に実機がないので確認できていませんが depthengine のパス問題は GitHub 上では対策がされているようです。**

* [Add the current module path to the search path #545](https://github.com/microsoft/Azure-Kinect-Sensor-SDK/pull/545)


あとは C# サンプルを参考にコードを書けば Unity 上でも動作させることができました。 API の数自体は少ないし、わかりやすいのでとりあえず動かすだけならそんなに難しくはなかったのですが、適切に動かすにはいろいろコツが必要なようです (というお話を伺った) 。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">がんばったけどDepthの扱いがうまくいきませんでした・・・ <a href="https://twitter.com/hashtag/TMCN?src=hash&amp;ref_src=twsrc%5Etfw">#TMCN</a> <a href="https://twitter.com/hashtag/AzureKinect?src=hash&amp;ref_src=twsrc%5Etfw">#AzureKinect</a> <a href="https://t.co/P2LEhYqGCS">pic.twitter.com/P2LEhYqGCS</a></p>&mdash; TAN-Y(たに) (@TANY_FMPMD) <a href="https://twitter.com/TANY_FMPMD/status/1155024524636594176?ref_src=twsrc%5Etfw">July 27, 2019</a></blockquote> 

実装的にはカメラの Color と Depth をそれぞれ RenderTexture の ARGB32 と R16 に書き出し、 Shader 側でごにょごにょしてます。

Depth は Vertex Shader で値を見て Z 方向に動かすようにしているのですが、そもそも Kinect から取得する際の扱いが適切ではなかったようでうまく反映できませんでした (ペットボトルの形状は取れているようではあったのですが) 。この辺はもう少し時間があれば対処できたと思います。

## おわりに

会で触れる時間は限られていましたが、事前準備を多少しておいたおかげで何もできずに終了、ということにはならずに済みました。

Unity でやってみた感想としては、一応 C# Wrapper を使えば基本的に Azure Kinect の機能を問題なく使えそうですが、 C# Wrapper が機能的には非常に低レベルな "C API ほぼそのまま" な定義なのにも関わらず、実装自体がよくわからない冗長な実装をしているように見えてあんまりよろしくない感じがしました。

ホロラボさんが独自に C# Wrapper を開発されているようですが、こちらの方がシンプルで無駄のない実装になっているようですので C# で開発をされる場合はこちらをベースにした方がよさそうです。

* [HoloLabInc/AzureKinectSharp](https://github.com/HoloLabInc/AzureKinectSharp)

個人的には Unity で扱う場合、例えばカメラの映像をテクスチャに反映するといったところで実質ネイティブブラグイン不可避なので、最初から C# Wrapper は使わずに Kinect に対する処理はネイティブで書くようにしそうです。あるいはインプロセス実行にこだわらず、 Kinect 自体は別プロセスで実行するのも考えられそうです。

なんにせよ実機がないと何もできないので早いところ日本で普通に入手できるようになってほしいところです・・・