23
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Raspberry Pi OpenCVで顔検出しサーボでトラッキング

Posted at

#はじめに
Aliexpressからカメラのパン/チルト雲台が届いたので、OpenCVで顔検出しサーボで顔をトラッキングするシステムを作成してみることにした。

DSD_2002.JPG

#用意するもの
##Raspberry Pi 1 Model B
2014年の古いラズパイです。能力がぜんぜん足りず8秒ほど遅延してしまう結果となりました。最新なら問題なくリアルタイム処理できそうです。
##サーボ駆動カメラ雲台
Aliexpressで購入。ST90サーボ2個つきでUS$5.89でした。
1set-Nylon-FPV-Pan-tilt-Camera-Mount-2pcs-SG90-9g-Servo-Retail-Promotion-Dropship-Free-Shipping.jpg
##16ch サーボドライバ
NXP社のPCA9685を使用した16×12-bit PWM制御基板です。I2Cで通信&制御できます。Aliexpressで購入。Adafruitのドライバが使用できます。

PCA9685.jpg
##USBカメラ
手持ちのドライブレコーダを使用しました。USBで接続するとPCモードになり、ドライバ無しでUSBカメラとして機能しました。
##3.5inch LCD
ラズパイ用として販売されている3.5inch LCD、タッチパネル付きです。26ピンコネクタが付いており、ラズパイのGPIOピンに差せばモニタ兼タッチパネルとして動作してくれます。ラズパイとはSPI通信しています。

LCD.jpg

#下準備1 - まずは顔認識してみる
RaspberryPiとOpenCVで顔認識してパフォーマンスも改善してみる
こちらを参考にしています。
takusenoさま、ありがとうございました。

##Setup
OpenCVのライブラリをインストールします。下記shellにて実行しました。

sudo apt-get install libopencv-dev
sudo apt-get install python-opencv
wget http://eclecti.cc/files/2008/03/haarcascade_frontalface_alt.xml

##OpenCVで顔認識してみる
USBCAMを接続します。接続するだけです。
##実行
下記Pythonコードを保存します。

usbcam.py
import cv2.cv as cv
import cv2

cv.NamedWindow("camera", 1)

capture = cv2.VideoCapture(0)
faceCascade = cv2.CascadeClassifier('haarcascade_frontalface_alt.xml')

while True:
    _, img = capture.read()
    img = cv2.resize(img, (320, 240))
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    faces = faceCascade.detectMultiScale(
        gray,
        scaleFactor=1.1,
        minNeighbors=3,
        minSize=(30, 30),
        flags=cv.CV_HAAR_SCALE_IMAGE
    )
    for (x, y, w, h) in faces:
        cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
    cv2.imshow("camera", img)
    if cv.WaitKey(10) > 0:
        break
cv.DestroyAllWindows()

##実行します。
LCD上でターミナルを起動し、下記実行します。

sudo python usbcam.py

DSD_1638.JPG

DSD_1644.JPG

認識してくれました。緑枠が認識された顔です。

#下準備2 - サーボ駆動してみる
##接続
ラズパイとPCA9685基板の接続は下記のとおり。

Raspberry Pi -- PCA9685
PIN3(SDA) -- SCA
PIN4(+5V) -- VCC
PIN5(SDL) -- SCL
PIN6(GND) -- GND
注意:PCA9685の"V+"ではなく**"VCC"**に接続すること。"VCC"はIC用の電源。"V+"はサーボ駆動用電源、そのためこちらは電流の取れる電源を別途供給必要。
###その他設定動作確認は下記先人の偉業を参考にしました
Raspberry Pi 3でPCA9685を使う
@ttyokoyamaさま、ありがとうございます!

##サンプルプログラム
下記実行し、サーボが動作することを確認します。ch0が水平、ch1が垂直用のサーボで、3秒ごとに移動します。
こちらはUSBカメラからの画像を表示する必要がない為、sshにてリモートから実行しても問題なく動作します。

servo.py
#!/usr/bin/python

import RPi.GPIO as GPIO
import time
import Adafruit_PCA9685

GPIO.setmode(GPIO.BOARD)


pwm = Adafruit_PCA9685.PCA9685()
pwm.set_pwm_freq(60)

sw1 = 0
sw2 = 0
try:
    while True:
        time.sleep(3)

        if sw1 == 1:
            pwm.set_pwm(1, 0, 600)
            sw1 = 0
        else:
            pwm.set_pwm(1, 0, 375)
            sw1 = 1

        if sw2 == 1:
            pwm.set_pwm(0, 0, 600)
            sw2 = 0
        else:
            pwm.set_pwm(0, 0, 375)
            sw2 = 1


except KeyboardInterrupt:
    pass

動作OK
DSD_1998.JPG

DSD_1999.JPG

#顔認識とサーボ駆動を連携してみる
##i2C配線の取り出し
###下調べ
i2Cの信号ピンは3番5番ピンなのですが、LCDのコネクタで塞がっています。
3.5 Inch 480x320 TFT Display with Touch Screen for Raspberry Pi
接続を調べてみると、i2Cで仕様する3番5番ピンはNCとなっていましたので、遠慮無く当該のPINに接続することにします。
Example1567.jpg

###信号の取り出し
PCBとLCDは両面テープでやっつけられているだけのようです。
DSD_1984.JPG

フレキシブルケーブルを痛めないよう注意しながら、両面テープを剥し、分離させます。
DSD_1986.JPG

コネクタのハンダ付け部分に4本のUEW線をハンダ付けします。UEW線はφ0.2mmのものを使用しています。UEW線はポリウレタンで被覆されており、ハンダ付けする箇所のみポリウレタンが溶けハンダ付けされます。このような箇所にハンダ付けするにぴったりな配線です。
DSD_1989.JPG

メスコネクタにUEW線をハンダ付けします。ピン番号も書いておきます。4番ピンは+5V線のため、不用意なショートを防ぐため、メスコネクタを使用しておきました。
DSD_1994.JPG

液晶が表示されること、i2Cを経由してサーボが動作することを確認してHWの改造は終了です。
DSD_1995.JPG

##顔認識させてサーボを動作させる
いよいよ本番です。顔認識した位置にサーボで雲台を向けてみます。

pwm.set_pwmにセットする値と角度の関係は
150~650 : 0 ~ 180deg
とのことです。画角等に応じてpwm.set_pwmに渡す引数を変更ください。

LCD上でターミナルを起動し、下記実行します。

sudo python sercam.py
sercam.py
import cv2.cv as cv
import cv2

#servo
import RPi.GPIO as GPIO
import time
import Adafruit_PCA9685

pwm = Adafruit_PCA9685.PCA9685()
pwm.set_pwm_freq(60)


GPIO.setmode(GPIO.BOARD)

cv.NamedWindow("camera", 1)

capture = cv2.VideoCapture(0)
faceCascade = cv2.CascadeClassifier('haarcascade_frontalface_alt.xml')

while True:
    _, img = capture.read()
    img = cv2.resize(img, (320, 240))
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    faces = faceCascade.detectMultiScale(
        gray,
        scaleFactor=1.1,
        minNeighbors=3,
        minSize=(30, 30),
        flags=cv.CV_HAAR_SCALE_IMAGE
    )
    for (x, y, w, h) in faces:
        cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
        #pulse = 150~650 : 0 ~ 180deg
        pwm.set_pwm(0, 0, 400 - (x+w)/2)	# h
        pwm.set_pwm(1, 0, 400 - (y+h)/2)	# v
    cv2.imshow("camera", img)
    if cv.WaitKey(10) > 0:
        break
cv.DestroyAllWindows()

#動いたぞ!
Googleから顔写真を探してきて、写真をモニタ上で移動してみた。実際には写真の位置を移動させてから8秒ほどタイムラグが有ったすえに検出、サーボ動作している。反応が悪いが昔のラズパイだということで納得はしている。
move.gifundefined

#Special thanks!
参考にしたサイトです。ありがとうございます!
Raspberry Pi 3でPCA9685を使う
RaspberryPiとOpenCVで顔認識してパフォーマンスも改善してみる
3.5 Inch 480x320 TFT Display with Touch Screen for Raspberry Pi

2018/01/28 Ikeda

23
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?