要追蹤人臉就需要可以動的相機,這邊使用的是 露天 買的二軸雲台,使用兩個 SG90 伺服馬達來帶動雲台。

RPi_Face_Detect_SG90.jpg

馬達由 Raspberry Pi 供給 5VDC,並使用 GPIO pin 控制角度,Python 控制 Servo 的方法,參考 http://www.toptechboy.com/raspberry-pi/raspberry-pi-lesson-28-controlling-a-servo-on-raspberry-pi-with-python/ 這篇專業文... 剛剛發現 這一篇 文章跟我做類似的事情... 我的接線圖,如下:

RPi_Face_Detect_SG90_02.jpg

基本上 SG90 這顆便宜馬達的公差還滿大的,因此建議對每一顆馬達做範圍校正,先抓出最大和最小的 DutyCycle,盡量避免 Raspberry Pi 輸出超過範圍的 DutyCycle,這樣馬達很容易燒壞的。下面這一段 code 主要就是在做校正。手動輸入 DutyCycle,看馬達的反應...

#!/usr/bin/env python
# -*- coding: utf-8 -*- 
import time
import datetime
import sys

import RPi.GPIO as GPIO

def initGPIO():
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(12, GPIO.OUT)
    GPIO.cleanup()
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(12, GPIO.OUT)

class servoSG90():
    def __init__(self, GPIO_Pin=12, PWM_Freq=50, dc0=5, dc100=10):
        self.dc0 = dc0
        self.dc100 = dc100
        self.pwm_now = 50
        self.deg_now = 90
        self.pwm_gpio = GPIO_Pin
        self.pwm_freq = PWM_Freq
        
        self.servo = GPIO.PWM(GPIO_Pin,50)
        self.servo.start( (self.dc0+self.dc100)/2 )
        self.setPWM( self.pwm_now )
        time.sleep(1)
    
    def setPWM(self, pwm):    ## Range 0 - 100
        if pwm > self.pwm_now:
            pwm_step = 5
        elif pwm < self.pwm_now:
            pwm_step = -5
        else:
            return
        for pwm_new in range(self.pwm_now, int(pwm), pwm_step):
            dc_new = round( ( self.dc100 - self.dc0 )/100*pwm_new + self.dc0 ,1)
            if dc_new > self.dc100:
                dc_new = self.dc100
            elif dc_new < self.dc0:
                dc_new = self.dc0
            self.servo.ChangeDutyCycle( dc_new )
            print(" --- Change PWM Steping... %d - %.1f"%(pwm_new, dc_new) )
            time.sleep(.1)
        self.pwm_now = int(pwm_new)
        
    def setDutyCycle(self, dc):
        self.servo.ChangeDutyCycle( dc )
        time.sleep(0.2)
        
    def stop(self):
        self.servo.ChangeDutyCycle( 7 )
        time.sleep(1)
        self.servo.stop()
        
def testServo1(servo):
    for x in range(50,100,2):
        pwm = float(x)/10
        print("Current Location %.1f ..." %(pwm))
        servo.setDutyCycle(pwm)
        time.sleep(.1)
       
def testServo2(servo):
    print("\n\n --- Test Servo ---\n\tPress 'q' to exit test mode...\n\tPress 'dc0' to set Min DutyCycle...\n\tPress 'dc100' to set Max DutyCycle...\n")
    dc_old = '5.0'
    while True:
        dc_raw = raw_input("Please enter raw pwm value (%s): "%dc_old)
        if 'dc0' in dc_raw:
            print("Set DC-0 as %s"%dc_old )
            servo.dc0 = float(dc_old)
        elif 'dc100' in dc_raw:
            print("Set DC-100 as %s"%dc_old )
            servo.dc100 = float(dc_old)
        elif dc_raw.lower() in 'quit, q':
            return
        else:
            dc_old = dc_raw
            servo.setDutyCycle(float(dc_old))
            #time.sleep(1)

def testServo3(servo):
    for i in range(2):
        for x in range(100):
            pwm = int(x)
            print("Change PWM to %d ..." %(pwm))
            servo.setPWM(pwm)
            time.sleep(.1)
    print("\n --- Test-3 Stop --- ")
    servo.setPWM(50)
    time.sleep(1)

def main():
    initGPIO()
    servo1 = servoSG90(12, 50, 5, 10.)        ## 建立馬達 instant,DutyCycle範圍是 5 ~ 10.
    
    testServo1(servo1)    ## 測試一:讓馬達由最小 DutyCycle 轉到最大 DutyCycle
    testServo2(servo1)    ## 測試二:手動輸入 DutyCycle,確認馬達的 DutyCycle 範圍
    testServo3(servo1)    ## 測試三:讓馬達由新的最小 DutyCycle 轉到最大 DutyCycle
    
    servo1.stop()
    

if __name__ == "__main__":
    main()
    GPIO.cleanup()
    sys.exit()

 


說完雲台的部分,再來講相機... 我用的是 PiCamera,OpenCV沒有直接支援它,需要另外裝 PiCamera 的 Python module,Google一下,有很多人分享怎麼用 Python + OpenCV + PiCamera,我主要參考 這一篇,另外 這一篇 也不錯... 幸好安裝不難...

    pi@rpi:~ $ workon cv

(cv) pi@rpi:~ $ sudo pip install "picamera[array]"

##  安裝 PiCamera 的重點是... 要加參數 [array] ,這樣才可以把照片餵給 OpenCV

再來就是測試 PiCamera了,測試 Code 如下:

(cv) pi@rpi:~ $ nano picam.py

#!/usr/bin/env python
# import the necessary packages
from picamera.array import PiRGBArray
from picamera import PiCamera
import cv2
import time
import sys

def initPiCamera():
    # initialize the camera and grab a reference to the raw camera capture
    camera = PiCamera()
    camera.resolution = (640, 480)
    camera.framerate = 32
    camera.hflip = False
    camera.vflip = False    # True
    rawCapture = PiRGBArray(camera, size=(640, 480))
     
    # allow the camera to warmup
    time.sleep(1)
    return(camera, rawCapture)

def main():
    (camera, rawCapture) = initPiCamera()
    i, t0, t1 = 0, time.time(), time.time()
    # capture frames from the camera
    for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
        # grab the raw NumPy array representing the image, then initialize the timestamp
        # and occupied/unoccupied text
        image = frame.array
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        
        # show the frame
        cv2.imshow("Detect Face - Press 'q' to stop", image)
        key = cv2.waitKey(1) & 0xFF
     
        # clear the stream in preparation for the next frame
        rawCapture.truncate(0)
     
        # if the `q` key was pressed, break from the loop
        if key == ord("q"):
            rawCapture.truncate(0)
            cv2.destroyAllWindows()
            print("\n\n --- Test PiCamera Done --- " )
            break
        
        i += 1
        if i == 50:
            print("\n PiCamera FPS : %.1f"%(50/(time.time() - t1)) )
            i, t1 = 0, time.time()
    
if __name__ == "__main__":
    main()
    sys.exit()

(cv) pi@rpi:~ $ python picam.py

 PiCamera FPS : 7.2

 PiCamera FPS : 7.1

測試了一下,雖然我設定 32 framerate,但是實際上 OpenCV 由 PiCamera 抓出影像,再顯示在視窗上,只有 7.1 FPS。


下一篇:人臉追蹤相機-初體驗

arrow
arrow
    文章標籤
    Raspberry Pi Python
    全站熱搜
    創作者介紹
    創作者 Webb 的頭像
    Webb

    我的Maker之路

    Webb 發表在 痞客邦 留言(0) 人氣()