UnitVでself learning classifier（〇×判定器を作る）

# 背景
表題通りですが、[UnitV AI Camera](https://www.switch-science.com/products/6996)と[MaixPy](https://wiki.sipeed.com/soft/maixpy/en/index.html)の [self learning classifier](https://wiki.sipeed.com/soft/maixpy/en/course/ai/image/self_learn_classifier.html)で遊びます。
self learning classifier（自己学習分類器？）では、開発ボード上でオブジェクトを直接学習し、それを直接使用して分類を行います。

試しに、〇×判定器を作りました。
計算式につけられているのが〇なのか×なのか判定します。
![IMB_sRogei.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324101/207ec45b-bd82-0760-17c2-ffc6f2a06e74.gif)


# 環境
- Windows11
- MaixPy (3ではないほうなので注意)
- [UnitV AI Camera(OV7740版)](https://www.switch-science.com/products/6996)


# 実装
- 公式wikiの [self learning classifier](https://wiki.sipeed.com/soft/maixpy/en/course/ai/image/self_learn_classifier.html)の使い方をもとに進めていきます。
    - More Usages > Neural Network Applications>Image Processing>self learning classifier
    - [MaixPy3](https://wiki.sipeed.com/soft/maixpy3/zh/usage/AI_net/self_learn.html#)版もあり、こちらの説明のほうが充実しているため参考にはなります。

## 1. MaixPy IDEのインストール
MaixPy IDEは、k210マイコンでプログラミングするためのツールです。
[こちら](https://github.com/sipeed/MaixPy/releases)からインストールします。
MaixPy3もあるため、注意が必要です。

## 2. kflash_guiのインストール
kflash_guiは、いわゆるマイコンにbin等のファームウェアを書き込むツールです。

[こちら](https://github.com/sipeed/kflash_gui/releases)からインストールします。
Windowsでしたので、kflash_gui_v1.8.1_windows.7zを選択。

## 3. モデルのダウンロード
学習済みモデルを入れ替えることによって、機能を入れ替えることができます。
Neural Network Applicationsサンプルには、他にも、顔認識や物体認識があります。

### 3.1 マシンコードの取得
self learning classifierのモデルは、暗号化モデルのため、使うハードウェアのマシンコードの登録が必要です。以下の記事を参考に、マシンコードを取得してください。

https://qiita.com/matsuhachi/items/2ffd339967b07a2dddc2


### 3.2 モデルのダウンロード
MaixHubから学習済みモデルをダウンロードします。

https://maixhub.com/model/zoo/61

下载（ダウンロード）ボタンを押します。
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324101/5f3eca6f-6b39-4b1b-fb58-6448b2404cf4.png">

以下の画面が出ますので、3.1で取得したマシンコードを入力してください。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324101/6e57c60b-e9aa-d97e-888c-c247bc4f0d08.png">

Self_Learning_Classifier.zipがダウンロードできます。
中に、モデル2つと、サンプルコードが入っています。

## 4. モデルの書き込み
kflash_guiを起動し、先ほどダウンロードしたモデルをアドレス0x30000に書き込みます。
モデルは2つありますが、今回はsipeed_learn_model.smodelを使います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324101/4bc21b87-d726-f679-636f-3000fde3746a.png)


self_learn_classifier_lite.smodelは軽いデータ量のモデルで、こちらを使う場合は分類器のインスタンス作成時に、fea_len=512を追加する必要があります。

```self_learning_classifier.py
classifier = kpu.classifier(model, class_num, sample_num, fea_len=512)
```


## 5. MaixPy IDEでの書き込み
MaixPyを起動し、先ほどダウンロードしたzipファイルの中にあるself_learning_classifier.pyを呼び出します。
UnitV向け、〇×判定向けにself_learning_classifier.pyを書き換えます。



○か×かの判別のため、分類数を`2`、名前を`maru`と`batsu`とします。
また、サンプル数を`20`にします。
```python:self_learning_classifier.py (12-16行目)
class_num = 2
sample_num = 20
THRESHOLD = 11
class_names = ['maru', 'batsu']
board_cube = 0
```


カメラの見え方を、UnitVのケーブルが下向き、対象物を正面に左右反転なく見えるよう調整します。
```python:self_learning_classifier.py (36, 37行目)
    sensor.set_vflip(True)
    sensor.set_hmirror(True)
```

UnitVのボタンのGPIOは18番と19番です。
今回はこちらのボタンを使うため、操作ボタンのGPIOの設定を`board_info.BOOT_KEY`から`19`に変更します。
```python:self_learning_classifier.py (40, 41行目)
fm.register(19, fm.fpioa.GPIOHS0)
key = GPIO(GPIO.GPIOHS0, GPIO.PULL_UP)
```

学習終了後にモデルを保存するように書き換えます。
```python:self_learning_classifier.py (96-98行目)
            print("train end")
            classifier.save("marubatsu.classifier")
            train_status = 1
```

学習済みの検出中のふるまいを書き換えます。
```python:self_learning_classifier.py (106-114行目)
        if res_index >= 0 and min_dist < THRESHOLD :
            print("predict result:", class_names[res_index])
            if class_names[res_index] =="maru":
                img = draw_string(img, 2, 2, class_names[res_index], color=lcd.WHITE,scale=2, bg=lcd.RED)
            else:
                img = draw_string(img, 2, 2, class_names[res_index], color=lcd.WHITE,scale=2, bg=lcd.BLUE)
        else:
            print("unknown")
            img = draw_string(img, 2, 2, 'unknown', color=lcd.WHITE,scale=2, bg=lcd.BLACK)

```

UnitVとMaixPyを接続し、self_learning_classifier.pyを実行します。

ファームウェアの全体はgithubにあります。

https://github.com/matsuhachi/marubatsuClassifier
# 遊び方

↓ 中国語ですがなんとなく内容の分かる動画。こちらを参考にやります。

https://www.youtube.com/watch?v=aLW1YQrT-2A

### 1. 登録する分類クラスの代表画像を1枚ずつ撮る
UnitVサイドのボタンを押して撮影します。
撮れると次の指示が出ます。
maruとbatsuそれぞれ撮ります。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324101/1d0d984c-a421-489b-b395-8d7f988272ba.jpeg">

### 2. サンプルを撮る
サンプル数20、分類数2なら、10枚ずつサンプルを連続して撮ります。
サンプル数を分類数で割り、その枚数が各クラスのサンプル数となります。

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324101/192af12e-0550-45a1-bc8f-ffe56c12e6a7.jpeg">

0から始まっているため、サンプル10からはbatsuのサンプルを撮ります。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324101/76867156-da37-b999-17ab-f5ea92944ed3.jpeg">


### 3. 完成、分類が始まる
学習が終わると、自動でカメラに映ったものを分類しはじめます。

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324101/eeb2574c-3a89-0b66-9905-dda64b6646cf.jpeg">

青いマルはmaruとして判定していません。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324101/f7aac895-4809-e445-8125-d5c85ef87a81.jpeg">

赤いバツはbatsuと誤判定してますね。サンプルを増やすと変わるかもしれません。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324101/8add6436-742b-708e-2bfa-6b6c516f54c3.jpeg">

# おわりに
学習済みモデルをロードする際は、self_learning_classifier_load.pyを実行し、保存したモデルを呼び出すと実行できます。
UnitVやSipeed Maix等を買ったものの、サンプルを動かして終わりになってしまった方々が、何か作ってみる一助となれば幸いです。
（特にマシンコードの取得等でつまづく）