FastMOTをDockerで動かしてみた

#FastMOTとは
　MOTとはMultiObjectTrackingの略であり、物体の「検出」と「追跡」を同時に行うタスクのことをいいます。このタスクの手法の1つにYukai Yang 氏(Alexis)がGitHubで公開されている「FastMOT」というものがあります。FastMOTはDockerでの動作を推奨してるらしいので、Docker環境を作成して動かしてみました。

![dense_demo (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2379984/497ed4e9-4fb3-7307-a69c-d7baf076cc4a.gif)
↑引用　https://github.com/GeekAlexis/FastMOT

#環境
Ubuntu 20.04
RTX3070
NvidiaDriver 495.44


#目次
1、NvidiaDriverのインストール
2、Docker&NVIDIA Container Toolkitのインストール
3、FastMOTのインストール
4、実行
5、まとめ
#1、　NVIDIA Driverのインストール
　FastMOTを動かすためにはまず前提条件として、Ubuntu18.04ではNVIDIA Driver versionが450以上、Ubuntu20.04では465.19.01以上である必要があるとのことなので現時点（2021/12/10）での最新版である495.44をインストールしました。

まず以下コマンドで推奨ドライバを確認します

```
$ ubuntu-drivers devices
```


以下コマンドでPPAパッケージのリストを追加します。

```
$ sudo add-apt-repository ppa:graphics-drivers/ppa
$ sudo apt update
```

nvidia-driver-495のインストール

```
$ sudo apt install nvidia-driver-495
```

再起動

```
$ sudo reboot
```

ターミナルを開いて以下のコマンドを入力

```
$ nvidia-smi
```
![Screenshot from 2021-12-12 02-41-43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2379984/5fd234d0-f1ca-a65a-fce8-a9b87524d312.png)

↑　Driver Versionのところに指定したバージョンがインストールされていればOK

#2、　Docker&NVIDIA Container Toolkitのインストール

　@karaage0703 さんの記事　[DockerでのディープラーニングGPU学習環境構築方法](https://qiita.com/karaage0703/items/e79a8ad2f57abc6872aa)を見てインストールさせていただきました。ありがとうございます、、、m(_ _;)m
この記事の「DockerとNVIDIA Container Toolkit(NVIDIA Docker）のインストール」のところを実行していきました。スクリプト化されていたので正規のインストール方法よりも簡単でした。

#３、　FastMOTのインストール
DockerでGPUを認識できたらいよいよFastMOTをインストールしていきます。
今回RTX3000番台のGPUを用いているので、正規のインストールにひと手間加えての実装となります。

まずFastMOTの[GitHub](https://github.com/GeekAlexis/FastMOT)からコードをダウンロードします。

ダウンロードしたZIPファイルを適当な場所に保存して解凍します。私は一度フォルダを作ってその中で解凍しました。

そしたらターミナルを開いて解凍したファイルのディレクトリまで移動します。
Dockerfileがあることを確認してください。

```
$ cd  /(保存先までのディレクトリ)/FastMOT-master
```
Dockerfileがあることが確認できたらDockerイメージをビルドしていきます。
、、、、、の前にやることが２つあります。

１つめ
FastMOTではTensorRTを用いて高速化しているのですが、Ubuntu20.04の場合デフォルトのイメージバージョン(20.09)のままではビルドできないため、バージョンを21.05に上げます。

まずDockerfileを開いて最初の1行目に書いてある

```
ARG TRT_IMAGE_VERSION=20.09
```
を

```
ARG TRT_IMAGE_VERSION=21.05
```

に書き換えます。

２つめ
FastMOTの実行中の動画を確認するために以下のコマンドを事前に実行しておきます。

```
$ xhost local:root
```
このコマンドを打つことで、Dockerコンテナの中でGUIアプリケーションを起動させることができます。

それができたら以下コマンドでDockerイメージをビルドします。

```
$ sudo docker build --build-arg TRT_IMAGE_VERSION=21.05 --build-arg CUPY_NVCC_GENERATE_CODE="arch=compute_86,code=sm_86" -t fastmot:latest .
```
ここではオプションとして「TensorRTのバージョンの指定」＋「Cupyのビルドをする際にGPUを使う」を指定しています。

ビルドが終わるまで15分くらいかかる場合があるので根気強く待ちましょう。特にCupyのビルドに時間がかかります。

それがおわったら以下コマンドでコンテナを起動します。

```
$ docker run --gpus all --rm -it -v $(pwd):/usr/src/app/FastMOT -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=unix$DISPLAY -e TZ=$(cat /etc/timezone) fastmot:latest
```

以下のようにコンテナを起動できたら成功です。
![Screenshot from 2021-12-12 03-57-39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2379984/1313fbc7-20e9-d9ea-2b6b-8797df07c6c0.png)

ここからは起動したコンテナ内で以下コマンドを実行します。まずデモモデルをダウンロードします。

```
$ ./scripts/download_models.sh
```

次にYOLOv4のTensorRTプラグインをビルドします。以下コマンドでディレクトリを移動して

```
$ cd fastmot/plugins
```
makeコマンドをします

```
$ make
```
makeできたらもとのディレクトリに戻ります。

```
$ cd ../../
```
準備完了！！

いざ実行してみます。

#４、　実行

実行する際は以下のコマンドでオプションを指定して実行します。

```
$ python3 app.py --input-uri ... --mot
```
オプションは以下の通り

・連続した画像　　　: --input-uri %06d.jpg
・ビデオファイル　　: --input-uri file.mp4
・USBウェブカメラ　: --input-uri /dev/video0
・MIPICSIカメラ　　:--input-uri csi://0
・RTSPストリーム　 : --input-uri rtsp://(user):(password)@(ip):(port)/(path)
・HTTPストリーム　 : --input-uri rtsp://(user):(password)@(ip):(port)/(path)

ただ私の環境では連続した画像とビデオファイルしか試したことがないので残り3つは実行できるかわかりません。

連続した画像は[MOTchallenge](https://motchallenge.net/)のサイトからダウンロードできます。

ダウンロードしたファイルを見てみると000000.jpg,000001.jpg・・・・のように6桁の0埋め数字の名前の画像が得られると思います。

私はこの写真をimgというフォルダの中に保存したため以下のようなコマンドで実行しました。このフォルダはapp.pyと同じディレクトリに入れてあります。

```
$ python3 app.py --input-uri img/%06d.jpg --mot
```

またこのコマンドの後ろに 　--show　をつけることで実行中に物体検出と追跡ができているかを確認することができます。
コマンドだとこんな感じ

```
$ python3 app.py --input-uri img/%06d.jpg --mot --show
```

実行した動画を保存したいなーと思ったら 　--output-uri　で出力を保存することができます。
私が試した際MP4形式でしか保存することしかできなかったため、以下のようなコマンドになりました。

```
$ python3 app.py --input-uri img/%06d.jpg --mot --output-uri result.mp4
```

これでresult.mp4という名前で保存することができます。

またフレーム枚の物体の位置情報をテキストファイルで出力する際は 　--txt　を持ちいます。

```
$ python3 app.py --input-uri img/%06d.jpg --mot --txt result.txt
```

一通りの出力を列挙したので実際に実行した動画（GIF）を載せます。

![Videotogif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2379984/1d43e955-8501-a90e-94ef-f1441f6bd645.gif)

人と人が重なる（オクルージョン）ときに追跡がうまくいかないときがありますが、高速にこれだけの精度で検出＆追跡できているのでヨシ！

#５、　まとめ
　今回Multi-Object Trackingの手法の１つとしてFastMOTを実装してみました。初投稿＆Linux初心者なので誤字脱字や間違ったコードを書いてしまっているかもしれません。（笑）
時間があれば検出モデルを変更した記事も書こうかなと思います。もしなにか間違った点などありましたらご指摘いただけると幸いです。