EMOI-PIC ライブキャプチャーAI画像評価サンプルコード
- Spresenseカメラでライブ撮影した画像を深層学習で評価するサンプルプログラムです。あらかじめSONY Neural Network Consoleで学習済のネットワークをmodelとして取り込んで実行します。評価値に基づいて様々なアプリケーションに応用することが可能です。
- 撮影画像: 160*120画素、RGB565カラー
- AI評価対象画像: 16*12画素、RGB888カラー
- Spresenseカメラ取付方向: カメラ基板のSONYロゴの上下が通常の場合は、 CAMERA_UPSIDEDOWNはFALSEで、ロゴが上下逆の場合はTRUEにしてください
#include <stdio.h>
#include <Camera.h>
#include <Adafruit_ILI9341.h>
#include <SDHCI.h>
#include <DNNRT.h>
#define TFT_DC (9)
#define TFT_CS (10)
#define CAMERA_UPSIDEDOWN FALSE
#define DISPLAY_WIDTH (320)
#define DISPLAY_HEIGHT (240)
#define DNN_WIDTH (16)
#define DNN_HEIGHT (12)
#define DNN_COLOR (24)
Adafruit_ILI9341 display = Adafruit_ILI9341(TFT_CS, TFT_DC);
SDClass theSD;
DNNRT dnnrt;
DNNVariable input(DNN_WIDTH*DNN_HEIGHT*DNN_COLOR);
uint16_t* image_buffer;
uint16_t drawImageBuf[160*120];
int total_image_count = 0;
void putStringOnLCD(String str, int line, int color) {
int len = str.length();
display.fillRect(0, DISPLAY_HEIGHT/2+line*18+6, DISPLAY_WIDTH-1, DISPLAY_HEIGHT/2+(line+1)*18+5, ILI9341_BLACK);
display.setTextSize(2);
int sx = DISPLAY_WIDTH/2 - len/2*12;
if (sx < 0) sx = 0;
if (line < 0) sx = 0;
else if (line > 5) sx = 5;
display.setCursor(sx, DISPLAY_HEIGHT/2+line*18+8);
display.setTextColor(color);
display.println(str);
}
void CamCB(CamImage img)
{
if (img.isAvailable()) {
image_buffer = (uint16_t *)img.getImgBuff();
}
}
void setup() {
CamErr err;
display.begin();
display.setRotation(3);
display.fillScreen(ILI9341_BLACK);
display.fillScreen(ILI9341_BLACK);
err = theCamera.begin(1, CAM_VIDEO_FPS_5, CAM_IMGSIZE_QQVGA_H, CAM_IMGSIZE_QQVGA_V, CAM_IMAGE_PIX_FMT_RGB565);
err = theCamera.setAutoWhiteBalanceMode(CAM_WHITE_BALANCE_AUTO);
err = theCamera.startStreaming(true, CamCB);
while (!theSD.begin()) {
putStringOnLCD("Insert SD card", 0, ILI9341_GREEN);
}
File nnbfile = theSD.open("model.nnb"); // SDカード内の学習済モデルのファイルをオープン
if (!nnbfile) {
putStringOnLCD("model.nnb is not found", 0, ILI9341_RED);
while(1);
}
int ret = dnnrt.begin(nnbfile); // DNNRTを初期化
if (ret < 0) {
char textBuf[16] = {0};
sprintf(textBuf, "DNNRT begin fail: %f", ret);
putStringOnLCD(textBuf, 0, ILI9341_RED);
while(1);
}
}
void loop() {
// 入力画像(160*120)をディスプレイに描画
display.drawRGBBitmap(0, 0, image_buffer, CAM_IMGSIZE_QQVGA_H, CAM_IMGSIZE_QQVGA_V);
float* rPlane = input.data();
float* gPlane = rPlane + DNN_WIDTH * DNN_HEIGHT;
float* bPlane = gPlane + DNN_WIDTH * DNN_HEIGHT;
// 入力画像(160*120)を16*10に間引きながら1次元入力ベクトルに書き込み
if(CAMERA_UPSIDEDOWN == FALSE) {
for (int y = 0; y < DNN_HEIGHT; y++) {
for (int x = 0; x < DNN_WIDTH; x++) {
int n = y*10*CAM_IMGSIZE_QQVGA_H + x*10;
*(rPlane++) = (float)((image_buffer[n] >> 8) & 0xf8) / 255.0;
*(gPlane++) = (float)((image_buffer[n] >> 3) & 0xfc) / 255.0;
*(bPlane++) = (float)((image_buffer[n] << 3) & 0xf8) / 255.0;
}
}
} else {
for (int y = DNN_HEIGHT; y >= 0; y--) {
for (int x = DNN_WIDTH; x >= 0; x--) {
int n = y*10*CAM_IMGSIZE_QQVGA_H + x*10;
*(rPlane++) = (float)((image_buffer[n] >> 8) & 0xf8) / 255.0;
*(gPlane++) = (float)((image_buffer[n] >> 3) & 0xfc) / 255.0;
*(bPlane++) = (float)((image_buffer[n] << 3) & 0xf8) / 255.0;
}
}
}
dnnrt.inputVariable(input, 0); // 入力データ設定
dnnrt.forward(); // 推論実行
DNNVariable output = dnnrt.outputVariable(0); // 推薦結果取得
char textBuf[16] = {0};
sprintf(textBuf, "AI eval: %f", output[0]); // outputベクトルの先頭がスカラー評価値
putStringOnLCD(textBuf, 3, ILI9341_WHITE);
delay(1000);
}
投稿者の人気記事
-
eMoi-pic
さんが
2024/06/19
に
編集
をしました。
(メッセージ: 初版)
-
eMoi-pic
さんが
2024/06/20
に
編集
をしました。
ログインしてコメントを投稿する