GR-KAEDEで取得した画像データを使ってe-AIで推論を実行してみた

[がじぇるねGR](https://qiita.com/advent-calendar/2021/gadget-renesas?fbclid=IwAR0BuL-eWRIyqzwnFemFtHRLVfWqD7MMYPJeYPFzLrbCm8-5S3Z0-hcr5xY)
アドベントカレンダー7日目の記事になります。
よろしくお願いします。

久しぶりにGR-KAEDEを使って引っ張り出して、e-AIで推論を実行してみた。
e-AIとは組み込み機器で推論を実行することで、ルネサスエレクトロニクスではTensorFlow等のAIフレームワークの学習済みAIモデルをMCU/MPU用にC言語ソースコードに変換するe-AIトランスレータを提供している。
今回はこのe-AIトランスレータを使用してGR-KAEDEで取得した画像データに対して、推論を実行してみることにした。

# 開発環境
- e2 studio v7.6.0
- Gadget Renesasボード GR-KAEDE (別売りのCMOS Camera BoardとZigbee Boardも使用する)

# 実行手順
以下の手順で推論を実行する
1.　GR-KAEDE用のスケッチサンプルプログラムをe2 studioにインポート
2.　サンプルプログラムを編集して取得した画像データを28x28サイズに変換する処理を実装
3.　e-AIトランスレータで学習済みAIモデルをCソースファイルに変換
4.　28x28サイズの画像データに対して推論を実行する処理を実装

## GR-KAEDE用スケッチサンプルプログラムのインポート
Gadget RenesasボードにはUSBでPCと接続するとUSBストレージとして認識されて、そこにビルドしたバイナリファイルを格納すると自動的にフラッシュメモリに書き込まれてプログラムを実行できるファームウェアが書き込まれているのだが、自分のGR-KAEDEは前に一度デバッガと接続したため、ファームウェアを消してしまった。
再度ファームウェアをダウンロードしようと思ったが、もうWebからダウンロードできないらしい。
仕方なく、公式サイトで公開しているe2 studio用のスケッチサンプルを使用することにした。

## スケッチサンプル上に画像データを28x28サイズに変換する処理を実装
スケッチサンプルでは実際にCMOSカメラから画像データを取得する処理や、推論の実行に必要なグレースケールイメージを生成する処理が既に実装されているため、後はこの320x240のグレースケールイメージを28x28サイズにリサイズして、float型に変換する処理を実装してやる必要がある。
そのため、スケッチサンプル(setup関数とloop関数)を以下のように編集した。

~~~c
void setup()
{
    int i;
    int j;

    /* Initialize debug console */
    Serial.begin(9600);

    /* Initialize image buffer */
    for (i = 0; i < SIZE_Y; i++)
    {
        for (j = 0; j < SIZE_X; j++)
        {
            r_image[i][j] = 0;
        }
    }

    for (i = 0; i < RESIZE_Y; i++)
    {
        for (j = 0; j < RESIZE_X; j++)
        {
            c_image[(i * RESIZE_X) + j] = 0;
        }
    }

    /* Initialize camera module and SDRAM */
    image.begin();
}
~~~

~~~c
void loop()
{
    uint8_t * addr;
    TPrecision *prediction;
    TPrecision *input_img;
    TsInt i;

    /* Capture start */
    image.captureStart();

    /* Wait for capture to finish */
    while(!image.isCaptureFinished());
    addr = image.createGrayImage();

    /* Reduce image to 28 x 28 */
    scaling_image((uint8_t *)addr, (uint8_t *)r_image, 320, 240, 0.0875, 0.1166666666666667);

    /* Copy image to buffer */
    copy_image((uint8_t *)r_image, (float *)c_image, 320, 240);

    long time_start = millis();

    input_img = (TPrecision *)c_image;
    prediction = (TPrecision*) (intptr_t) dnn_compute(input_img);

    Serial.print("Dnn Compute time(ms):");
    Serial.println(millis() - time_start);
    for(i = 0;i < 10;i++){
        Serial.print(i); Serial.print(":");
        Serial.println(prediction[i]);
    }
}
~~~

loop関数上のscaling_image関数は画像データを指定した拡大率にリサイズする関数で、copy_image関数はリサイズした画像データをfloat型の28x28サイズのバッファにコピーする処理である。

## e-AIトランスレータで学習済みAIモデルをCソースファイルに変換
使用する学習済みAIモデルは「GRボード e-AI」で検索すると表示されるwebページ e-AIトランスレータ チュートリアルの学習済みAIモデルを使用させて頂いた。これをGRボードのWebコンパイラ上でCソースファイルに変換する。変換したCソースファイルをダウンロードして、先ほどのスケッチサンプルのプロジェクトにコピーしたら推論を実行する準備は完了する。

## 28x28サイズの画像データに対して推論を実行する処理を実装
推論を実行する処理はWebコンパイラでCソースファイルに変換した時に表示されるサンプルプログラムをそのまま使用させて頂いた。loop関数の`long time_start = millis();`以下がそのサンプルプログラムである。

## 推論を実行した結果
28x28のfloat型グレースケールイメージを入力して推論を実行してみたが、上手く数字を認識することはできなかった。
グレースケールイメージではなく、2値化したイメージなら上手く数字を認識できると考えて、2値化したイメージを入力して推論を実行してみた。
以下が入力した元画像とコンソール出力結果である。

![e_ai_3_qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354472/51808fa7-93b6-c155-1315-28d9c69cef3a.png)

![e_ai_9_qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354472/31b85802-d869-3d36-9ea3-f2eb1d972075.png)