初めに
Spresenseを使って、「赤丸とか緑丸とかを判断したい」んだけど、と相談されたので、
ソニーの太田さんの本にあるSementic segmentationを使って認識させようと思ったんだけど、
もっと手軽にやって欲しいとのことなので、簡単に中心部の色だけを判断するコードを書いてみました。
用意するもの
SpresenseはMainボードとカメラボードのみです!
SPRESENSEメインボード[CXD5602PWBMAIN1]
SPRESENSE HDRカメラボード[CXD5602PWBCAM2W]
小さく作れます!
ブログ(元ネタ)
この記事は、以下のブログにあるものです。
ソースコード
Spresense Arduino の Camera Sampleを使って作ってみます。
基本、CamCBを使って、常時、小さい画像を取り込みながら、
真ん中部分の色が、赤、黄色、緑の範囲に入っているか?を見るというサンプルになります。
なので、loopでは、秒に1回結果を表示するだけ。
switch(current_color){
case DETECT_RED:
Serial.println("Detect Red!");
break;
case DETECT_YELLOW:
Serial.println("Detect Yellow!");
break;
case DETECT_GREEN:
Serial.println("Detect Green!");
break;
case DETECT_NONE:
default:
break;
}
sleep(1);
CamCBでは、320x240で撮りこまれた画像を、真ん中の96x96だけ切り出し1/8にする。
#define OFFSET_X (112)
#define OFFSET_Y (72)
#define CLIP_WIDTH (96)
#define CLIP_HEIGHT (96)
#define DETECT_WIDTH (12)
#define DETECT_HEIGHT (12)
if (!img.isAvailable()) return;
// HWでの画像の切り出しと縮小
CamImage small;
CamErr camErr = img.clipAndResizeImageByHW(small
,OFFSET_X ,OFFSET_Y
,OFFSET_X+CLIP_WIDTH-1 ,OFFSET_Y+CLIP_HEIGHT-1
,DETECT_WIDTH ,DETECT_HEIGHT);
RGBに変換して、色を検出。
// 画像をYUVからRGB565に変換
small.convertPixFormat(CAM_IMAGE_PIX_FMT_RGB565);
uint16_t* sbuf = (uint16_t*)small.getImgBuff();
int detect_red = 0;
int detect_yellow = 0;
int detect_green = 0;
for(int i=0;i<DETECT_WIDTH;i=i+2){
for(int j=0;j<DETECT_HEIGHT;j=j+2){
int k = i*DETECT_HEIGHT+j;
int red = (sbuf[k] >> 11) & 0x1F;
int green = (sbuf[k] >> 5) & 0x3F;
int blue = sbuf[k] & 0x1F;
// printf("sbuf[%d]=%04x,r=%02x,g=%02x,b=%02x\n",k,sbuf[k],red,green,blue);
if(detectRed(red,green,blue)) detect_red++;
if(detectYellow(red,green,blue)) detect_yellow++;
if(detectGreen(red,green,blue)) detect_green++;
}
}
それぞれの色の範囲は、detectRed
/detectYellow
/detectGreen
の中で調整。
全画素を見ずに、1つおきに見ることで処理を軽くして、閾値以上の色が見つかれば表示をしました。
本体のコードはこちらにあります。
Spresenseは、クリップと縮小、フォーマット変換が簡単にできるので、
この手のコードは楽に書けますよ!