M5StickVで☭を認識してﾃﾞｪｪｪｪｪｪﾝしてみた

# きっかけ
<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="ja" dir="ltr">M5StickVで画像認識のチュートリアルとしてこれやったら面白そうなのでやります <a href="https://t.co/DZagC2Ibak">https://t.co/DZagC2Ibak</a></p>&mdash; 爆さん＠意識他界系 (@HogePiyo33_4) <a href="https://twitter.com/HogePiyo33_4/status/1199038819024007170?ref_src=twsrc%5Etfw">November 25, 2019</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 本題に入る前に

[これ](https://gihyo.jp/admin/serial/01/ubuntu-recipe/0587?page=1)に従って最新版ファームウェアをM5StickVに焼いておいてください．

# 制作過程
[MotoJapan's Tech-Memo](http://motojapan.hateblo.jp/entry/2019/09/17/083028)
さんを参考に作ります．
## 1. bootファイルをSDカードに展開
https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/VTraining-Client-VerA02B01.zip
をダウンロードし，SDカードに展開する．
元記事でも言われてますがSDの直下に置かないとだめらしいです．

## 2. 学習用データの収集
M5StickVにSDカード差し込んで電源を入れてちょっとするとこんな画面が出てくるので正面のボタンで撮影，SDスロットの反対側のボタンで学習対象を変えられます．
![startup.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238384/a42cb235-5155-cf2d-ad0f-44fb76151c89.jpeg)

こんな感じでパシャパシャ取っていきます．
<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="ja" dir="ltr">学習用データ収集中 <a href="https://t.co/NXrHo3fss4">pic.twitter.com/NXrHo3fss4</a></p>&mdash; 爆さん＠意識他界系 (@HogePiyo33_4) <a href="https://twitter.com/HogePiyo33_4/status/1199312538636185601?ref_src=twsrc%5Etfw">November 26, 2019</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 3. V-Training(モデル生成サイト)にデータをアップロード

http://v-training.m5stack.com/
にSDカードにある`train`と`valid`を`upload.zip`にしてアップロードします．
このとき気をつけるのが解凍したときにuploadディレクトリの直下に`train`と`valid`ができないとエラー(メールで来る)を吐かれます．
アップロードに成功して数分するとメールでモデルのダウンロードリンクと学習結果のグラフが送られてきます．

## 4. M5StickVで認識テスト

先程送られてきたリンクのモデルをダウンロードし，そのままM5StickV用のSDカードに解凍します(元々SDにあったファイルは念の為，消しました)．
その後，SDカードをM5StickVに前と同じように差し込み，起動！

<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="ja" dir="ltr">3種類の判別に成功！ <a href="https://t.co/MXDhx9MXGs">pic.twitter.com/MXDhx9MXGs</a></p>&mdash; 爆さん＠意識他界系 (@HogePiyo33_4) <a href="https://twitter.com/HogePiyo33_4/status/1199321085172310016?ref_src=twsrc%5Etfw">November 26, 2019</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 5. ﾃﾞｪｪｪｪﾝを流すプログラムを書く
https://github.com/sipeed/MaixPy_scripts/blob/master/multimedia/audio/play_wav.py
を参考に`boot.py`を改造していきます．

最終的にはこうなりました．

``` boot.py
import image
import lcd
import sensor
import sys
import time
import KPU as kpu
from fpioa_manager import *

import audio

from fpioa_manager import fm
from Maix import I2S, GPIO

wav_dev = I2S(I2S.DEVICE_0)

def setup():
    lcd.init()
    lcd.rotation(2)

    try:
        from pmu import axp192
        pmu = axp192()
        pmu.enablePMICSleepMode(True)
    except:
        pass

    try:
        img = image.Image("/sd/startup.jpg")
        lcd.display(img)
    except:
        lcd.draw_string(lcd.width()//2-100,lcd.height()//2-4, "Error: Cannot find start.jpg", lcd.WHITE, lcd.RED)

    sensor.reset()
    sensor.set_pixformat(sensor.RGB565)
    sensor.set_framesize(sensor.QVGA)
    sensor.set_windowing((224, 224))
    sensor.run(1)

    lcd.clear()

flag = False

def play_sound(fname):
    global flag
    flag = False
    if flag == False:
        flag = True
        try:
            player = audio.Audio(path = fname)
            player.volume(100)
            wav_info = player.play_process(wav_dev)
            wav_dev.channel_config(wav_dev.CHANNEL_1, I2S.TRANSMITTER,resolution = I2S.RESOLUTION_16_BIT, align_mode = I2S.STANDARD_MODE)
            wav_dev.set_sample_rate(wav_info[1])
            while True:
                ret = player.play()
                if ret == None:
                    break
                elif ret==0:
                    break
            player.finish()
        except:
            print("error")
        flag = False
    else:
        pass

def main():
    setup()
    fm.register(board_info.SPK_SD, fm.fpioa.GPIO0)
    spk_sd=GPIO(GPIO.GPIO0, GPIO.OUT)
    spk_sd.value(1) #Enable the SPK output

    fm.register(board_info.SPK_DIN,fm.fpioa.I2S0_OUT_D1)
    fm.register(board_info.SPK_BCLK,fm.fpioa.I2S0_SCLK)
    fm.register(board_info.SPK_LRCLK,fm.fpioa.I2S0_WS)


    task = kpu.load("/sd/21c4fa151bed20a9_mbnet10_quant.kmodel")

    labels=["USSR","USA","GB"] #You can check the numbers here to real names.
    while(True):
        img = sensor.snapshot()
        fmap = kpu.forward(task, img)
        plist=fmap[:]
        pmax=max(plist)
        max_index=plist.index(pmax)
        a = lcd.display(img)
        fname = None
        if pmax > 0.95:
            lcd.draw_string(40, 60, "Accu:%.2f Type:%s"%(pmax, labels[max_index].strip()))
            if labels[max_index] == "USSR":
                fname = "/sd/USSR.wav"
            elif labels[max_index] == "USA":
                fname = "/sd/USA.wav"
            elif labels[max_index] == "GB":
                fname = "/sd/GB.wav"
            play_sound(fname)
            sensor.reset()
            sensor.set_pixformat(sensor.RGB565)
            sensor.set_framesize(sensor.QVGA)
            sensor.set_windowing((224, 224))
            sensor.run(1)
            lcd.clear()
    a = kpu.deinit(task)

main()

```
<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="ja" dir="ltr">できたー <a href="https://t.co/AkfWvrYPl1">pic.twitter.com/AkfWvrYPl1</a></p>&mdash; 爆さん＠意識他界系 (@HogePiyo33_4) <a href="https://twitter.com/HogePiyo33_4/status/1199695416419217409?ref_src=twsrc%5Etfw">November 27, 2019</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

音はWikipediaから国歌を取ってきて加工しました．
一回対象を認識するとカメラがフリーズするので，その度にリセット噛ませたほうがいいです．
このプログラムの問題としては，音楽再生中にディスプレイの更新が止まること．
マルチスレッドにしてないから仕方ないけどチョット不便です．

#感想
完走した感想としては，M5StickVとk210には文句はないですが，IDEのUIによるストレスがあったのでVSCodeベースになってほしいです(宗教)．

#参考にさせてもらったところ
https://qiita.com/nnn112358/items/6f4934f8b81902b8e98c
https://qiita.com/manontroppo1974/items/43105469a8d560bfead8
https://qiita.com/KatsuShun89/items/72b918c6ec8314380b77
https://qiita.com/iwaoka1986/items/fcf48cb3ae3fd8f88a33