【You Only Look Drone】Jetson Nano でドローン検知システムを作ってみた

## はじめに

最近発売された`Jetson Nano 2GB`を使ってドローン検知システムを作ってみました。
お好きな物体の画像でデータセットを作れば、オリジナルの検知システムが出来上がりますので是非ご参考ください！

## 構成

今回は`YOLOv4 tiny`を Colaboratory で転移学習させ、生成された重みを Jetson に移植しました。
学習に用いたドローンの画像は約100枚。YOLO独特のフォーマットがあるので、[こちら](https://github.com/tzutalin/labelImg)のラベリングツールでYOLO用のデータセットを作成し、食べさせました。

**推論は Jetsonローカルで行うため、インターネット接続は必要ありません。**
ただし、検知 → アラート通知の仕組みも作ったので、そこだけWiFiが必要です。

以下、全体の構成です。
WEBカメラは Logicool C525n を使用しました。
![image01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386486/df2dc644-9303-1d1b-bb79-d9c1d04a67e5.png)

YOLOの推論結果のログを監視して、ドローンを検知したら`LINE Notify`の API を叩く構成にしました。
ちなみに、こんな感じで検知します。
![image02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386486/0a2ca192-2cc3-e4f1-dbab-572d85a1af5e.png)

## モデル作成

Colaboratory を開いたら、GPUモードに変更しましょう。
そして、YOLOv4 (darknet) を `git clone` します。
コマンドは以下です。

```
!git clone https://github.com/AlexeyAB/darknet
```
GPU と OpenCV を使えるように `makefile` を書き換えます。

```
%cd darknet
!sed -i 's/OPENCV=0/OPENCV=1/' Makefile
!sed -i 's/GPU=0/GPU=1/' Makefile
!sed -i 's/CUDNN=0/CUDNN=1/' Makefile
!sed -i 's/CUDNN_HALF=0/CUDNN_HALF=1/' Makefile
```
そして`make`します。

```
!make
```
これには少し時間がかかります。
できたら次は、学習済みの重みを落とします。

```
!wget https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v4_pre/yolov4-tiny.conv.29
```
そして、自分の Google Drive をマウントして、あらかじめアップロードしておいたデータセットを読み込めるようにしましょう。
YOLO の学習にはデータセット以外にも`obj.data.txt`や`yolov4-tiny-custom.cfg`などの設定ファイルが必要です。
用意しましょう。

まず`obj.data.txt`を作って以下を書き込みます。

```txt:obj.data.txt
classes = 1
train = /path/to/train.txt
valid = /path/to/test.txt
names = /path/to/obj.names
backup = /path/to/backup
```
今回はドローンを検知するだけなので`classes`は`1`にします。

`obj.names`にはラベル名を記載します。今回はテキストファイルに「drone」とだけ記載すればOKです。

`backup`ディレクトリには学習済みの重みが記録されます。

`yolov4-tiny-custom.cfg`はニューラルネットのアーキテクチャーを設定するファイルです。[こちら](https://github.com/alexeyab/darknet#how-to-train-to-detect-your-custom-objects)を参考に内容を書き換えましょう。

`train.txt`と`test.txt`は各データセットの画像へのパスを記載したテキストファイルです。仮に、親ディレクトリ名が`dir`、trainデータセットのディレクトリ名が`obj`の場合、以下のコードで生成できます。

```python

import os

image_files = []
os.chdir(os.path.join("dir", "obj"))
for filename in os.listdir(os.getcwd()):
    if filename.endswith(".jpg"):
        image_files.append("dir/obj/" + filename)
os.chdir("..")
with open("train.txt", "w") as outfile:
    for image in image_files:
        outfile.write(image)
        outfile.write("\n")
    outfile.close()
os.chdir("..")
```
Colaboratory などで実行すると、`train.txt`が生成されたはずです。
`test.txt`も同様に作ります。
最終的に以下のファイル/フォルダが同じ場所にあればOKです。

- backup
- obj
- test
- train.txt
- test.txt
- obj.data.txt
- obj.names
- yolov4-tiny-custom.cfg
- yolov4-tiny.conv.29

`backup`は学習済みの重みが保存される空ディレクトリ、`obj`と`test`は自作したオリジナルの training/test データセットをそれぞれ格納するディレクトリです。
これで準備OKですので、オリジナルデータセットで YOLOv4 (darknet) を訓練しましょう！

```
!./darknet detector train /path/to/obj.data.txt /path/to/yolov4-tiny-custom.cfg /path/to/yolov4-tiny.conv.29 -dont_show -map
```
約100枚のドローン画像を用いた学習で約1時間半かかりました。
学習が終わると、`backup`フォルダに`yolov4-tiny-custom_best.weights`が生成されます。
こいつと`obj.data.txt` `obj.names` `yolov4-tiny-custom.cfg`を Jetson Nano に移して推論していきます！

## Jetson Nano の環境構築

基本的には Colaboratory と同じ環境を Jetson Nano にも作ってあげます。
初期設定などは以下の動画を参考に進めていけばOKです。
これで必要なモノがだいたい揃うので、この後は足りないものを Jetson のターミナルから都度ダウンロードしていく感じです。

Jetson AI Fundamentals - S1E1 - First Time Setup with JetPack
https://youtu.be/uvU8AXY1170

Jetson AI Fundamentals - S3E1 - Hello AI World Setup
https://youtu.be/QXIwdsyK7Rw

Jetson のターミナルを起動し、YOLOv4 (darknet) を入れたいディレクトリに移動して`git clone`です。

```
$ git clone https://github.com/AlexeyAB/darknet
```
次に Colaboratory 同様に `makeflie` をいじるのですが、少し方法が違います。
[こちらの記事](https://qiita.com/tayutayufk/items/3d715184e0a7cefa5e9a)を参考に変更しましょう。

できたら`make`コマンドでビルドします。

```
$ make
```
これで準備できました。
Jetson Nano + WEBカメラで YOLOv4 のリアルタイム推論を発動させましょう。

```
$ ./darknet detector demo /path/to/obj.data.txt /path/to/yolov4-tiny-custom.cfg /path/to/yolov4-tiny-custom_best.weights -thresh 0.1 >darknet.log
```
デフォルトで接続されたWEBカメラを使ってくれるはずです。

`- thresh`で検知の閾値を設定します。推論結果として一種の確度(%)みたいなものを出力するのですが、`thresh 0.1`なら`10%`以上の確度を持ってドローンと分類したものだけを表示してくれます。

`>darknet.log`は次に説明するアラート通知に使うためのログを吐き出すコマンドです。

## LINE通知の仕組みを作る

今回は`swatch`で`darknet.log`を監視して「drone」というワードが出てきたら .shファイルを実行させ`LINE Notify`の API を叩きます。

まず`swatch`をインストールします。

```
$ sudo apt-get install swatch
```
次に`vim`や`nano`で`swatch.conf`ファイルを作ります。
>※ vim などが入っていない場合はターミナルから落としてください。
※ アクセス権限も適宜変更してください。

```
$ vim swatch.conf
```
```txt:swatch.conf
watchfor /drone/
	exec /path/to/LINEnotify.sh
	threshold track_by=/drone/,type=both,count=3,seconds=10
```
`type=both,count=3,seconds=10`とすると、
「time interval が10秒に設定され、time intervalの間に 3 回ドローンを検知した時点で`LINEnotify.sh`を実行。その後はtime intervalが切れるまで無視される。」
という設定になります。
検知する度にLINEがくるのは嫌なので。。

実行ファイルには以下のように記述します。

```sh:LINEnotify.sh
curl -g -X POST -H "Authorization: Bearer ACCESS_TOKEN" -F "message=ここにメッセージを書く" https://notify-api.line.me/api/notify

echo
exit 0
```
`ACCESS_TOKEN`に発行されたトークンを記入します。
トークンの発行方法は[こちら](https://qiita.com/iitenkida7/items/576a8226ba6584864d95)を参照ください。

これで完成です！
リアルタイムでドローン検知しているときに以下のように実行すると、

```
$ swatchdog --config-file=/path/to/swatch.conf --tail-file=/path/to/darknet.log
```
こんな感じでLINEのメッセージが届きます。
![image03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386486/6ab84ba7-7686-f8e1-7229-91d300b0d140.png)

## おわりに

Jetson Nano 2GB でオリジナルデータセットを学習した YOLOv4 tiny を動かしてみました。
この構成でだいたい`5 FPS`は出ます。
飛行しているトイドローンの横で本をひらひらさせても誤検知しません笑
100枚程度で tiny なのに、なかなか優秀です。

![image04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386486/a7a88617-0cf9-3b03-403f-7e5a791d9d2e.png)

これで部屋にドローンが侵入しても安心ですね！

## 参考文献
- [JETSON AI COURSES AND CERTIFICATION](https://developer.nvidia.com/ja-jp/embedded/learn/jetson-ai-certification-programs)
- [LINE Notify](https://notify-bot.line.me/ja/)
- [GitHub - dusty-nv/jetson-inference: Hello AI World guide to deploying deep-learning inference networks and deep vision primitives with TensorRT and NVIDIA Jetson.](https://github.com/dusty-nv/jetson-inference)
- [GitHub - AlexeyAB/darknet: YOLOv4v / Scaled-YOLOv4 - Neural Networks for Object Detection (Windows and Linux version of Darknet )](https://github.com/AlexeyAB/darknet)
- [Train YOLOv4-tiny on Custom Data - Lightning Fast Object Detection](https://blog.roboflow.com/train-yolov4-tiny-on-custom-data-lighting-fast-detection/)

<br>