EMOI-PIC AI学習用画像データ撮影サンプルコード
AI学習には大量の画像データが必要ですので、そのデータ収集のためにSpresenseカメラをデジカメ化するサンプルプログラムです。プッシュボタンを押すと、Spresenseカメラが画像を1枚撮影し、2種類の画像ファイルをSDカードに保存します。
- 確認用画像: 160×120画素のRGB各8ビットのBMP画像(IMG***.BMP、***は通し番号)
- AI学習対象画像: 16×12画素のRGB各8ビットのBMP画像(DAT***.BMP、***は通し番号)
- Spresenseカメラ取付方向: カメラ基板のSONYロゴの上下が通常の場合は、 CAMERA_UPSIDEDOWNはFALSEで、ロゴが上下逆の場合はTRUEにしてください
- デジタルピンD15をシャッターボタンの入力にしていますが、Spresense拡張ボードのpinModeをプルアップモード(INPUT_PULLUP)に設定していますので、外部に抵抗とかは無用で単にスイッチをD15とGNDとに接続するだけす。
#include <stdio.h>
#include <Camera.h>
#include <Adafruit_ILI9341.h>
#include <SDHCI.h>
#define TFT_DC (9)
#define TFT_CS (10)
#define BUTTON_PIN 15
#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;
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 writeBMPHeader(File &file, int w, int h, int bit) {
uint8_t bmpHeader_1[18] = {
0x42, 0x4D, // "BM" シグネチャ
0x36, 0x00, 0x00, 0x00, // ファイルサイズ(未使用)
0x00, 0x00, 0x00, 0x00, // 予約済み
0x36, 0x00, 0x00, 0x00, // ピクセルデータのオフセット
0x28, 0x00, 0x00, 0x00, // ヘッダーサイズ
};
uint8_t bmpHeader_2[3] = {
0x00, 0x00, 0x00
};
uint8_t bmpHeader_3[2] = {
0x01, 0x00 // プレーン数=1
};
uint8_t bmpHeader_4[24] = {
0x00, 0x00, 0x00, 0x00, // 圧縮(なし)
0x00, 0x00, 0x00, 0x00, // イメージサイズ(未使用)
0x13, 0x0B, 0x00, 0x00, // 水平解像度
0x13, 0x0B, 0x00, 0x00, // 垂直解像度
0x00, 0x00, 0x00, 0x00, // 色数(未使用)
0x00, 0x00, 0x00, 0x00 // 重要な色数(未使用)
};
file.write(bmpHeader_1, 18);
file.write(w); // 幅(160)
file.write(bmpHeader_2, 3); // 0パディング×3
file.write(h); // 高(120)
file.write(bmpHeader_2, 3); // 0パディング
file.write(bmpHeader_3, 2); // プレーン数×3
file.write(bit); // ビット/ピクセル(24ビットRGBカラー)
file.write(bmpHeader_2, 1); // 0パディング
file.write(bmpHeader_4, 24);
}
void CamCB(CamImage img)
{
if (img.isAvailable()) {
image_buffer = (uint16_t *)img.getImgBuff();
}
}
void setup() {
CamErr err;
pinMode(BUTTON_PIN, INPUT_PULLUP); // ボタン:プルアップ抵抗モードのためスイッチOFF時は1、ON時が0
display.begin();
display.setRotation(3);
display.fillScreen(ILI9341_BLACK);
while (!theSD.begin()) {
putStringOnLCD("Insert SD card", 0, ILI9341_GREEN);
}
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);
}
void loop() {
// 入力画像をディスプレイに描画
display.drawRGBBitmap(0, 0, image_buffer, CAM_IMGSIZE_QQVGA_H, CAM_IMGSIZE_QQVGA_V);
// シャッターボタンの押下(LOW)確認
if(digitalRead(BUTTON_PIN)==HIGH) return;
// 高精細BMP画像ファイル(RGB24ビット)のSDカード保存
char filename[16] = {0};
sprintf(filename, "IMG%03d.BMP", total_image_count);
theSD.remove(filename);
File bmpFile = theSD.open(filename, FILE_WRITE);
writeBMPHeader(bmpFile, CAM_IMGSIZE_QQVGA_H, CAM_IMGSIZE_QQVGA_V, DNN_COLOR); // 160*120画素のRGB888のBMPヘッダーの書き込み
// 画像データの書き込み
uint16_t* imgbuf_RGB565 = (uint16_t*)image_buffer;
if(CAMERA_UPSIDEDOWN == FALSE) {
for (int y = CAM_IMGSIZE_QQVGA_V-1; y >= 0; y--) {
for (int x = 0; x < CAM_IMGSIZE_QQVGA_H; x++) {
int n = y*CAM_IMGSIZE_QQVGA_H + x;
bmpFile.write((uint8_t)(imgbuf_RGB565[n] << 3) & 0x00f8); // 青
bmpFile.write((uint8_t)(imgbuf_RGB565[n] >> 3) & 0x00fc); // 緑
bmpFile.write((uint8_t)(imgbuf_RGB565[n] >> 8) & 0x00f8); // 赤
}
}
} else {
for (int y = 0; y < CAM_IMGSIZE_QQVGA_V; y++) {
for (int x = CAM_IMGSIZE_QQVGA_H-1; x >= 0 ; x--) {
int n = y*CAM_IMGSIZE_QQVGA_H + x;
bmpFile.write((uint8_t)(imgbuf_RGB565[n] << 3) & 0x00f8); // 青
bmpFile.write((uint8_t)(imgbuf_RGB565[n] >> 3) & 0x00fc); // 緑
bmpFile.write((uint8_t)(imgbuf_RGB565[n] >> 8) & 0x00f8); // 赤
}
}
}
bmpFile.close();
// AI学習用BMP画像ファイル(RGB24ビット)のSDカード保存
sprintf(filename, "DAT%03d.BMP", total_image_count);
theSD.remove(filename);
bmpFile = theSD.open(filename, FILE_WRITE);
writeBMPHeader(bmpFile, DNN_WIDTH, DNN_HEIGHT, DNN_COLOR); // 16*12画素のRGB888のBMPヘッダーの書き込み
// 画像データの書き込み
if(CAMERA_UPSIDEDOWN == FALSE) {
for (int y = CAM_IMGSIZE_QQVGA_V-1; y >= 0; y-=10) {
for (int x = 0; x < CAM_IMGSIZE_QQVGA_H; x+=10) {
int n = y*CAM_IMGSIZE_QQVGA_H + x;
bmpFile.write((uint8_t)(imgbuf_RGB565[n] << 3) & 0x00f8); // 青 CAM_IMGSIZE_QQVGA_H/DNN_WIDTH=10
bmpFile.write((uint8_t)(imgbuf_RGB565[n] >> 3) & 0x00fc); // 緑 CAM_IMGSIZE_QQVGA_V/DNN_HEIGHT=10
bmpFile.write((uint8_t)(imgbuf_RGB565[n] >> 8) & 0x00f8); // 赤
}
}
} else {
for (int y = 0; y < CAM_IMGSIZE_QQVGA_V; y+=10) {
for (int x = CAM_IMGSIZE_QQVGA_H-1; x >= 0 ; x-=10) {
int n = y*CAM_IMGSIZE_QQVGA_H + x;
bmpFile.write((uint8_t)(imgbuf_RGB565[n] << 3) & 0x00f8); // 青 CAM_IMGSIZE_QQVGA_H/DNN_WIDTH=10
bmpFile.write((uint8_t)(imgbuf_RGB565[n] >> 3) & 0x00fc); // 緑 CAM_IMGSIZE_QQVGA_V/DNN_HEIGHT=10
bmpFile.write((uint8_t)(imgbuf_RGB565[n] >> 8) & 0x00f8); // 赤
}
}
}
bmpFile.close();
putStringOnLCD(filename, 4, ILI9341_WHITE);
total_image_count++;
delay(1000);
}
投稿者の人気記事
-
eMoi-pic
さんが
2024/06/19
に
編集
をしました。
(メッセージ: 初版)
-
eMoi-pic
さんが
2024/06/19
に
編集
をしました。
-
eMoi-pic
さんが
2024/06/19
に
編集
をしました。
-
eMoi-pic
さんが
2024/06/19
に
編集
をしました。
ログインしてコメントを投稿する