カメラに人が写り込んだらLEDを光らせる

はじめに

  1. 【MXNet】写真に写っている人を数える(Faster RCNN resnet101を用いた物体検出) - パソコン関連もろもろ
  2. 【MXNet】物体検出(detect only one class) - パソコン関連もろもろ
  3. 【Realtime Object Detection】動画に対して物体検出(ssd_512_mobilenet1.0) - パソコン関連もろもろ

上の3つで習得したものを組み合わせて、人を検出したらLEDが光るシステムを作ってみた。
超音波センサー?赤外線センサー?いやいやどちらも違います。
深層学習を用いた物体検出です。
メリットとして人以外の動物に反応しない。プログラムを変更すれば犬には反応して猫には反応しないなどが可能。
Webカメラの画像をPCで受信。そのPCで画像に対して学習済みモデルを適応し、ArduinoにLEDのon、offの命令を送っている。

環境

Windows10 Pro
NVIDIA GeForce GTX1080
Python 3.7.7
Arduino IDE 1.8.12
Arduino Uno R3

バージョン確認(pip freeze)

インストールが必要なのは「mxnet-cu101]と「gluoncv」と「opencv-python」と「pyserial」のみ。

pip install https://repo.mxnet.io/dist/python/cu101/mxnet_cu101-1.6.0-py2.py3-none-win_amd64.whl
pip install gluoncv
pip install opencv-python
pip install pyserial

その他は勝手についてくる。

certifi==2020.4.5.1
chardet==3.0.4
cycler==0.10.0
gluoncv==0.7.0
graphviz==0.8.4
idna==2.6
kiwisolver==1.2.0
matplotlib==3.2.1
mxnet-cu101 @ https://repo.mxnet.io/dist/python/cu101/mxnet_cu101-1.6.0-py2.py3-none-win_amd64.whl      
numpy==1.16.6
opencv-python==4.2.0.34
Pillow==7.1.2
portalocker==1.7.0
pyparsing==2.4.7
pyserial==3.4
python-dateutil==2.8.1
pywin32==227
requests==2.18.4
scipy==1.4.1
six==1.14.0
tqdm==4.46.0
urllib3==1.22

Pythonコード

import mxnet as mx
import gluoncv

import serial, time

import cv2

ctx = mx.gpu()
# Load the model
net = gluoncv.model_zoo.get_model('ssd_512_resnet50_v1_voc', pretrained=True, root='./model', ctx=ctx)
net.reset_class(["person"], reuse_weights=['person'])
# Compile the model for faster speed
net.hybridize()

# Load the webcam handler
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
# letting the camera autofocus
time.sleep(1)

ser =serial.Serial("COM3", 9600)

while(True):
    # Load frame from the camera
    ret, frame = cap.read()

    # Image pre-processing
    frame = mx.nd.array(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)).astype('uint8')
    rgb_nd, frame = gluoncv.data.transforms.presets.ssd.transform_test(frame, short=512, max_size=700)
    # Run frame through network
    class_IDs, scores, bounding_boxes = net(rgb_nd.as_in_context(ctx))

    n_box = class_IDs.shape[1]
    count = 0
    for n in range(n_box):
        if(scores[0][n].asscalar()>0.8):
            count += 1
    
    if(count==0):
        ser.write(b'0')
    else:
        ser.write(b'1')

    # Display the result
    img = gluoncv.utils.viz.cv_plot_bbox(frame, bounding_boxes[0], scores[0], class_IDs[0], class_names=net.classes, thresh=0.8)
    gluoncv.utils.viz.cv_plot_image(img)

    time.sleep(0.2)

    # escを押したら終了
    if cv2.waitKey(1) == 27:
        break
    
ser.write(b'0')
ser.close()
cap.release()
cv2.destroyAllWindows()

Arduinoスケッチ

void setup() {
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW); 
}

void loop() {
  byte var;
  var = Serial.read();
  
  switch(var){
    case '0':
      digitalWrite(13, LOW);
      break;
    case '1':
      digitalWrite(13, HIGH);
      break;
    default:
      break;
  }                     
}