PythonとArduinoで顔認識

今回は顔認識をやってみたのでまとめてみます。

PythonのOpenCVを使って顔認識を行い、その結果を使ってArduino側でインタラクティブな処理(LED点灯)を行うシステムです。

Python側とArduino側をそれぞれ解説していきます。

Python側

まずPython側のプログラム全体を載せます。

import os
import sys

import cv2
from PIL import Image
import serial

# シリアル通信のための設定
ser = serial.Serial()
ser.baudrate = 9600

# カメラ使う宣言
cap = cv2.VideoCapture(0)

# カスケード読み込む
cascade = cv2.CascadeClassifier("./cascade/haarcascade_frontalface_alt.xml")

# arduinoのポートを探して繋ぐ
for file in os.listdir('/dev'):
    if "cu.usbmodem" in file:
        ser.port = "/dev/" + file
        ser.open()

while True:
    # カメラから画像ゲット
    ret, frame = cap.read()
    # 認識用にグレースケールにする
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # ここで顔認識
    face_list = cascade.detectMultiScale(
        frame_gray,
        scaleFactor=1.1,
        minNeighbors=1,
        minSize=(100, 100)
    )

    # 顔があれば認識した箇所を囲む
    face_num = len(face_list)
    if face_num > 0:
        color = (0, 0, 255)
        for face in face_list:
            x, y, w, h = face
            cv2.rectangle(frame, (x, y), (x+w, y+h), color, thickness=3)

    cv2.imshow("frame", frame)

    ser.write(str(face_num).encode())
    
ser.close()

順番に解説していきます。まず初めに

import serial

の部分ですが、pySerialというライブラリを使用しています。

私の環境(macOS Sierra ver.10.12)では

pip install pyserial

ですんなり入りました。

続いてpySerialのインスタンスを生成します。baudrateは通信速度のようなもので、送り手と受け手で揃えておく必要があります。

# シリアル通信のための設定
ser = serial.Serial()
ser.baudrate = 9600

次で行なっているカメラの設定は見た通りなので省略して、カスケードの読み込みです。

# カスケード読み込む
cascade = cv2.CascadeClassifier("./cascade/haarcascade_frontalface_alt.xml")

カスケードは認識したい対象の特徴を表したようなものです。今回は正面から見た顔の特徴を使用します。

OpenCVをインストールした時に付いて来るようですが、今回はOpenCVのgithubからcloneしてきました(OpenCVがパソコン内のどこにあるのか探せませんでした…)。

cloneしてきたディレクトリの中の、dataというディレクトリの中にいろいろなカスケードが入っています。必要なものをカレントディレクトリにコピーするなりパスを覚えておくなりして、プログラム上で呼び出します。

Arduinoが接続しているポートを探します。USBを抜くと変わることがあるので、自動で探して接続するようにしています。

# arduinoのポートを探して繋ぐ
for file in os.listdir('/dev'):
    if "cu.usbmodem" in file:
        ser.port = "/dev/" + file
        ser.open()

続くwhile文(24行目から)の中では、初めにカメラから画像を取得してグレースケールにしています。特に解説するところもないので省略します。

次に顔認識をして、検出した顔の数を数えています。

# ここで顔認識
face_list = cascade.detectMultiScale(
    frame_gray,
    scaleFactor=1.1,
    minNeighbors=1,
    minSize=(100, 100)
)

パラメーターをいじると少し認識の精度が変わってくるのですが、どういじればいいかは私もまだよくわかってません。

続いて検出した顔があれば赤枠で囲むなどの処理をしています(39行目から)。

最後に検出した顔の数をシリアル通信でArduino側に送っています。

ser.write(str(face_num).encode())

Arduino側

こちらも初めに全体を載せます。

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

void loop() {
    int inputchar;
    inputchar = Serial.read();

    if(inputchar != -1) {
        switch(inputchar) {
          case '0':
              digitalWrite(13, LOW);
              break;
          default:
              digitalWrite(13, HIGH);
        }
    } else {
      
    }
}

とはいえこちらでは特に変わった処理はしておらず、

inputchar = Serial.read();

で受け取った値に応じてLEDをつけたり消したりしているだけです。

おわりに

これでPythonとArduinoの間で情報をやり取りできるようになりました。Pythonで機械学習を行なって、その結果に応じてArduinoに様々な処理をさせることができます。

しかし本来は、Arduinoに搭載したセンサー等の値をPython側で受け取る方が使い道があるんじゃないかな?とも思ってます。IoT的な感じで。それもいずれ公開すると思っているのでお楽しみに。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする