ZED2iとUnityでオブジェクト検出を行う（ZEDCustomObjDetectionを使う）

## 記事を書いたきっかけ
ZED2iのUnitySampleでは元から人は検出されるようになってますが、人以外を検出しようとすると若干苦戦したので、同じ境遇の方との共有も兼ねて記事にさせていただきました。

## ターゲット
+ Unityが使える環境にある人
+ ZED2iセンサーがある人
+ ZEDセンサーで物体検出がしたい人
Scripts書き換えはありますが、あんまり考えなくても大丈夫です。

## 使用したもの
ZED SDK ver:4.0
現時点で4.1の物が出ているので、そちらをインストールすることをお勧めします。
4.1だと下記に記入した問題とかも治ってるかもしれません。

Unityのサンプルも必要なのでそちらもインストールを行ってください。

SDKとサンプルをインストールしたら、Unityを起動して『CustomObjectDetection』というSceneを探して起動してください。（多分ここにあるはず）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3723719/16a72cca-6e5e-7479-afde-0a10d062a525.png)

## Unity for OpenCVが必要
ZED2iとUnityが揃ったのでいざ検出！…とはなりません。
画像検出にはOpenCVが別途必要になってきます。（有料）
UnityAssetsからインストールしてください。
https://assetstore.unity.com/packages/tools/integration/opencv-for-unity-21088

## 読み込み準備
OpenCVもインストールしました！よし起動！…ともなりません。
初期段階だとOpenCVで使用する機械学習のラベルが読み込まれないのです。
事前準備をしなければいけません。下記に従って構築して下さい。

#### 1\. ZED_Rig_MonoのCompornentに『ZEDToOpenCVRetriever』を追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3723719/1be204d2-4ceb-e76d-2956-ec0c3dac8e56.png)

Scene分けしてるなら最初からつけてくださいよ！って感じですが、追加を忘れずに行ってください。

#### 2\.3DObjectVisualizerのCompornentにある『ZEDCustomObjDetection』のModel,Config,Classesのパスを確認する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3723719/66bbbd85-32c7-d907-4a9e-19ae970f1cdb.png)

初期で書かれているパスは

Model ```Assets/OpenCVForUnity/StreamingAssets/dnn/yolov4-tiny.weights```
Config ```Assets/OpenCVForUnity/StreamingAssets/dnn/yolov4-tiny.cfg```
Classes ```Assets/OpenCVForUnity/StreamingAssets/dnn/coco.names```

になってますが、筆者の環境だとこれらの入ってるパスが全て

Model ```Assets/StreamingAssets/OpenCVForUnity/dnn/yolov4-tiny.weights```
Config ```Assets/StreamingAssets/OpenCVForUnity/dnn/yolov4-tiny.cfg```
Classes ```Assets/StreamingAssets/OpenCVForUnity/dnn/coco.names```

になっていて読み込みエラーが起こったので、パス名を上記に書き換える必要がありました。（多分OpenCVがどこかの更新で入れる場所を変えたのかも）

一度書かれているパス名が正しいか、確認しておくと良いでしょう。

#### 3\.『ZEDCustomObjDetection』のClassesFilterに読み込ませたいラベルを追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3723719/4e517d26-b8ac-8bdf-90b0-3112f988f529.png)

筆者はperson(人)とcup（コップ）を追加しました。

:::note info
読み込みできるラベル集は『coco.names』に一覧が乗ってます。UnityEditorのProjectで『coco』と検索すれば発見できると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3723719/c827e3d5-db45-0e57-8360-446823e34bb2.png)
:::

#### 4\. 『ZEDCustomObjDetection』のImageRetrieverにZED_Rig_Monoをアタッチする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3723719/fc301c03-dc2b-d6b6-8801-3374f7b898ee.png)

１で付けた『ZEDToOpenCVRetriver』を読み込ませるためにアタッチします。

#### 5\.ZED_Rig_Monoにある『ZEDManager』に１行加える
ここまで来たらPlayを押せばUnityサンプルの人体検出みたいにオブジェクトに対してなんか出てくるはず！…と思いきや何も出てきません。ver4.1だと修正されているかもしれませんが、カメラが表示されるだけで何も反応しない現象が起きました。

調べてみると公式バグのようで、対処法を解答されていました。そちらに従ってやってみます。

https://community.stereolabs.com/t/zed-customdetection-cs-not-working-with-opencvforunity-plugin/4829/6

:::note info
フォーマットを見てみると（筆者は遭遇しなかったけど）『ZEDManager』にあるStartObjectDetectionが起動してなかったりすることもあるみたいなので、この記事を見てもうまくいかない場合は上記の解答を参考にしてみてください。
:::

#### 対処方法
EditScriptをクリック（直接探して起動するのでもOK）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3723719/83c76f46-2329-d176-5028-571a9a973a19.png)

この行を探す（3068行目ぐらい）
```od_param.instanceModuleID = objectDetectionInstanceID;```

この行の直前に一行追加
```objectDetectionImageSyncMode = true;```

下記の図になると思います。これでOKです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3723719/d5476d24-98d0-7d44-41f1-7a9f965c459a.png)

#### 6\.起動確認
ここまで来たらあとは起動するだけです。
好きなものを好きなだけ読み込みまくってください。※起動に時間かかります

## 結論
確かにセンサーとして高性能なZED2iですが、画像取得してオブジェクト検出するだけに使用するには出費が痛いし、今時なら無料でお手軽だしサンプルもあるBarracuda使った方がいい気もしてきます。

しかし、高度な表現ができるのも事実。深度センサーを同時並行などで使用するのであれば、ZED2iでやった方が作業効率は上がりそうです。使用用途によって使い分けるのが吉でしょう。