RaspberryPi
初心者です。
RaspberryPi
、カメラ、サーボモーターを用いて、顔追跡を行います。
@PonDadさんの記事を参考にさせていただきました。@PonDadさんありがとうございます。
Raspberry Pi サーボモーターとOpen CVで顔追跡カメラ(Haar-like)
しかし、自分の環境では、@PonDadさんの記事どおりではうまく動作しなかったため、face_tracking.py
を以下のとおり変更しています。
#環境
- Raspberry Pi3 (RASPBIAN JESSIE WITH PIXEL 4.4/ Python 3.4.2)
- Open CV 3.1.0
- LOGICOOL ウェブカム HD画質 120万画素 C270
- PCA9685 16Channel 12bit PWM(Adafruit 16-Channel Servo Driver互換品)
- SG90サーボ用 2軸 カメラマウント
- ラズパイ用電源とは別にサーボ用の電源としてDCアダプター(5V 2A)をPCA9685へ接続
- コードを実行するためには @PonDadさんの記事で紹介されている
PCA9685.py
が必要です。
#概要
OpenCV
のHaar-like特徴分類器
を使って顔認識します。
haarcascade_frontalface_alt.xml
を利用した顔認識を使うと、cascade.detectMultiScale()
メソッドを利用して顔の範囲を表す座標を取得する事が出来ます。
この座標から顔の中心点の座標を計算し、ストリーミング画面の中心点と顔の中心点の差が減る方向へ、サーボモータでカメラを移動します。この動作を繰り返すことによって、カメラが顔を追跡するようにします。
#コードの変更点
@PonDadさんの記事からの変更点
- line15
cap.set(4, 320)
からcap.set(4, 240)
に変更した。デスクトップ上に表示されるストリーミング画像のウィンドウサイズを320*240にした。 - line18から21を追加した。コードを実行する毎にカメラの向きを初期値に戻すため。サーボ2個ともニュートラルである375( Min150~Max600なので
(150+600)/2=375
)へ移動。 - line23 この行をwhile文の前に出した。
- line27
now_degree_x
とnow_degree_y
をサーボのニュートラルである375に変更。 - line33から34
*0.4
を*0.06
に変更した。掛算の値をいろいろ変更していちばん動きが良かった値に変更した。この部分は試行錯誤の結果で適当に決めた。値が大きいほど早く動くが大きすぎると行き過ぎる。自分の環境では0.04から0.06くらいが良い感じ。 - line34 160を120に変更した。line15の変更に伴い、ストリーミング画像の中心点(=240/2)を変更した。
- line38
time.sleep(0.1)
は無くても支障が無かったためコメントアウト。 - line39から40
now_degree_x = move_degree_x
とnow_degree_y = move_degree_y
に変更した。
#コード
face_tracking2.py
# -*- coding: UTF-8 -*-
import cv2
import os
import time
import Adafruit_PCA9685
pwm = Adafruit_PCA9685.PCA9685()
pwm.set_pwm_freq(60)
cascade_path = "haarcascade_frontalface_alt.xml"
cascade = cv2.CascadeClassifier(cascade_path)
cap = cv2.VideoCapture(0)
cap.set(3, 320)
cap.set(4, 240)
color = (255, 255, 255)
pwm.set_pwm(0, 0, 375)
time.sleep(1)
pwm.set_pwm(1, 0, 375)
time.sleep(1)
now_degree_x, now_degree_y, move_degree_x, move_degree_y = 375, 375, 0, 0
while(True):
ret, frame = cap.read()
facerect = cascade.detectMultiScale(frame, scaleFactor=1.2, minNeighbors=2, minSize=(10, 10))
for rect in facerect:
img_x = rect[0]+rect[2]/2
img_y = rect[1]+rect[3]/2
print(img_x, img_y)
move_degree_x = now_degree_x - (img_x-160)*0.06
move_degree_y = now_degree_y + (img_y-120)*0.06
print('deg: ', move_degree_x , move_degree_y)
pwm.set_pwm(0, 0, int(move_degree_x))
pwm.set_pwm(1, 0, int(move_degree_y))
#time.sleep(0.1)
now_degree_x = move_degree_x
now_degree_y = move_degree_y
cv2.circle(frame, (int(img_x), int(img_y)), 10, (255,255,255), -1)
cv2.rectangle(frame, tuple(rect[0:2]),tuple(rect[0:2] + rect[2:4]), color, thickness=3)
cv2.imshow("Show FLAME Image", frame)
k = cv2.waitKey(1)
if k == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
#感想など
顔追跡のためのサーボ制御がなかなかうまくいかず、試行錯誤しながら上記のコードを変更しました。
プログラミングのことが全くわからない初心者なので、間違えが沢山あるかもしれません。どなたかご指摘いただけるとありがたいです。
python face_tracking2.py
だとpython2
で動作してしまうため、 python3 face_tracking2.py
で実行しています。