違法（迷惑）行為をAIで検出　AI異常行動検知の方法

# 迷惑行為を一発検出

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/b468a7dc-dded-d209-f71d-ed2e51a9ddbe.png width=800>


店舗や公共の場では様々な違法・迷惑行為のリスクがあります。
**人力で監視するのは大変です。**

**AIを使えば24時間人員なしで監視でき、異常があればすぐに検出してアラートできます。**

# 路上喫煙を検知してみる

例として、禁煙地域に設置した監視カメラから路上喫煙を検知してみましょう。

# データを用意して、AIに学習させる

手順は単純です。
タバコの写っている画像を用意して、AIに学習させます。
するとAIはタバコを覚えて、監視カメラにタバコが移れば禁煙地域での喫煙を検知します。

### データの用意

このようにタバコの場所を四角で囲みます。
今回はRect Labelというツールを使いました。

![Mar-08-2023 20-57-49](https://user-images.githubusercontent.com/23278992/223707970-561ec681-4123-401a-b2d3-06b7bdf7efbd.gif)

https://rectlabel.com/

今回はデータをCOCO形式のjsonファイルで保存しました。

# AIの学習

今回は物体検出モデルをデータで学習します。

mmdetectionという様々なモデルが使えるツールボックスを使います。

https://github.com/open-mmlab/mmdetection

以下のようなモデルが同じ実行形式で使えるようになっています。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/5e7ab82e-6ae8-0189-c2c0-b468831e2776.png width=600>

### インストール

```shell
pip install -U openmim
mim install mmcv-full
git clone https://github.com/open-mmlab/mmdetection.git
cd mmdetection
pip install -v -e .
```

以下のトレーニングスクリプトを実行します。

```shell
python tools/train.py configs/my_config.py --work-dir work_dir/
```

work-dirにログとチェックポイントが保存されます。
独自のconfigファイル（使うモデル、設定、データセットが記載されている）を作って自分のデータを学習させます。


### Configファイル
Configファイルには、使うモデル、設定、データセットなど、学習に必要なオプションが全て記載されています。
これを自分が使いたい設定で作ります。
以下に例を記載します。

```my_config.py
# The new config inherits a base config to highlight the necessary modification
_base_ = 'faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' 

# We also need to change the num_classes in head to match the dataset's annotation
model = dict(
    roi_head=dict(
        bbox_head=dict(num_classes=2)))

# Modify dataset related settings
dataset_type = 'COCODataset'
classes = ('tabacco','head')
data = dict(
    train=dict(
        img_prefix='my_dataset/images/train/',
        classes=classes,
        ann_file='my_dataset_train.json'),
    val=dict(
        img_prefix='my_dataset/images/val/',
        classes=classes,
        ann_file='my_dataset_val.json'),
    test=dict(
        img_prefix='my_dataset/images/val/',
        classes=classes,
        ann_file='my_dataset_val.json'))

load_from = 'faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth'
runner = dict(type='EpochBasedRunner', max_epochs=300)
```

### configファイルに必要な項目

以下のような内容を記載して継承元configを書き換えますが、**記載形式がモデルによって異なるので、継承元configを参照して記載するようにします**。

##### _ base _
自分のconfigファイルの元となる継承元configファイルを設定します。
継承元のconfigファイルはリポジトリの **configs/** にあります。
**自分のconfigファイルに記載する内容は継承元のconfigファイルの項目を書き換え、特に記載しない項目については継承元のconfigファイルの項目をそのまま引き継ぎます。**
つまり、configファイルは、ベースのconfigファイルを継承しています。

さらに、継承元のconfigファイル（父config）は更なる他のconfigファイル（祖父config）を継承している場合があります。
自分のconfigファイル（子）で継承元のconfigファイルの内容を書き換える場合は、継承元の記載形式を厳密に引き継いで内容を変える必要があります。そのため、継承元のconfigをさかのぼれるところまで見ておくことを推奨します。

### model
自分のデータセットのクラス数などをここのbbox_headで設定しておく必要があります。

### dataset_type
自分が使用するデータセットタイプを指定します。今回はCOCO形式を使うのでCOCODatasetを指定しています。
使えるデータセット形式（カスタム含む）はリポジトリのdataset/ディレクトリにあります。

### classes
自分のデータセットのクラス名を記載します。

### data
データ画像のディレクトリとアノテーションファイルのパスを指定します。

### load_from
トレーニングに使う事前トレーニング済みの重みのチェックポイントを指定します。
チェックポイントは継承元のモデルconfigとセットになっており、リポジトリのReadMeのモデル一覧から取得できます。

### runner
トレーニングの回数（エポック数）をここで指定します。


デフォルトでは１エポックごとにチェックポイントファイルが保存されます。
**学習開始時にエラーが出た場合、configファイルの何かしらが間違っているので、継承元を辿りながら正しく継承できるように解消していきます。**

![スクリーンショット 2023-03-08 21.20.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/749d1d98-0d75-1f5b-377f-b8eecb2eb447.png)

ということで順調に学習が進みました。

# 出来上がったAIでタバコを検出する

学習のconfigファイルと学習状況を記録したウェイトのチェックポイントから検出モデルを初期化して入力を指定して実行します。

```python
from mmdet.apis import init_detector, inference_detector
import mmcv

# Specify the path to model config and checkpoint file
config_file = 'configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py'
checkpoint_file = 'faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth'

# build the model from a config file and a checkpoint file
model = init_detector(config_file, checkpoint_file, device='cuda:0')

# test a single image and show the results
img = 'your_image.jpg'  # or img = mmcv.imread(img), which will only load it once
result = inference_detector(model, img)
# visualize the results in a new window
model.show_result(img, result)
# or save the visualization results to image files
model.show_result(img, result, out_file='result.jpg')
```

うまく検出できました。
これを監視カメラの映像に置き換えると、自動で検出できます。
また、頭の位置もとっているので吸うタイミングもわかります。

また、他の違法行為や迷惑行為も同様の工夫をすることで検出できます。

<img src=https://user-images.githubusercontent.com/23278992/223714557-5cac5022-ce96-4e2a-a403-d038e0ffd729.gif>

🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

機械学習、ARアプリ（Web/iOS）を作っています。
機械学習／AR関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
[GitHub](https://github.com/john-rocky)