twsのアイコン画像
tws 2022年09月26日作成 (2022年09月26日更新)
製作品 製作品 閲覧数 356
tws 2022年09月26日作成 (2022年09月26日更新) 製作品 製作品 閲覧数 356

SPRESENSEで背後の危険を察知する

SPRESENSEで背後の危険を察知する

概要

歩行者の背後の映像から急接近する自転車等を検出し、イヤホンから報知することで危険を知らせます。
SPRESENSEを利用してカメラ画像から差分を検出して、変化量が大きい場合に音を鳴らします。
自転車が背後から急接近してビックリすることが多く、なんとか事前に危険を察知しておきたい。
顔検知、自転車の検知、Optical Flow等を使うことが考えられますが、とりあえず連続したカメラ画像の差分を取り、差分の大きさで簡易的に検出しています。
現状は簡易的過ぎて反応しすぎたり、誤検知してしまいます。

部品

  • SPRESENSEメインボード
  • SPRESENSE拡張ボード
  • SPRESENSEカメラボード
  • SDカード
  • USBケーブル
  • モバイルバッテリー
  • リュックサックの肩紐に設置するケース

概略図

SPRESENSEを通常通り組み立て、モバイルバッテリーより電源供給します。
SDカードにはDSPファイルをインストールの上(チュートリアルの通り)、通知用のalarm.mp3を保存、SPRESENSEに挿しておいてください。

SPRESENSEはリュックサックの肩紐に設置して背後にカメラを向けます。
キャプションを入力できます

仮説

  • 歩行者の背後に向けカメラを設置。
  • 全部の歩行者を検知する必要はない。
  • 遠くのものは検知する必要はない。
  • 背景はあまり急には動かない(実際には歩行の上下運動や方向転換で結構動く)。
  • スピードを出している自転車(に限らず)により連続したカメラ画像間の差分が大きくなる。

ソースコード

SPRESENSEのコード

#include <Camera.h> #include <SDHCI.h> #include <Audio.h> SDClass theSD; AudioClass *theAudio; File myFile; #define BAUDRATE (115200) uint8_t image[CAM_IMGSIZE_QQVGA_H * CAM_IMGSIZE_QQVGA_V]; int bufno = 0; int alarmflg = 0; unsigned long prediff; void CamCB(CamImage img) { /* Check the img instance is available or not. */ if (img.isAvailable()) { uint16_t* imgbuf = (uint16_t*)img.getImgBuff(); if (bufno == 0) { for (int n = 0; n < CAM_IMGSIZE_QQVGA_H * CAM_IMGSIZE_QQVGA_V; n++) { image[n] = (uint8_t)(((imgbuf[n] & 0xf000) >> 8) | ((imgbuf[n] & 0x00f0) >> 4) & 0xff); } bufno++; } else { int diff = 0; for (int n = 0; n < CAM_IMGSIZE_QQVGA_H * CAM_IMGSIZE_QQVGA_V; n++) { uint8_t data = (uint8_t)(((imgbuf[n] & 0xf000) >> 8) | ((imgbuf[n] & 0x00f0) >> 4) & 0xff); diff = diff + abs(image[n] - data); } Serial.println((unsigned long)diff); if (prediff != 0 && diff / prediff > 2.4) { alarmflg = 1; } prediff = diff; bufno = 0; } } else { Serial.println("Failed to get video stream image"); } } void setup() { CamErr err; Serial.begin(BAUDRATE); while (!Serial) { ; /* wait for serial port to connect. Needed for native USB port only */ } Serial.println("Prepare camera"); err = theCamera.begin(2, CAM_VIDEO_FPS_120, CAM_IMGSIZE_QQVGA_H, CAM_IMGSIZE_QQVGA_V, CAM_IMAGE_PIX_FMT_YUV422); Serial.println("Start streaming"); err = theCamera.startStreaming(true, CamCB); Serial.println("Set Auto white balance parameter"); err = theCamera.setAutoWhiteBalanceMode(CAM_WHITE_BALANCE_DAYLIGHT); while (!theSD.begin()) { Serial.println("Insert SD card."); } theAudio = AudioClass::getInstance(); //theAudio->begin(audio_attention_cb); theAudio->begin(); theAudio->setRenderingClockMode(AS_CLKMODE_NORMAL); theAudio->setPlayerMode(AS_SETPLAYER_OUTPUTDEVICE_SPHP, AS_SP_DRV_MODE_LINEOUT); theAudio->initPlayer(AudioClass::Player0, AS_CODECTYPE_MP3, "/mnt/sd0/BIN", AS_SAMPLINGRATE_AUTO, AS_CHANNEL_STEREO); theAudio->setVolume(-160); } void loop() { if (alarmflg != 0) { theAudio->stopPlayer(AudioClass::Player0); myFile.close(); myFile = theSD.open("alarm.mp3"); theAudio->writeFrames(AudioClass::Player0, myFile); theAudio->startPlayer(AudioClass::Player0); bufno=0; prediff = 0; alarmflg = 0; } }

まとめ

簡易的な方法なので実用できず、もう少し歩行の動きに影響されないようにする必要がある。
せめて特徴量検出してカメラの動きを最小化した上で差分を取らないといけない。
Optical Flow、Deep Learningを使った方法も試してみたい。

ログインしてコメントを投稿する

投稿者の人気記事