本帖最后由 云天 于 2022-5-23 21:36 编辑  
 
    
 
【项目设计】 
已经掌握了行控板与micro:bit扩展板的结合的使用方法,那么扩展板上的舵机引脚就可以驱动摄像头云台。 
Mediapipe获取人脸中心坐标,通过滤波算法使用得数据不频繁抖动。通过PID算法,控制舵机运行,追踪人脸。 
【控制舵机】 
microbit_motor.py文件可从Pinpong库中找到,上传到行空板中,应与主文件在同一个文件夹内。 
  
 
			
			
			- 
 - # -*- coding: utf-8 -*-
 - import time
 - from pinpong.board import Board
 - from microbit_motor import Microbit_Motor #导入Microbit_Motor库
 - 
 - Board("microbit").begin()  #初始化,选择板型和端口号,不输入端口号则进行自动识别
 - #Board("microbit","COM36").begin()  #windows下指定端口初始化
 - #Board("microbit","/dev/ttyACM0").begin()   #linux下指定端口初始化
 - #Board("microbit","/dev/cu.usbmodem14101").begin()   #mac下指定端口初始化
 - 
 - motorbit = Microbit_Motor()
 - 
 - while True:
 -    #舵机引脚S1-S8,角度范围0-180
 -    motorbit.servo(motorbit.S2, 0)
 -    time.sleep(1)
 -    motorbit.servo(motorbit.S2, 90)
 -    time.sleep(1)
 -    motorbit.servo(motorbit.S2, 180)
 -    time.sleep(1)
 -    motorbit.servo(motorbit.S2, 90)
 -    time.sleep(1)
 
  复制代码
  
  
 
【行空板获取摄像头全屏】在行空板网页端使用Jupyter notebook,在终端使用:pip install cvzone,安装cvzone 
- 
 - import cvzone.FaceDetectionModule as face
 - import cv2
 - import numpy as np
 - import time
 - 
 - 
 - 
 - 
 - 
 - def main():
 -     cap = cv2.VideoCapture(0)
 -     cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
 -     cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)
 -     cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
 -     cv2.namedWindow('camera',cv2.WND_PROP_FULLSCREEN)    #窗口全屏
 -     cv2.setWindowProperty('camera', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)   #窗口全屏
 -     detector = face.FaceDetector()
 -     # For a 640x480 image center target is 320 and 240
 -  
 - 
 -     while True:
 -         success, img = cap.read()
 -         img, bboxs = detector.findFaces(img)
 -         if bboxs:
 -             x, y, w, h = bboxs[0]["bbox"]
 -             cx, cy = bboxs[0]["center"]
 -             xVal=cx
 -             yVal=cy
 -             cv2.putText(img, f'x:{xVal} , y:{yVal} ', (x, y - 100), cv2.FONT_HERSHEY_PLAIN, 3,
 -                         (255, 0, 0), 3)
 -         output_image = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)
 -         cv2.imshow("camera", output_image)
 -         cv2.waitKey(1)
 - 
 - 
 - if __name__ == "__main__":
 -     main()
 - 
 
  复制代码
  
【人脸中心数据滤波】 
使用的是“递推平均滤波法”: 
递推平均滤波法(又称滑动平均滤波法)  
方法:  把连续取N个采样值看成一个队列,遵循先进先出原则  队列的长度固定为N  每次采样到一个新数据放入队尾,并扔掉原来队首的一次数据.(先进先出原则)  把队列中的N个数据进行算术平均运算,就可获得新的滤波结果  N值的选取:流量,N=12;压力:N=4;液面,N=4~12;温度,N=1~4  
优点:  对周期性干扰有良好的抑制作用,平滑度高  适用于高频振荡的系统  
缺点:  灵敏度低  对偶然出现的脉冲性干扰的抑制作用较差  不易消除由于脉冲干扰所引起的采样值偏差  不适用于脉冲干扰比较严重的场合  比较浪费RAM   
 
- 
 - import cvzone.FaceDetectionModule as face
 - import cv2
 - import numpy as np
 - import time
 - 
 - 
 - 
 - 
 - 
 - def main():
 -     cap = cv2.VideoCapture(0)
 -     #cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
 -     #cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)
 -     #cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
 -     #cv2.namedWindow('camera',cv2.WND_PROP_FULLSCREEN)    #窗口全屏
 -     #cv2.setWindowProperty('camera', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)   #窗口全屏
 -     detector = face.FaceDetector()
 -     s=[0,0,0,0,0,0,0,0,0,0,0,0]
 -     while True:
 -         PTime = time.time()
 -         success, img = cap.read()
 -         img, bboxs = detector.findFaces(img)
 -         if bboxs:
 -             x, y, w, h = bboxs[0]["bbox"]
 -             cx, cy = bboxs[0]["center"]
 -             xVal=cx
 -             yVal=cy
 -             cv2.putText(img, f'x:{xVal} , y:{yVal} ', (x, y - 100), cv2.FONT_HERSHEY_PLAIN, 3,
 -                         (255, 0, 0), 3)
 -         #output_image = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)
 -             s.pop(0)
 -             s.append(cx)
 -             mean=int(np.mean(s))
 -             cv2.putText(img, f'x:{mean} , y:{yVal} ', (x, y - 50), cv2.FONT_HERSHEY_PLAIN, 3,
 -                         (255, 0, 0), 3)
 -         fps = 1 / (time.time() - PTime)
 -         cv2.putText(img, f'FPS: {int(fps)}', (20,50), cv2.FONT_HERSHEY_PLAIN,
 -                             3, (255, 255, 0), 3)
 -         cv2.imshow("camera", img)
 -         cv2.waitKey(1)
 -         
 - 
 - if __name__ == "__main__":
 -     main()
 - 
 
  复制代码
  
  
【PID控制水平舵机】 
 
- 
 - import cvzone.FaceDetectionModule as face
 - import cv2
 - import numpy as np
 - import time
 - from pinpong.board import Board
 - from microbit_motor import Microbit_Motor #导入Microbit_Motor库
 - 
 - Board("microbit").begin()
 - motorbit = Microbit_Motor()
 - targetVal=0
 - pError=0
 - pTime=0
 - pidVals=[0.03,0,0.01]
 - I=0
 - jd_x=90
 - def pid(cVal):
 -         global I,pidVals,pTime,pError,targetVal
 -         # Current Value - Target Value
 -         t = time.time() - pTime
 -         error = cVal - targetVal
 -         P = pidVals[0] * error
 -         I = I + (pidVals[1] * error * t)
 -         D = (pidVals[2] * (error - pError)) / t
 - 
 -         result = P + I + D
 - 
 -         
 -         pError = error
 -         ptime = time.time()
 - 
 -         return result
 - 
 - 
 - 
 - def main():
 -     global ptime,jd_x
 -     cap = cv2.VideoCapture(0)
 -     cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
 -     cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)
 -     cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
 -     cv2.namedWindow('camera',cv2.WND_PROP_FULLSCREEN)    #窗口全屏
 -     cv2.setWindowProperty('camera', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)   #窗口全屏
 -     detector = face.FaceDetector()
 -     s=[0,0,0,0,0,0]
 -     ptime = time.time()
 -     motorbit.servo(motorbit.S2,jd_x)
 -     pre_jd_x=0
 -     while True:
 -         PTime = time.time()
 -         success, img = cap.read()
 -         img, bboxs = detector.findFaces(img)
 -         if bboxs:
 -             x, y, w, h = bboxs[0]["bbox"]
 -             cx, cy = bboxs[0]["center"]
 -             xVal=cx
 -             yVal=cy
 -             cv2.putText(img, f'x:{xVal} , y:{yVal} ', (x, y - 100), cv2.FONT_HERSHEY_PLAIN, 3,
 -                         (255, 0, 0), 3)
 -         
 -             s.pop(0)
 -             s.append(cx)
 -             mean=int(np.mean(s))
 -             jd_x=jd_x+int(pid(160-mean))
 -             if jd_x<1:
 -                 jd_x=1
 -             if jd_x>179:
 -                 jd_x=179
 -             print(jd_x)
 -             if pre_jd_x !=jd_x:
 -               pre_jd_x =jd_x
 -               motorbit.servo(motorbit.S2,jd_x)
 -             cv2.putText(img, f'x:{mean} , y:{yVal} ', (x, y - 50), cv2.FONT_HERSHEY_PLAIN, 3,
 -                         (255, 0, 0), 3)
 -         fps = 1 / (time.time() - PTime)
 -         cv2.putText(img, f'FPS: {int(fps)}', (20,50), cv2.FONT_HERSHEY_PLAIN,
 -                             3, (255, 255, 0), 3)
 -         output_image = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)                    
 -         cv2.imshow("camera", output_image)
 -         cv2.waitKey(1)
 -         
 - 
 - if __name__ == "__main__":
 -     main()
 - 
 
  复制代码
  
【使用PID类控制水平】 
- 
 - import cvzone.FaceDetectionModule as face
 - import cv2
 - import numpy as np
 - import time
 - from pinpong.board import Board
 - from microbit_motor import Microbit_Motor #导入Microbit_Motor库
 - 
 - Board("microbit").begin()
 - motorbit = Microbit_Motor()
 - targetVal=0
 - pError=0
 - pTime=0
 - pidVals=[0.03,0,0.01]
 - I=0
 - jd_x=90
 - class PID:
 -     def __init__(self, pidVals, targetVal,  limit=None):
 -         self.pidVals = pidVals
 -         self.targetVal = targetVal
 -         self.pError = 0
 -         self.limit = limit
 -         self.I = 0
 -         self.pTime = 0
 -     def update(self,cVal):
 -         
 -         # Current Value - Target Value
 -         t = time.time() - self.pTime
 -         error = cVal - self.targetVal
 -         P = self.pidVals[0] * error
 -         self.I = self.I + (self.pidVals[1] * error * t)
 -         D = (self.pidVals[2] * (error - self.pError)) / t
 - 
 -         result = P + self.I + D
 -         if self.limit is not None:
 -             result = float(np.clip(result, self.limit[0], self.limit[1]))
 -         
 -         self.pError = error
 -         self.ptime = time.time()
 - 
 -         return result
 - 
 - 
 - 
 - def main():
 -     
 -     cap = cv2.VideoCapture(0)
 -     cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
 -     cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)
 -     cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
 -     cv2.namedWindow('camera',cv2.WND_PROP_FULLSCREEN)    #窗口全屏
 -     cv2.setWindowProperty('camera', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)   #窗口全屏
 -     detector = face.FaceDetector()
 -     s_x=[0,0,0,0,0,0]
 -     jd_x=90
 -     pre_jd_x=0
 -     motorbit.servo(motorbit.S2,jd_x)
 -     xPID = PID([0.03, 0.000000000001, 0.01], 320 // 2,  limit=[-90, 90])
 -     while True:
 -         PTime = time.time()
 -         success, img = cap.read()
 -         img, bboxs = detector.findFaces(img)
 -         if bboxs:
 -             x, y, w, h = bboxs[0]["bbox"]
 -             cx, cy = bboxs[0]["center"]
 -             xVal=cx
 -             yVal=cy
 -             cv2.putText(img, f'x:{xVal} , y:{yVal} ', (x, y - 100), cv2.FONT_HERSHEY_PLAIN, 3,
 -                         (255, 0, 0), 3)
 -         
 -             s_x.pop(0)
 -             s_x.append(cx)
 -             mean_x=int(np.mean(s_x))
 -             
 -             xVal= int(xPID.update(mean_x))
 -             jd_x=jd_x-xVal
 -             print(jd_x)
 -             if pre_jd_x !=jd_x:
 -               pre_jd_x =jd_x
 -               motorbit.servo(motorbit.S2,jd_x)
 -             cv2.putText(img, f'x:{mean_x} , y:{yVal} ', (x, y - 50), cv2.FONT_HERSHEY_PLAIN, 3,
 -                         (255, 0, 0), 3)
 -         fps = 1 / (time.time() - PTime)
 -         cv2.putText(img, f'FPS: {int(fps)}', (20,50), cv2.FONT_HERSHEY_PLAIN,
 -                             3, (255, 255, 0), 3)
 -         output_image = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)                    
 -         cv2.imshow("camera", output_image)
 -         cv2.waitKey(1)
 -         
 - 
 - if __name__ == "__main__":
 -     main()
 - 
 
  复制代码 【控制水平和垂直舵机】 
- 
 - import cvzone.FaceDetectionModule as face
 - import cv2
 - import numpy as np
 - import time
 - from pinpong.board import Board
 - from microbit_motor import Microbit_Motor #导入Microbit_Motor库
 - 
 - Board("microbit").begin()
 - motorbit = Microbit_Motor()
 - targetVal=0
 - pError=0
 - pTime=0
 - pidVals=[0.03,0,0.01]
 - I=0
 - jd_x=90
 - class PID:
 -     def __init__(self, pidVals, targetVal,  limit=None):
 -         self.pidVals = pidVals
 -         self.targetVal = targetVal
 -         self.pError = 0
 -         self.limit = limit
 -         self.I = 0
 -         self.pTime = 0
 -     def update(self,cVal):
 -         
 -         # Current Value - Target Value
 -         t = time.time() - self.pTime
 -         error = cVal - self.targetVal
 -         P = self.pidVals[0] * error
 -         self.I = self.I + (self.pidVals[1] * error * t)
 -         D = (self.pidVals[2] * (error - self.pError)) / t
 - 
 -         result = P + I + D
 -         if self.limit is not None:
 -             result = float(np.clip(result, self.limit[0], self.limit[1]))
 -         
 -         self.pError = error
 -         self.ptime = time.time()
 - 
 -         return result
 - 
 - 
 - 
 - def main():
 -     
 -     cap = cv2.VideoCapture(0)
 -     cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
 -     cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)
 -     cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
 -     cv2.namedWindow('camera',cv2.WND_PROP_FULLSCREEN)    #窗口全屏
 -     cv2.setWindowProperty('camera', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)   #窗口全屏
 -     detector = face.FaceDetector()
 -     s_x=[0,0,0,0,0,0]
 -     s_y=[0,0,0,0,0,0]
 -     jd_x=90
 -     jd_y=135
 -     pre_jd_y=0
 -     motorbit.servo(motorbit.S1,jd_y)
 -     xPID = PID([0.03, 0.000000000001, 0.01], 320 // 2,  limit=[-90, 90])
 -     yPID = PID([0.03, 0.000000000001, 0.01], 240 // 2,  limit=[-45, 45])
 -     while True:
 -         PTime = time.time()
 -         success, img = cap.read()
 -         img, bboxs = detector.findFaces(img)
 -         if bboxs:
 -             x, y, w, h = bboxs[0]["bbox"]
 -             cx, cy = bboxs[0]["center"]
 -             xVal=cx
 -             yVal=cy
 -             cv2.putText(img, f'x:{xVal} , y:{yVal} ', (x, y - 100), cv2.FONT_HERSHEY_PLAIN, 3,
 -                         (255, 0, 0), 3)
 -         
 -             s_x.pop(0)
 -             s_y.pop(0)
 -             s_x.append(cx)
 -             s_y.append(cy)
 -             mean_x=int(np.mean(s_x))
 -             mean_y=int(np.mean(s_y))
 -             xVal= int(xPID.update(mean_x))
 -             yVal= int(yPID.update(mean_y))
 - 
 - 
 -             jd_x=jd_x-xVal
 -             jd_y=jd_y-yVal
 -             print(jd_x,jd_y)
 -             if pre_jd_x !=jd_x:
 -               pre_jd_x =jd_x
 -               motorbit.servo(motorbit.S2,jd_x)
 -             if pre_jd_y !=jd_y:
 -               pre_jd_y =jd_y
 -               motorbit.servo(motorbit.S1,jd_y)
 -             cv2.putText(img, f'x:{mean_x} , y:{mean_y} ', (x, y - 50), cv2.FONT_HERSHEY_PLAIN, 3,
 -                         (255, 0, 0), 3)
 -         fps = 1 / (time.time() - PTime)
 -         cv2.putText(img, f'FPS: {int(fps)}', (20,50), cv2.FONT_HERSHEY_PLAIN,
 -                             3, (255, 255, 0), 3)
 -         output_image = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)                    
 -         cv2.imshow("camera", output_image)
 -         cv2.waitKey(1)
 -         
 - 
 - if __name__ == "__main__":
 -     main()
 - 
 
  复制代码
   
【演示视频】 
 
 
 |