クリスマスイブイブに AzureKinect を Python で動かす。

3D Sensor Advent Calendar 2019の23日目の記事です。

## 概要
3D センサー歴 3 か月程度の初心者ですが、AzureKinect 手元にあるので、頑張ってみようかと思った Advent Calendar 第四弾です。
週一記事、Qiitaを書いて、何とかここまで来ました。
今回は、目標として、初心者レベルで Azure Kinect Sensor SDK 使って、Python で接続、動作するところまで試してみたいと思います。

## 環境
-   Windows10 Pro
- 　Azure Kinect Sensor SDK 1.2.0
- （Python 3.7.4）
- （Open3D 0.8.0）

環境としては、上記は Windows10 と Azure Kinect Sensor SDK 1.2.0がインストールされている状態で開始します。
(1.3.0 ではないので注意！)

## まずは Windows に Python,Open3Dをインストール
まずは、Pythonをインストールします。
やり方は色々ありますが、初心者向けに Windows でインストールするなら以下があるでしょうか

1. Python をダウンロードしインストール
2. Anaconda (機械学習やデータサイエンスやらを色々入れられるパッケージ)をダウンロードしインストール
3. Miniconda（Anaconda の最小インストール版）をダウンロードしインストール

どれもインストールは簡単ですが、とりあえず Miniconda の最新版（現時点でMiniconda3 4.7.12）で入れます。
![コメント 2019-12-20 201529.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389500/27e3d0f4-fb6a-12c9-b768-c991b18a48c8.png)

環境変数に設定するのはおススメされてないので、下のレジストリに入れる設定にチェックしてインストール
![コメント 2019-12-20 201708.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389500/8a16f1ec-0f6e-3f5d-dd33-957b7e66c3d4.png)

その次に、Azure KinectをPythonで使用するには、 Open3Dというframeworkをインストールするのが簡単そうでした。

```
Open3Dは、3Dデータを扱うソフトウェアの開発をサポートするオープンソースライブラリです。
Open3DはC++とPythonのフロントエンドを提供し、厳選されたデータ構造とアルゴリズムを
どちらの環境でも利用できます。
```
とのことです。
実はこのライブラリが最新バージョンの 0.8.0 で、「AzureKinect」に対応しています。
こちらを使ったら、作業ができます。

### Open3Dインストール

Open3D 0.8.0 は以下のようにPython2.7,3.5,3.6に対応していますが、最新の3.7.4でも動作しました。（Mac でも Open3D は動きますが、残念ながら AzureKinect のモジュールはWindowとUbuntuのみのようです、残念！）
とりあえず、以下のコマンドを使用すると一発で入ると思います。

```
(base) D:\>conda install -c open3d-admin open3d
```


- Open3D のサンプルを実行

とりあえず、Open3D が正しく認識されているかを以下のコマンドで確認できます

```
python -c "import open3d"
```

上記は何も返ってきませんが、エラーにならなければ成功です。

次に、sampleモジュールを実行してみましょう。これが問題なければ、Open3Dのインストールは成功です。
sampleモジュールは、以下のgithub からダウンロードしてください。
https://github.com/intel-isl/Open3D

ダウンロードは、D直下に配置したとして作業します。
sample モジュールを実行しようと思ったら、matplotlibというツールが必要なようです。これは、conda install コマンドですぐに入れられます。

```
(base) D:\>cd D:\Open3D-master\examples\Python\Basic

(base) D:\Open3D-master\examples\Python\Basic>conda install matplotlib

(base) D:\Open3D-master\examples\Python\Basic>python rgbd_redwood.py
```
うまくいけば、以下のような画面になります。
![コメント 2019-12-20 212336.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389500/03e257cc-8348-30cf-3e52-1330387aafd7.png)

## AzureKinect のsampleモジュールを実行

さて、次に本命の AzureKinect のモジュールを実行してみましょう！
実行するサンプルは以下になります
azure_kinect_viewer.py

```
(base) D:\Open3D-master>python examples/Python/ReconstructionSystem/sensors/azure_kinect_viewer.py --align_depth_to_color

```

ただ、ここで注意点があります。
・SDK1.2.0 というprogram内のフォルダ名を直接参照しているらしく、SDK1.3.0だと動きません（1.3.0というフォルダ名にリネームすればできるかもしれませんが、その場合環境変数なども変更が必要です）
・私の環境では、以下のようなエラーが出ました。

```
  File "examples/Python/ReconstructionSystem/sensors/azure_kinect_viewer.py", line 72, in <module>
    v.run()
  File "examples/Python/ReconstructionSystem/sensors/azure_kinect_viewer.py", line 36, in run
    vis.update_geometry()
TypeError: update_geometry(): incompatible function arguments. The following argument types are supported:
    1. (self: open3d.open3d.visualization.Visualizer, arg0: open3d.open3d.geometry.Geometry) -> bool

Invoked with: VisualizerWithKeyCallback with name viewer
```

調べてもエラーが出なそうな部分なのでよく分からず、とりあえず
update_geometry() が while で都度更新する際に何か変なパラメータを渡してるのではないか・・・くらいしか推測できません。
とりあえず、36行目の
vis.update_geometry()
を削除することで、画面の更新はできなくなりますが動作だけは確認できました。

```python:azure_kinect_viewer.py抜粋
        vis_geometry_added = False
        while not self.flag_exit:
            rgbd = self.sensor.capture_frame(self.align_depth_to_color)
            if rgbd is None:
                continue

            if not vis_geometry_added:
                vis.add_geometry(rgbd)
                vis_geometry_added = True

            vis.update_geometry() <== この部分を削除
            vis.poll_events()
            vis.update_renderer()

```

すると、静止画ではありますが、AzureKinectの動作が確認できました。

![コメント 2019-12-21 181534.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389500/4b71ba8c-3614-22ea-2898-071f77f4a54e.png)

実際には左にカラー写真もついているのですが、部屋が汚かったのでDepthのみ・・・
ちなみに、上記の絵は Depth 画像にカメラの補正をかけた状態の絵となります。
第三回でも紹介しましたが、AzureKinect は内部カメラパラメータで補正を既にかける関数を保持しており補正後の状態を取得することができます。補正前だと、こんな感じの絵が取得できます。
![コメント 2019-12-21 181554.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389500/1826333f-23e3-6c72-2833-5b87fb5c17fb.png)

補正をかけた状態でないと、正しい3次元での位置合わせができないのでAzureKinectで簡単にできるのは助かります。

・・・ところで、このOpen3D、すごく楽です。特に描画処理が、たった三行（コメント含めて四行）しかないので、全体のスクリプトが非常に少ないですね。下のこの部分だけですごく簡単です。

```python:
        vis = o3d.visualization.VisualizerWithKeyCallback()
        vis.register_key_callback(glfw_key_escape, self.escape_callback)
        vis.create_window('viewer', 1920, 540)
        print("Sensor initialized. Press [ESC] to exit.")

```


何とかPythonで表示することだけはできました・・・。


## 振り返り

- 今回は、Pythonだけではなく、Macでも動いてくれることを期待したのですが、そうはうまくいきませんでした。
- Open3D、将来性がありそうなライブラリです。ただ、非常に速いスピードで成長しているからか、結構単純な不具合みたいなものもある気がします。（ドキュメントに未実装の記述があったりするようで）楽しみではあるので、使っていれば段々改善されるのではないかと。
- なんとなく、Pythonで扱うのは簡単そうに見えますが、AzureKinectの描画処理は重く、センサー部分の非同期なハンドリングもてこずりそうで、Pythonで制御しきれるのかが漠然とした不安が。でも、Pythonとつなぐのは機械学習などにもつなげられそうで、良さそうです。


ということで、今回も初歩の初歩で終わってしまいました。
四回の記事全部、初心者オブ初心者、みたいな状態からから抜けられませんでした。
でも、これに懲りず、3Dセンサーの学びを深めるような活動をこれからもしていきたいと思います。
この場を提供していただいたゆるふわUNAさん、又、読んでいただいた方、応援していただいた方に感謝の意を表したいと思います。
どうもありがとうございました。



明日24日のクリスマス・イブは pisa-kun さんの「RealSense l515プレオーダー記念 Lidarについてまとめてみる」です。
RealSense L515、良さそうですよね。日本で売り出した際には自分も手に入れてる気がします・・・。
来年も、xR、および 3DSensor 関連の技術で頑張っていきたいと思います。