SPRESENSEにOLEDがついたので、今度はカメラをつけてAIカメラにしてみようと思います。久しぶりにNeural Network Console を使います。
1. 画像を準備
まず、画像を用意します。ネットから適当に集めてきた”鳥”、”馬”、”うさぎ”、”人”、”壁”の画像を使いました。
2. 画像を加工
これらを、ImageMagick を使って、28x28pixel 8bit (256階調)のグレースケールの画像に変換し、ニューラルネットワークのデータセットとして登録します。(詳細は、また別の機会に)
3. ニューラルネットワークをデザイン
Neural Network Console を開いてニューラルネットワークをデザインします。今回は LeNet ベースで作ってみました。(Spresenseに入るように少し改造しています)
4. ニューラルネットワークを学習・評価
登録したデータセットを使って、デザインしたニューロンを学習・評価します。
5. ニューロンモデルの出力
SPRESENSEで解釈できるニューロンモデル(model.nnb)を出力します。
6. Arduino スケッチの作成・焼き込み
ArduinoのAIスケッチを作成します。AIカメラを小さくしかったので、ニューロンモデルはSPRESENSEメインボードのフラッシュの中に格納してみました。
動作の様子は動画でどうぞ!!( ^ω^ )/~
関連記事
SPRESENSEでSony Neural Network Console を使ってみた!
https://makers-with-myson.blog.ss-blog.jp/2019-07-14
1. 画像を準備
まず、画像を用意します。ネットから適当に集めてきた”鳥”、”馬”、”うさぎ”、”人”、”壁”の画像を使いました。
2. 画像を加工
これらを、ImageMagick を使って、28x28pixel 8bit (256階調)のグレースケールの画像に変換し、ニューラルネットワークのデータセットとして登録します。(詳細は、また別の機会に)
3. ニューラルネットワークをデザイン
Neural Network Console を開いてニューラルネットワークをデザインします。今回は LeNet ベースで作ってみました。(Spresenseに入るように少し改造しています)
4. ニューラルネットワークを学習・評価
登録したデータセットを使って、デザインしたニューロンを学習・評価します。
5. ニューロンモデルの出力
SPRESENSEで解釈できるニューロンモデル(model.nnb)を出力します。
6. Arduino スケッチの作成・焼き込み
ArduinoのAIスケッチを作成します。AIカメラを小さくしかったので、ニューロンモデルはSPRESENSEメインボードのフラッシュの中に格納してみました。
#include <Camera.h>
#include <Flash.h>
#include <DNNRT.h>
#include <File.h>
#include "Adafruit_GFX.h"
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define BAUDRATE 115200
#define OFFSET_X 48
#define OFFSET_Y 8
#define BOX_WIDTH 224
#define BOX_HEIGHT 224
#define DNN_IMG_WIDTH 28
#define DNN_IMG_HEIGHT 28
DNNRT dnnrt;
DNNVariable input(DNN_IMG_WIDTH*DNN_IMG_HEIGHT);
String gStrResult = "";
void CamCB(CamImage img) {
if (!img.isAvailable()) return;
img.convertPixFormat(CAM_IMAGE_PIX_FMT_RGB565);
Serial.println("start clip and resize");
gStrResult = "";
int x;
int index = 0;
static uint8_t label[5] = {0, 1, 2, 3, 4};
CamImage small;
CamErr camErr = img.clipAndResizeImageByHW(small
,OFFSET_X ,OFFSET_Y
,OFFSET_X+BOX_WIDTH-1 ,OFFSET_Y+BOX_HEIGHT-1
,DNN_IMG_WIDTH ,DNN_IMG_HEIGHT);
if (!small.isAvailable()) {
Serial.println("Error Occured at making a target image");
if (camErr) Serial.println("CamErr: " + String(camErr));
return;
}
uint16_t* buf = (uint16_t*)small.getImgBuff();
float* input_buffer = input.data();
for (int i = 0; i < DNN_IMG_WIDTH * DNN_IMG_HEIGHT; ++i, ++buf) {
input_buffer[i] = (float)(((*buf & 0x07E0) >> 5) << 2) ; // extract green
}
Serial.println("DNN forward");
dnnrt.inputVariable(input, 0);
dnnrt.forward();
DNNVariable output = dnnrt.outputVariable(0);
float max_value = 0.0;
for (int i = 0; output.size() > i; ++i) {
if (output[i] > max_value) {
max_value = output[i];
index = i;
}
}
Serial.print("Result : ");
Serial.println(label[index] + " (" + String(output[index]) + ")");
if (label[index] != 10) {
gStrResult += String(label[index]);
} else {
gStrResult += String(" ");
}
display.clearDisplay();
display.setTextSize(3); // Normal 1:1 pixel scale
display.setCursor(0, 0); // Start at top-left corner
display.cp437(true); // Use full 256 char 'Code Page 437' font
switch (index) {
case 0: display.println("BIRD"); break;
case 1: display.println("HORSE"); break;
case 2: display.println("HUMAN"); break;
case 3: display.println("-----"); break;
case 4: display.println("RABBIT"); break;
}
display.display();
Serial.println("Recognition Result: " + gStrResult);
}
void setup() {
Serial.begin(BAUDRATE);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.display();
delay(2000); // Pause for 2 seconds
// Clear the buffer
display.clearDisplay();
// Draw a single pixel in white
display.drawPixel(10, 10, SSD1306_WHITE);
display.display();
delay(2000);
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(0, 0); // Start at top-left corner
display.cp437(true); // Use full 256 char 'Code Page 437' font
for(int16_t i=0; i<256; i++) {
if(i == '\n') display.write(' ');
else display.write(i);
}
display.display();
Serial.println("Loading network model");
File nnbfile = Flash.open("model.nnb", FILE_READ);
if (!nnbfile) {
Serial.println("nnb not found");
while(1);
}
Serial.println("Initialize DNNRT");
int ret = dnnrt.begin(nnbfile);
if (ret < 0) {
Serial.println("DNNRT initialize error.");
while(1);
}
theCamera.begin();
theCamera.startStreaming(true, CamCB);
}
void loop() {
/* do nothing here */
}
動作の様子は動画でどうぞ!!( ^ω^ )/~
関連記事
SPRESENSEでSony Neural Network Console を使ってみた!
https://makers-with-myson.blog.ss-blog.jp/2019-07-14
ソニー開発のNeural Network Console入門【増補改訂・クラウド対応版】--数式なし、コーディングなしのディープラーニング
- 出版社/メーカー: リックテレコム
- 発売日: 2018/11/14
- メディア: 単行本(ソフトカバー)
SONY SPRESENSE メインボード CXD5602PWBMAIN1
- 出版社/メーカー: スプレッセンス(Spresense)
- メディア: Tools & Hardware
SONY SPRESENSE カメラモジュール CXD5602PWBCAM1
- 出版社/メーカー: スプレッセンス(Spresense)
- メディア: Tools & Hardware