編集履歴一覧に戻る
eMoi-picのアイコン画像

eMoi-pic が 2024年06月19日18時06分59秒 に編集

初版

タイトルの変更

+

EMOI-PIC ライブキャプチャーAI画像評価

タグの変更

+

SPRESENSE

メイン画像の変更

メイン画像が設定されました

記事種類の変更

+

セットアップや使用方法

本文の変更

+

# 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); } ```