Maix BitのNPUを動かしてみる(1)

カメラを動かしてNPUを動作させてみます

ogochan
ロボットネズミ

前回の予告通り、カメラを動かしてみます。

しばらく本体を動かさないので、Maix Bit単体で動かす話になります。

準備

何はともあれ、カメラが必要になります。

カメラはMaixで売っているカメラならどれでも大丈夫っぽいです。ちっちゃいスマポっぽいカメラでも、

でっかい広角レンズのついたカメラでも、

問題なく動きます(試しました)。

買う前はいろいろ心配になりましたが、そんなに悩む必要はありませんでした。

当然、画角は異なりますし、向き等も異なります。

裸カメラ

 

レンズのある方

お好みの方にして下さい。今のところは、大きいレンズのついた奴の方がいろいろやりやすそうではありますが、実際にどうかは試してからですね。

まぁそんなに高いものでもないので、両方持っておいて良いかも知れません。

まずは顔検出の準備(モデルのロード)

簡単かつ基本的なものから試してみます。

SiPeedのWikiのソフトウェアドキュメントのKPUの項に、顔検出の説明があるので試してみます。

まず、モデルのダウンロードをします。使うモデルは、

http://dl.sipeed.com/MAIX/MaixPy/model/face_model_at_0x300000.kfpkg

です。適当な場所にダウンロードしておきます。

このモデルを使うわけですが、Maix Bitのモデルは、

  • 内部メモリに直接ロード
  • SDカードに入れて実行時ロード

の2つの方法があります。違いについては、ストレージシステムについての説明の項にあります。前者はロードさせるためにkflash_guiというツールが必要です。ただし、あまり大きなモデルを入れることができません。後者は特にツールは不要ですが、SDカードを物理的に用意してやる必要があります。前者で使うツールは他のことに使うツールですからどうせ用意しておかなくてはなりません。後者で使うSDカードはMaix Bitを使う時ファイルシステムが必要な時には必須だと思った方が良いです。ですから、結局のところ両方準備した方が良いでしょう。

今回は初回なので、前者の「内部メモリに直接ロード」という方法にします。と言うのも、このためのコードface_findは前者を前提としたコードになっているからです。まぁ説明を見ればほんのちょっとの違いでしかないので、わかるようになってまた使うのであれば、書き換えてしまえばいいだけなんですけどね。

kflash_guiについて

というわけで、まずはkflash_guiを入手します。kflash_guiのバイナリはGitHubに置いてあります。ここから、自分の環境に合ったものを落として使って下さい。

現在のバージョンのkflash_guiはこんな感じです。

ここで絶対に指定しなければならないのは、BoardPortですね。他は多分そのままで大丈夫だと思います。↑のようになっていればOKです。Boardについてはボードをの種類を指定するわけですが、これは現在入手可能なものは「Sipeed Maix Bit( with Mic )」です。多分マイクなしの方は入手できないと思います。

Maix Bitを接続して、Select Fileのところにダウンロードしたモデルファイルの名前を指定して「Download」ボタンをクリックするとMaix Bitにモデルがロードされます。最初は「Download」の意味が全くわからなくて、「モデルを置くんだからUploadだろう」と思ってボタンを探しまくりましたが、なぜかこのツールはボード目線です。

このツールはファイル名の拡張子を見て動作を変えます。ファイル名の拡張子がkfpkgの場合はモデルの場所(0x30000)からデータを配置するように動作します。拡張子がそれ以外の場合はデータを配置するアドレスを聞いて来ます。kfpkgは実は単なるzipファイルなんですが、これを展開して来たmodelという拡張子のファイルを使うことになった場合は、0x30000を指定すれば同じように動作させることができます。

「Download」が成功すればモデルのロードが成功です。

このツールはファームウェアの更新等にも使います。

走らせてみる

ではプログラムを走らせてみましょう。

Pythonコードの走らせ方もいろいろありますが、今回はMaixPy IDEにコードのコピペをして動かしてみます。

コードは前述のGitHubにありますが、ここに展開しておきます。

import sensor, image, lcd, time
import KPU as kpu
import gc, sys

def lcd_show_except(e):
    import uio
    err_str = uio.StringIO()
    sys.print_exception(e, err_str)
    err_str = err_str.getvalue()
    img = image.Image(size=(224,224))
    img.draw_string(0, 10, err_str, scale=1, color=(0xff,0x00,0x00))
    lcd.display(img)

def main(model_addr=0x300000, lcd_rotation=0, sensor_hmirror=False, sensor_vflip=False):
    try:
        sensor.reset()
    except Exception as e:
        raise Exception("sensor reset fail, please check hardware connection, or hardware damaged! err: {}".format(e))
    sensor.set_pixformat(sensor.RGB565)
    sensor.set_framesize(sensor.QVGA)
    sensor.set_hmirror(sensor_hmirror)
    sensor.set_vflip(sensor_vflip)
    sensor.run(1)

    lcd.init(type=1)
    lcd.rotation(lcd_rotation)
    lcd.clear(lcd.WHITE)

    anchors = (1.889, 2.5245, 2.9465, 3.94056, 3.99987, 5.3658, 5.155437, 6.92275, 6.718375, 9.01025)
    try:
        task = None
        task = kpu.load(model_addr)
        kpu.init_yolo2(task, 0.5, 0.3, 5, anchors) # threshold:[0,1], nms_value: [0, 1]
        while(True):
            img = sensor.snapshot()
            t = time.ticks_ms()
            objects = kpu.run_yolo2(task, img)
            t = time.ticks_ms() - t
            if objects:
                for obj in objects:
                    img.draw_rectangle(obj.rect())
            img.draw_string(0, 200, "t:%dms" %(t), scale=2)
            lcd.display(img)
    except Exception as e:
        raise e
    finally:
        if not task is None:
            kpu.deinit(task)


if __name__ == "__main__":
    try:
        main( model_addr=0x300000, lcd_rotation=0, sensor_hmirror=False, sensor_vflip=False)
        # main(model_addr="/sd/m.kmodel")
    except Exception as e:
        sys.print_exception(e)
        lcd_show_except(e)
    finally:
        gc.collect()

これをコピペすると

こんな感じに。

処理の内容はざっと見ると何となくわかるんじゃないかと思いますが、

  1. sensor(カメラ)を初期化して走らせる
  2. LCDを初期化する
  3. KPUにモデルをロードする
  4. KPUでyolo2を走らせるようにする
  5. ループ
    1. sensorから静止画を1枚取得する
    2. 取得した画像でyolo2の処理をさせる
    3. 2の結果を1の画像に重畳する
    4. LCDに結果を表示する

という感じになっています。簡単ですねw

これを走らせてみます。

こんな感じで顔検出されました。

GitHubにはmachine_visionというフォルダにいくつかデモがあるので、それを試してみるのも面白いでしょう。

まとめ

今回は顔検出を例に、Maix Bitの基本的な操作を説明しました。

Maix Bitのこの辺の説明はわかってみればどうってことないのですが、いろんな説明が散在していて、まとまった形になっていなかったりどれが重要なのかわからなかったりで、案外つまづくことではないかと思います。

個々のAPIについては追い追い勉強することにして、とりあえずは基本的なオペレーションを把握しましょう。