Jetson NanoにDeepStream SDK Python Bindingを入れて物体検出をしてみる

# 概要
[![DeepStream](http://img.youtube.com/vi/Y43W04sMK7I/0.jpg)](http://www.youtube.com/watch?v=Y43W04sMK7I)

DeepStream SDKを使うことでJetson Nanoでも高速な推論が可能となった(YOLOv3-TInyだと25FPS程度出る模様)。
今回はDeepStream SDKを使ってPython上から推論結果を取得するプログラムを作ってみる。
ちなみにDeepStream SDKについては[マクニカに詳しい記事](https://www.macnica.co.jp/business/semiconductor/articles/nvidia/134117/)が載っているので参考にすると良い

# 環境
端末：Jetson Nano
イメージ： JetPack 4.2.2.
DeepStream SDK：v4.0.2 
Python Binding：v0.5α
※ちなみにJetcardだとDeepstream SDKのインストールでこけたのでJetPack推奨

# DeepStreamインストール
こちらを参照
[Jetson NanoでDeepStream SDK　USBカメラ映像をリアルタイムで物体検出してRTSP配信をする](https://www.space-i.com/post-blog/jetson-nano%E3%81%A7deepstream-sdk%E3%80%80usb%E3%82%AB%E3%83%A1%E3%83%A9%E6%98%A0%E5%83%8F%E3%81%8B%E3%82%89%E6%A4%9C%E7%9F%A5%EF%BC%86iphone%E3%81%A7%E3%82%B9%E3%83%88%E3%83%AA%E3%83%BC%E3%83%A0/)

# DeepStream Python Bindingインストール
[こちらのサイト](https://developer.nvidia.com/deepstream-download)から"DeepStream Python Apps and Bindings"をダウンロード
![Screenshot from 2020-04-24 19-01-24.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72035/9c57d0ec-a114-9fcd-8128-a0d0f0f34a09.jpeg)
任意の場所に保存して解凍

```
$ tar -xjvf deepstream_python_v0.5.tbz2 
deepstream_python_v0.5/
deepstream_python_v0.5/LICENSE.txt
deepstream_python_v0.5/ds_pybind_0.5.tbz2
deepstream_python_v0.5/LicenseAgreement.pdf
deepstream_python_v0.5/README
```
更に"ds_pybind_0.5.tbz2"を解凍

```
$ cd deepstream_python_v0.5/
$ ls
LICENSE.txt  LicenseAgreement.pdf  README  ds_pybind_0.5.tbz2
~/deepstream_python_v0.5$ tar -xjvf ds_pybind_0.5.tbz2 
```
deepstream_python_v0.5/READMEを参考にしながらインストールを進める。
まず、DeepStream SDKのインストールディレクトリにPython Bindingを入れる。

```
$ tar -xjvf ds_pybind_v0.5.tbz2
$ cp -r python /opt/nvidia/deepstream/deepstream-4.0/sources/
```

この際、フォルダ構成は以下のようになっていることを確認

```
/opt/nvidia/deepstream/deepstream-4.0/sources/python/bindings
/opt/nvidia/deepstream/deepstream-4.0/sources/python/apps$ ls
common            deepstream-test2  deepstream-test4  
deepstream-test1  deepstream-test3  
```

Gst-pythonをインストールする。

```
   $ sudo apt-get install python-gi-dev
   $ export GST_LIBS="-lgstreamer-1.0 -lgobject-2.0 -lglib-2.0"
   $ export GST_CFLAGS="-pthread -I/usr/include/gstreamer-1.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include"
   $ git clone https://github.com/GStreamer/gst-python.git
   $ cd gst-python
   $ git checkout 1a8f48a
   $ ./autogen.sh PYTHON=python3
   $ ./configure PYTHON=python3
   $ make
   $ sudo make install
```
## Jetson Nano用に設定ファイルを修正する。
今回はサンプルプログラムのdeepstream-test1を例に設定を行う
まず、deepstream-test1内に入る。

```
$ cd /opt/nvidia/deepstream/deepstream-4.0/sources/python/apps/deepstream-test1
$ ls
README                dstest1_pgie_config.txt  
deepstream_test_1.py  
```
この中の”dstest1_pgie_config.txt”がデフォルトの設定ファイルなのだが、これはJetson AGX Xavier用の設定ファイルなので、Jetson Nano用に修正する必要がある。
そのため新規に以下の"dstest_jetson_nano_config.txt"というファイルを作成する。
以下の内容をそのままコピーして貼り付ける。

```dstest_jetson_nano_config.txt
[property]
gpu-id=0
net-scale-factor=0.0039215697906911373
model-file=../../../../samples/models/Primary_Detector_Nano/resnet10.caffemodel
proto-file=../../../../samples/models/Primary_Detector_Nano/resnet10.prototxt
model-engine-file=../../../../samples/models/Primary_Detector_Nano/resnet10.caffemodel_b8_fp16.engine
labelfile-path=../../../../samples/models/Primary_Detector_Nano/labels.txt
batch-size=8
process-mode=1
model-color-format=0
## 0=FP32, 1=INT8, 2=FP16 mode
network-mode=2
num-detected-classes=4
interval=0
gie-unique-id=1
output-blob-names=conv2d_bbox;conv2d_cov/Sigmoid
#parse-bbox-func-name=NvDsInferParseCustomResnet
#custom-lib-path=/path/to/libnvdsparsebbox.so
#enable-dbscan=1

[class-attrs-all]
threshold=0.2
group-threshold=1
## Set eps=0.7 and minBoxes for enable-dbscan=1
eps=0.2
#minBoxes=3
roi-top-offset=0
roi-bottom-offset=0
detected-min-w=0
detected-min-h=0
detected-max-w=0
detected-max-h=0
```
また、deepstream_test_1.pyを以下のように修正する。

```deepstream_test_1.py
    - pgie.set_property('config-file-path', "dstest1_pgie_config.txt")
    + pgie.set_property('config-file-path', "dstest_jetson_nano_config.txt")

  　- streammux.set_property('width', 1920)
  　+ streammux.set_property('width', 動画の幅)
    - streammux.set_property('height', 1080)
    + streammux.set_property('height', 動画の高さ)
```
動画の解像度を事前に調べて設定するのは面倒なのでOpenCVを使って動画の解像度を取得するようにしてみるのも良い。
たとえばこんな感じ

```deepstream_test_1.py
    import cv2
    cap = cv2.VideoCapture(args[1])
    ret, frame = cap.read()
    width = len(frame[0])
    height = len(frame)
    print (f"width:{width}, height:{height}")
    streammux.set_property('width', width)
    streammux.set_property('height', height)
```

## 実行
deepstream_test_1.pyと同一ディレクトリにテスト用の動画ファイルを起き、以下のコマンドを実行すると画面上にDeepStreamの推論結果が表示される。
また、推論結果が表示されるまで５分程度かかる模様

```
$ python3 deepstream_test_1.py "動画ファイル"
```
![Screenshot from 2020-04-28 11-04-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72035/311f734a-80bd-7a25-9421-8806ea30e11d.png)


## 動かない場合
もし動かない場合、以下の点を確認してみる。

 - DeepStream SDK配下のPyhonBindingの配置場所が正しいか確認する<Br>　→deepstream-4.0/sources/python/appsの下にdeepstream-test*フォルダがちゃんと存在しているか
 - 動画はH.264か
 - DeepStream SDK、Jetpack、Python Bindingのバージョンはそれぞれ適切な組み合わせか<Br>　→執筆時点ではJetPack v.4.2.2.、DeepStream SDK v.4.0.2、Python Binding v.0.5αの組み合わせが最新である
 - それでもわからない場合はGSTのデバッグオプションを有効にしてみる。<Br>　→```$ GST_DEBUG=3 python3 deepstream_test_1.py "動画ファイル"```で実行するとGSTのデバッグオプションが有効となり、詳細な起動ログがコンソールに表示される。