深層学習ツール"DeepLabCut-live"で動物をリアルタイムに追跡する

#はじめに#

[DeepLabCut-Live!](https://github.com/DeepLabCut/DeepLabCut-live-GUI)を使って、動物の動きをリアルタイムに追跡します。
[論文はこちら。](https://www.biorxiv.org/content/10.1101/2020.08.04.236422v1)
[動画はこちらから。](https://www.youtube.com/watch?v=KDSgddOqHtM)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284801/4b301f09-8b11-f302-77d8-c2822ba48314.png)
[BONSAIとの合わせ技の動画もどうぞ。](https://www.youtube.com/watch?v=0aachcS0CUY)

以前の記事はこちらです→
[深層学習で動物の身体をトラッキングするdeeplabcutをgoogle colaboratoryで走らせる](https://qiita.com/riichirohira/items/b92723278ba92fb42db9)

新しいDeepLabCutは以前のもとと比べて**格段に操作が簡単になっています**。
今回は前半でDeepLabCut2.2のGUIを用いた動画の解析によって深層学習モデルを作成する方法について、後半でDeepLabCut-liveを用いたリアルタイムな動作の追跡とその出力方法について解説します。これを用いると、**ハムスターがトリプルアクセルを飛べるかもしれません。**色々夢が広がります（ビジネスにもなりそうですね）。



#DeepLabCut2.2を使った深層学習モデルの作成#

今回使用するパソコンはドスパラで買ったガレリアシリーズのもので20万円程度です。

GPUは[RTX2070Super](https://www.amazon.co.jp/dp/B07V2DBVMH/)で、CPUは[AMD Ryzen9 3900X](https://www.amazon.co.jp/dp/B07SXMZLP9/)です。コスパ重視。GPUはどんどん値段が下がっていますので1年前にこのスペックだと30万はしたんじゃないかな。GPUは必須ではありませんがトレーニングにかかる時間を大幅に短縮できます。GPUを持っていない場合は訓練してモデルを得るまではGoogle Colabで行うことをお勧めします。Google Colabでモデルを作る方法→
[深層学習で動物の身体をトラッキングするdeeplabcutをgoogle colaboratoryで走らせる](https://qiita.com/riichirohira/items/b92723278ba92fb42db9)
ただし、リアルタイムに動物を追跡するときにもどうもGPUを使っているようで、GPUが使えないマシンだと無視できない程度の遅延*が生じました。したがってDeepLabCut-liveではある程度GPUにコストをかける必要があるようです。

※この点については情報が必要です。GPUなしで快適に追跡できたという方は教えていただけますと助かります。

さて、まずは環境構築です。[Anacondaをインストール](https://www.python.jp/install/anaconda/windows/install.html)します。

次に、[このページ](http://www.mousemotorlab.org/deeplabcut)の下の方に行くと下のような画面がありますので、**DOWNLOAD CONDA FILE FOR GPU**を選択します。ただし、GPUを使わない場合は**DOWNLOAD CONDA FILE FOR CPU**を選択します（以下はGPUを使用するときの説明をしますが、すべてGPUをCPUに書き直せばCPUで動きます）。ダウンロードできたら、ダウンロード先のフォルダ名をチェックしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284801/390f3bea-5477-c33b-0c33-768725a94874.png)


Anaconda Promtを起動し、上でチェックしたダウンロードしたフォルダ名にcdで移動して、次のように環境構築を行います。

```ruby:
conda env create -f DLC-GPU.yaml
```

これでDLCが実行できるGPU環境が整いました。環境をactivateします。

```ruby:
activate DLC-GPU
```
(LinuxまたはMacの場合はsource activate DLC-GPU）


そして、最後に

```ruby:
python -m deeplabcut
```

とすれば、下のようなGUIが立ち上がります。ここまで私の環境ではエラーがありませんでした。1年前はここまで来るのに1週間以上かかったような気がします。あの苦労は何だったのか。。。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284801/286d2692-d611-3495-1f01-7fcc186afc64.png)



GUIが起動した後は解説動画の通りやればすぐできます。
https://www.youtube.com/watch?v=JDsa8R5J0nQ
最短で結果が知りたい場合は、
まず、Manage Project で動画を指定し、
→ Extract frames
→ Label frames　　（デフォルトだと４つの体の部位をトレースします。）
→ Train network　（ここではinterationとSave iterationを100程度にしておくとよいです。こうしておくと、100単位の繰り返しでセーブされますので、適当なタイミングで強制終了できます。私の場合は5000回くらいで十分、2万回くらい繰り返すと申し分ない精度が出ます。）

終了したらもう一度、


```ruby:
activate DLC-GPU
python -m deeplabcut
```

でGUIを起動し、今度はManage ProjectでLoad existing projectから、Select config fileで、上で作ったyamlファイルを選択すれば、100単位で最後の繰り返し時に保存したネットワークのパラメータをロードしてくれます。
ラベル付きの動画を得るには、
→Analyze videos
→Create videos
で、いずれも元の動画を選択すればOKです。私の環境だとラベリングとトレーニングと結果の動画の出力全体で30分くらいで終わります。動画の大きさとGPUによるとは思いますが、非常に快適です。


動画のフォーマットが適切でないと、うまく画像を読み込んでくれない場合があります。動画の前処理の仕方やconfig.yamlでのラベル枚数とターゲット数の指定については、[以前の記事](https://qiita.com/riichirohira/items/b92723278ba92fb42db9#%E5%8B%95%E7%94%BB%E3%81%AE%E5%89%8D%E5%87%A6%E7%90%86)を参考にしてください。もう一度書いておくと、どんな動画でも構いませんが、コーデックの問題でうまく処理されない可能性があります。私は[XMedia Record](https://forest.watch.impress.co.jp/library/software/xmediarecode/)で映像だけのRaw video(AVI)に変換したのち[ImageJ](https://imagej.nih.gov/ij/download.html)で確認しながら必要なフレーム、場所をクロップし、AVI(JPEG)で保存しました。

こちらはケージの中を動き回るラットを追跡してみた動画です。ラベリング20枚でその後の修正も何もやっていませんが、ラットがどっちを向いているのかくらいは追跡できています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284801/cc61ee92-b022-fa20-4c8c-31637746deb0.png)
https://www.youtube.com/watch?v=ajltpstOkGg

さて、後半に行く前に**訓練したモデルをExport**しておきます。このモデルは、実際にリアルタイムな姿勢認識に用いるカメラを用いて取得したビデオデータを用いるとよいと思います。
上で作った環境をActivateして、ipythonを起動し、import deeplabcutしたらmodelをexportします。

```ruby:
activate DLC-GPU
ipython
import deeplabcut
deeplabcut.export_model('C:Users/…directory of yaml file/config.yaml')
```

で、モデルを出力しておきます。ちなみに、ここで¥（バックスラッシュ）を使ってディレクトリを区切るとUnicode errorが出ていました。/を使うとうまくいきました。

exported-modelのフォルダができますので、そこにpose_cfg.yamlや,XXXX.pbがあることを確認出来ればOKです。



#DeepLabCutをリアルタイムに実行する#

[DeepLabCut-live GUI](https://github.com/DeepLabCut/DeepLabCut-live-GUI)を用います。

まず、[Anaconda](https://www.python.jp/install/anaconda/windows/install.html)をインストールしてください。

環境構築は[ここ](https://github.com/DeepLabCut/DeepLabCut-live-GUI/blob/master/docs/install.md)を参考にして、以下のように行います。

GPUを用いる人は、

```ruby:
conda create -n dlc-live python=3.7 tensorflow-gpu==1.13.1
```
で、GPUを用いない人は、

```ruby:
conda create -n dlc-live python=3.7 tensorflow==1.13.1
```

でddlc-live環境を構築します。

構築出来たら、この環境をActivateします。

```ruby:
conda activate dlc-live
```

Activateできたら、Live-GUIをpip installします。

```ruby:
pip install deeplabcut-live-gui
```

※このpip installの前に、pip自体をUpgradeしておくほうが良いかもしれません。

```ruby:
python -m pip install --upgrade pip
```


ここまでエラーなしでインストールできたら、

```ruby:
dlclivegui
```

これを実行します。

ここで私の環境では3つのうちすべてエラーが出ました。エラーが出ない人はここは飛ばしてください。

Ubuntuのノートパソコン環境とデスクトップ環境では/HOME/Documents/DeepLabCut-live-GUIがありませんよ、というエラーが全く同じように発生しました。そのフォルダを作って再度実行するだけで問題は解決しました。

Wiondows10ではモジュールが見つからないというエラーが出て、いろいろ調べた結果、次のように対応するとうまくいくことがわかりました。

[AnacondaでTISカメラをPythonで動作させる方法](https://www.argocorp.com/UVC_camera/Windows_Python_Anaconda_operating.html)を参考にします。ただし、Pythonのバージョンの問題で少し修正が必要でしたのでここに記しておきます。

まず、[ここ](https://www.argocorp.com/software/DL/tis/index.html#tab4
)の「4-1）IC Imaging Control」をインストールします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284801/75a211c2-c8bf-1dc4-27a2-b0a423486c9a.png)

次に、Githubの[ここ](https://github.com/TheImagingSource/IC-Imaging-Control-Samples
)から、ダウンロードします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284801/e362c2f9-b115-dba8-e36b-241514818fa0.png)

次に、tisgrabber_windos.pyというファイルを見つけてエディタで開きます。これはC:\Users\Argo\Downloads\IC-Imaging-Control-Samples-master\IC-Imaging-Control-Samples-master\Python\Open Camera, Grab Image to OpenCV　相当の場所に見つかると思います。

そこで次の赤のようにos.add_dll_directoryで、Githubからダウンロードしたパスを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284801/a5363f20-b7d0-327f-57ac-3685f07b63a5.png)

しかし、このos.add_dll_directoryは現在使用しているpythonのバージョン3.7では使用できないようです。そこで、
os.environ['PATH'] = 'C:\\Users\\Argo\\Downloads\\IC-Imaging-Control-Samples-master\\IC-Imaging-Control-Samples-master\\Python\\Open Camera, Grab Image to OpenCV' + os.pathsep + os.environ['PATH']

とします。ここまで修正したら、再度起動します。

```ruby:
dlclivegui
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284801/ce1ca496-6983-ac74-bd74-86090b76a730.png)


このように立ち上がればOKです。


今回使うカメラは[このUSBカメラ](https://www.amazon.co.jp/dp/B07R55B6FF)です。カラーで5-50mmの可変焦点レンズです。広角に見たい場合は2.8-12mmのレンズを使う方が良いです。今回は最後に説明するように、同じカメラを２つ使っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284801/fdde1ab4-aaf5-3dc0-2cc0-70aa7804fdb7.png)



#DeepLabCut Live GUIの設定#


Config/Create New Configで、適当に名前を付けます。

Camera→Add Cameraとして、Init Camを押すと、次の画面が出てきますので、Nameに適当に名前をいれて、Add Cameraします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284801/61da98b9-27b8-4a3b-7068-8748a12601aa.png)

次にEdit Camera Settingを押すと、次のような画面が現れますので、deviceに0を選択し、Updateしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284801/25c56751-df8c-f0ad-e4b5-c0039c63833e.png)

ここまで来たらInit Camを押して、カメラの画像が見えればOKです。画面が確認出来たらClose Camでいったんカメラを閉じます。

さて次はいよいよ上で保存しておいたモデルをインポートします。Edit DLC Settingを押すとDLC Setting画面が現れますので、


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284801/772388d2-d4ea-9f6f-cfa9-0a5e1ae8eba2.png)


ここで、**Nameを適当につけてから**、Model Path/Browseから、exported-modelの**下の**、pose_cfg.yamlや,XXXX.pbがあるフォルダ名を指定します。そのほかはデフォルト設定でOKだと思いますのでUpdateボタンを押します。


Display DLC Keypointsを押したら、あとはInit CamとInit DLCを押せばリアルタイムの動作追跡が開始します。自分の顔でやってみましたが、恥ずかしいので動画は載せられません。。。

RTX2070Superだと、遅延はほとんど感じません。手元のラップトップのCPUモードだと1秒以上遅延がありました。CPUモードでリアルタイム性を確保したい場合にはCropエリアやResizeで画像処理の負担を低減する工夫が必要のようです。




#リアルタイム追跡の結果を出力する#


最後に、リアルタイムに追跡したXY座標をつかって、他の機器を制御する方法についてです。BonsaiやAutopilotを使ったり、teensyで出力したりするオプションがあるようですが、

**追跡結果がせっかくディスプレイにうつってるんだから、そのままそれを使えばいいんじゃないでしょうか。**

私は2つ目のカメラでディスプレイを撮影し、[LabVIEW](https://www.ni.com/ja-jp/shop/labview.html)上でマーカー位置を色と形の違いを使って特定し、その値をLabVIEW上で使って他の機器の計測・制御と統合しています。同じPCで走らせても特に問題はなく、遅延は0.1-0.2秒程度しかかかりません。異なる計測器をつなぎたいときにこういう方法を使うのはちゃんとしたエンジニアは極度に嫌うわけですが、ほとんどの計測制御機器は人間の目に見える出力をディスプレイ上に出せるようになっているので、それをカメラとパターン認識を介して繋ぐのは汎用性が高く、多くの手間を省くことができます。実際[このブレーンマシーンインターフェイスの論文](https://www.nature.com/articles/ncomms6551)でも使われています。200ミリ秒程度の遅延が気にならない系ならこれで良いのでお勧めです。

冒頭に、これを使えばハムスターにトリプルアクセルを飛んでもらえるかもしれないというようなことを書きました。[ラットの動画](https://www.youtube.com/watch?v=ajltpstOkGg)でわかるように、ハムスターがクルクル回ったときにそれを検出することはできそうですので、そのとき餌を与えるのを自動化すれば、お腹が空いたらクルクル回るようになるのではないでしょうか。ジャンプして3回転半回って着地するのをリアルタイムに検出するにはかなり高速なカメラを配置する必要がありますが、不可能ではないでしょう。あとはハムスターがそういった身体能力を持っているかどうかですが、[ネズミたちはそれくらいはできそうな気がします](https://www.youtube.com/watch?v=z4xZpm5n214)。