树莓派,opencv,Picamera2利用舵机云台追踪人脸(PID控制)
一、需要准备的硬件
- Raspiberry Pi 4b
- 两个SG90 180度舵机(注意舵机的角度,最好是180度且带限位的,切勿选360度舵机)
- 二自由度舵机云台(如下图)
- Raspiberry CSI 摄像头
组装后的效果:

二、项目目标
追踪人脸:
当人脸移动时,摄像头通过控制两个伺服电机(分别是偏航和俯仰)把该人脸放到视界的中心位置,本文采用了PID控制伺服电机
三、具体步骤
3.1 下载用于人脸识别的级联分类器
下载级联分类器“haarcascade_frontalface_default.xml”,下载地址:haarcascade_frontalface_default.xml
下载完成后将其与后面的所有文件放到同一目录中。
3.2人脸追踪代码
- 创建文件“face_tracking_PID.py” ,代码如下:
#face_tracking_PID.py
#-*- coding: UTF-8 -*-
# 调用必需库
from multiprocessing import Manager
from multiprocessing import Process
from objcenter import ObjCenter
from pid import PID
from servo import Servo
import argparse
import signal
import time
import sys
import cv2
from picamera2 import Picamera2# 定义舵机
pan=Servo(pin=19)
tilt=Servo(pin=16)#定义图像尺寸
dispW=1280
dispH=720# 键盘终止函数
def signal_handler(sig, frame):# 输出状态信息print("[INFO] You pressed `ctrl + c`! Exiting...")# 关闭舵机pan.stop()tilt.stop()# 退出sys.exit()def obj_center(args, objX, objY, centerX, centerY):# ctrl+c退出进程signal.signal(signal.SIGINT, signal_handler)# 启动视频流并缓冲print("[INFO] waiting for camera to warm up...")cv2.startWindowThread()picam2 = Picamera2()preview_config = picam2.create_preview_configuration(main={"size": (dispW, dispH),"format":"RGB888"})picam2.configure(preview_config)picam2.start()time.sleep(2.0)# 初始化人脸中心探测器obj = ObjCenter(args["cascade"])# 进入循环while True:# 从视频流抓取图像并旋转frame= picam2.capture_array()frame = cv2.flip(frame, 1)# 找到图像中心(H, W) = frame.shape[:2]centerX.value = W // 2centerY.value = H // 2#draw a point in the center of framecv2.circle(frame, (centerX.value, centerY.value), 5, (0, 0, 255), -1)# 找到人脸中心objectLoc = obj.update(frame, (centerX.value, centerY.value))((objX.value, objY.value), rect) = objectLocprint("objx.value", objX.value)print("objy.value", objY.value)# 绘制人脸外界矩形if rect is not None:(x, y, w, h) = rectcv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)fX = int(x + (w / 2.0))fY = int(y + (h / 2.0))cv2.circle(frame, (fX, fY), 5, (0, 0, 255), -1)# 在人脸中心和视窗中心画一条连线cv2.line(frame, (centerX.value, centerY.value),(fX, fY), (0, 255, 0), 2)# 显示图像cv2.imshow("Pan-Tilt Face Tracking", frame)cv2.waitKey(1)def pid_process(output, p, i, d, objCoord, centerCoord):# ctrl+c退出进程signal.signal(signal.SIGINT, signal_handler)# 创建一个PID类的对象并初始化p = PID(p.value, i.value, d.value)p.initialize()# 进入循环while True:# 计算误差error = centerCoord.value - objCoord.value# 更新输出值,当error小于50时,误差设为0,以避免云台不停运行。if abs(error) < 50:error = 0output.value = p.update(error)def set_servos(panAngle, tiltAngle):# ctrl+c退出进程signal.signal(signal.SIGINT, signal_handler)#进入循环while True:# 偏角变号yaw = -1 * panAngle.valuepitch = -1 * tiltAngle.value# 设置舵机角度。pan.set_angle(yaw)tilt.set_angle(pitch)# 启动主程序
if __name__ == "__main__":# 建立语法分析器ap = argparse.ArgumentParser()ap.add_argument("-c", "--cascade", type=str, required=True,help="path to input Haar cascade for face detection")args = vars(ap.parse_args())# 启动多进程变量管理with Manager() as manager: #相当于manager=Manager(),with as 语句操作上下文管理器(context manager),它能够帮助我们自动分配并且释放资源。# 舵机角度置零pan.set_angle(0)tilt.set_angle(0)# 为图像中心坐标赋初值centerX = manager.Value("i", 0) #"i"即为整型integercenterY = manager.Value("i", 0)# 为人脸中心坐标赋初值objX = manager.Value("i", 0)objY = manager.Value("i", 0)# panAngle和tiltAngle分别是两个舵机的PID控制输出量 panAngle = manager.Value("i", 0)tiltAngle = manager.Value("i", 0)# 设置一级舵机的PID参数panP = manager.Value("f", 0.015) # "f"即为浮点型floatpanI = manager.Value("f", 0.01)panD = manager.Value("f", 0.0008)# 设置二级舵机的PID参数tiltP = manager.Value("f", 0.025)tiltI = manager.Value("f", 0.01)tiltD = manager.Value("f", 0.008)# 创建4个独立进程# 1. objectCenter - 探测人脸# 2. panning - 对一级舵机进行PID控制,控制偏航角# 3. tilting - 对二级舵机进行PID控制,控制俯仰角# 4. setServos - 根据PID控制的输出驱动舵机processObjectCenter = Process(target=obj_center,args=(args, objX, objY, centerX, centerY))processPanning = Process(target=pid_process,args=(panAngle, panP, panI, panD, objX, centerX))processTilting = Process(target=pid_process,args=(tiltAngle, tiltP, tiltI, tiltD, objY, centerY))processSetServos = Process(target=set_servos, args=(panAngle, tiltAngle))# 开启4个进程processObjectCenter.start()processPanning.start()processTilting.start()processSetServos.start()# 添加4个进程processObjectCenter.join()processPanning.join()processTilting.join()processSetServos.join()
- 创建文件“objcenter.py”,代码如下:
#objcenter.py
#-*- coding: UTF-8 -*-
# 调用必需库
import cv2class ObjCenter:def __init__(self, haarPath):# 加载人脸探测器self.detector = cv2.CascadeClassifier(haarPath)def update(self, frame, frameCenter):# 将图像转为灰度图gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)# 探测图像中的所有人脸rects = self.detector.detectMultiScale(gray, scaleFactor=1.05,minNeighbors=9, minSize=(30, 30),flags=cv2.CASCADE_SCALE_IMAGE)# 是否检测到人脸if len(rects) > 0:# 获取矩形的参数# x,y为左上角点坐标,w,h为宽度和高度# 计算图像中心(x, y, w, h) = rects[0]faceX = int(x + (w / 2.0))faceY = int(y + (h / 2.0))# 返回人脸中心return ((faceX, faceY), rects[0])# 如果没有识别到人脸,返回图像中心return (frameCenter, None)
- 创建“pid.py”,代码如下:
#pid.py
#-*- coding: UTF-8 -*-
# 调用必需库
import timeclass PID:def __init__(self, kP=1, kI=0, kD=0):# 初始化参数self.kP = kPself.kI = kIself.kD = kDdef initialize(self):# 初始化当前时间和上一次计算的时间self.currTime = time.time()self.prevTime = self.currTime# 初始化上一次计算的误差self.prevError = 0# 初始化误差的比例值,积分值和微分值self.cP = 0self.cI = 0self.cD = 0def update(self, error, sleep=0.2):# 暂停time.sleep(sleep)# 获取当前时间并计算时间差self.currTime = time.time()deltaTime = self.currTime - self.prevTime# 计算误差的微分deltaError = error - self.prevError# 比例项self.cP = error# 积分项self.cI += error * deltaTime# 微分项self.cD = (deltaError / deltaTime) if deltaTime > 0 else 0# 保存时间和误差为下次更新做准备self.prevTime = self.currTimeself.prevError = error# 返回输出值return sum([self.kP * self.cP,self.kI * self.cI,self.kD * self.cD])
- 上述代码中的from servo import Servo导入servo,这个库是没有的,我们要手动创建这个库,在object_tracking.py所在的目录下新建servo.py文件,复制下面的代码到文件中
#!/usr/bin/env python3
import pigpio
from time import sleep
# Start the pigpiod daemon
import subprocess
result = None
status = 1
for x in range(3):p = subprocess.Popen('sudo pigpiod', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)result = p.stdout.read().decode('utf-8')status = p.poll()if status == 0:breaksleep(0.2)
if status != 0:print(status, result)
'''
> Use the DMA PWM of the pigpio library to drive the servo
> Map the servo angle (0 ~ 180 degree) to (-90 ~ 90 degree)'''class Servo():MAX_PW = 1250 # 0.5/20*100MIN_PW = 250 # 2.5/20*100_freq = 50 # 50 Hz, 20msdef __init__(self, pin, min_angle=-90, max_angle=90):self.pi = pigpio.pi()self.pin = pin self.pi.set_PWM_frequency(self.pin, self._freq)self.pi.set_PWM_range(self.pin, 10000) self.angle = 0self.max_angle = max_angleself.min_angle = min_angleself.pi.set_PWM_dutycycle(self.pin, 0)def set_angle(self, angle):if angle > self.max_angle:angle = self.max_angleelif angle < self.min_angle:angle = self.min_angleself.angle = angleduty = self.map(angle, -90, 90, 250, 1250)self.pi.set_PWM_dutycycle(self.pin, duty)def get_angle(self):return self.angledef stop(self):self.pi.set_PWM_dutycycle(self.pin, 0)self.pi.stop()# will be called automatically when the object is deleted# def __del__(self):# passdef map(self, x, in_min, in_max, out_min, out_max):return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_minif __name__ =='__main__':from vilib import Vilib# Vilib.camera_start(vflip=True,hflip=True) # Vilib.display(local=True,web=True)pan = Servo(pin=13, max_angle=90, min_angle=-90)tilt = Servo(pin=12, max_angle=30, min_angle=-90)panAngle = 0tiltAngle = 0pan.set_angle(panAngle)tilt.set_angle(tiltAngle)sleep(1)while True:for angle in range(0, 90, 1):pan.set_angle(angle)tilt.set_angle(angle)sleep(.01)sleep(.5)for angle in range(90, -90, -1):pan.set_angle(angle)tilt.set_angle(angle)sleep(.01)sleep(.5)for angle in range(-90, 0, 1):pan.set_angle(angle)tilt.set_angle(angle)sleep(.01)sleep(.5)
- 在树莓派相应文件目录中输入`“python face_tracking_PID.py --cascade haarcascade_frontalface_default.xml",即可实现对人脸对象自动追踪。相较之前的非PID控制而言,系统运行会更顺滑一些。在本例中采用的命令参数输入的方式,可以方便有多个人脸识别级联分类器时随时切换。
- 当运行时,可能会有摄像头随机摆动的现象出现,这是因为人脸识别级联分类器的识别过程中的误识别,对于普通用户我们还无能为力,只能是避开经常被误该识别的物体。
相关文章:
树莓派,opencv,Picamera2利用舵机云台追踪人脸(PID控制)
一、需要准备的硬件 Raspiberry Pi 4b两个SG90 180度舵机(注意舵机的角度,最好是180度且带限位的,切勿选360度舵机)二自由度舵机云台(如下图)Raspiberry CSI 摄像头 组装后的效果: 二、项目目…...
uniapp中推出当前微信小程序
uni.exitMiniProgram() 通过代码直接退出当前小程序 uni.exitMiniProgram({success: function() {console.log(退出小程序成功);},fail: function(err) {console.log(退出小程序失败, err);} })...
AndroidStudio无法新建aidl文件解决办法
我用的 AS 版本是 Android Studio Giraffe | 2022.3.1 Build #AI-223.8836.35.2231.10406996, built on June 29, 2023 右键新建 aidl 文件, 提示 (AIDL File)Requires setting the buildFeatures.aidl to true in the build file 解决办法 修改 app 的 build.…...
java爬虫(jsoup)如何设置HTTP代理ip爬数据
目录 前言 什么是HTTP代理IP 使用Jsoup设置HTTP代理IP的步骤 1. 导入Jsoup依赖 2. 创建HttpProxy类 3. 设置代理服务器 4. 使用Jsoup进行爬取 结论 前言 在Java中使用Jsoup进行网络爬虫操作时,有时需要使用HTTP代理IP来爬取数据。本文将介绍如何使用Jsoup设…...
ZooKeeper Client API 安装及使用指北
下载 wget https://archive.apache.org/dist/zookeeper/zookeeper-3.5.4-beta/zookeeper-3.5.4-beta.tar.gz解压 tar -zxf zookeeper-3.5.4-beta.tar.gz安装 cd zookeeper-3.5.4-beta/src/c/ ./configure make sudo make install到 make 这一步大概率会出现报错:…...
本机ping不通虚拟机
windows下finall shell连不上虚拟机了,之前是可以的,然后ping虚拟机,发现也ping不通,随后到处找问题。 在本地部分,控制面板 ——>网络和Internet——>网络连接 , 可以看到 VMnet1和Vmnet8虽然都是已…...
Linux cfdisk命令
Linux cfdisk命令用于磁盘分区。 cfdisk是用来磁盘分区的程序,它十分类似DOS的fdisk,具有互动式操作界面而非传统fdisk的问答式界面,您可以轻易地利用方向键来操控分区操作。 语法 cfdisk [-avz][-c <柱面数目>-h <磁头数目>-…...
实用学习网站和资料
github:https://github.com/GitHubDaily/GitHubDaily Linux操作手册: GitHub - abarrak/linux-sysops-handbook: Essentials of Linux system administration. 从零开始制作一个操作系统: GitHub - ruiers/os-tutorial-cn: 从零开始编写一个操作系统…...
【已解决】c++qt如何制作翻译供程序调用
本博文源于笔者正在编写的工具需要创建翻译文件,恰好将qt如何进行翻译,从零到结果进行读者查阅,并非常推荐读者进行收藏点赞,因为步步都很清晰,堪称胎教式c制作,而且内容还包括如何部署在windows下。堪称值…...
DPDK单步跟踪(3)-如何利用visual studio 2019和visual gdb来单步调试dpdk
准备工作 因为时间的关系,我想到哪说到哪,可能没那么高的完成度。 但其实有心的人,看到这个标题,就关了本文自己能做了。 why和how to build debug version DPDK,见前两篇。这里我们准备开始。 首先,你有一台linux机…...
Python爬虫---解析---BeautifulSoup
BeautifulSoup简称:bs4 作用:解析和提取数据 1. 安装:pip install bs4 或pip install bs4 -i https://pypi.douban.com/simple(使用国内镜像下载) 注意:需要安装在python解释器相同的位置,例如…...
Argument list too long when copying files
for i in /path/to/dir/*; do cp "$i" /path/to/other/dir/; done...
configure
configure 配置软件./configure --prefix$PWD/output CCaarch64-linux-gcc --hostaarch64-linux --enable-shared --enable-staticconfig.sub 文件 这个文件用于确定主机系统的类型,并返回与该系统相关的标识符。它包含一系列 shell 函数,用于检测主机…...
HOJ 项目部署-前端定制 默认勾选显示标签、 在线编辑器主题和字号大小修改、增加一言功能 题目AC后礼花绽放
# 项目拉取地址: https://gitee.com/himitzh0730/hoj.git # 切换到hoj-vue目录执行以下命令 #安装依赖 npm install #运行服务 npm run serve #修改代码后构建项目到dist文件夹,到服务器docker-compose.yml中修改hoj-frontend文件映射即可 npm run build…...
Scikit-Learn线性回归(二)
Scikit-Learn线性回归二:多项式回归 1、多项式回归2、多项式回归的原理3、Scikit-Learn多项式回归3.1、Scikit-Learn多项式回归API1、多项式回归 线性回归研究的是一个自变量与一个因变量之间的回归问题。在实际应用中,并不是所有的情景都符合线性关系,大多数情况都是非线性…...
07 Vue3框架简介
文章目录 一、Vue3简介1. 简介2. 相关网站3. 前端技术对比4. JS前端框架5. Vue核心内容6. 使用方式 二、基础概念1. 创建一个应用2. 变量双向绑定(v-model)3. 条件控制(v-if)4. 数组遍历(v-for)5. 绑定事件…...
前端八股文(js篇)
一.强制类型转换规则 首先需要了解隐式转换所调用的函数。 当程序员显示调用Boolean(value),Number(value),String(value)完成的类型转换,叫做显示类型转换。 当通过new Boolean&…...
windows+ubuntu离线安装翻译软件有道词典
背景: 某些情况下,需要在无法连接互联网的电脑上翻译单词,句子以及段落,就需要能离线安装和翻译的翻译软件,具备一定的词库量,目前找到了《有道词典》。 windows 亲测,无法联网的win10中安装…...
DevC++ easyx实现视口编辑,在超过屏幕大小的地图上画点,与解决刮刮乐bug效果中理解C语言指针的意义
继上篇文案, DevC easyx实现地图拖动,超过屏幕大小的巨大地图的局部显示在屏幕的方法——用悬浮窗的原理来的实现一个视口-CSDN博客 实现了大地图拖动,但是当时野心不止,就想着一气能搓啥就继续搓啥,看着地图移动都搓…...
Kali Linux—借助 SET+MSF 进行网络钓鱼、生成木马、获主机shell、权限提升、远程监控、钓鱼邮件等完整渗透测试(一)
社会工程学—世界头号黑客凯文米特尼克在《欺骗的艺术》中曾提到,这是一种通过对受害者心理弱点、本能反应、好奇心、信任、贪婪等心理陷阱进行诸如欺骗、伤害等危害手段。 SET最常用的攻击方法有:用恶意附件对目标进行 E-mail 钓鱼攻击、Java Applet攻…...
Python 字典遍历全攻略:5 种常用方法 + 性能对比 + 实战优化技巧
在 Python 开发中,字典(dict) 是最常用的数据结构之一,以键值对形式存储数据,具备查询快、易操作的特点。而字典的遍历是日常开发中高频操作 —— 从简单的数据读取,到大规模数据处理、接口返回值解析&…...
手把手教你用STM32实现BLDC电机的SPWM控制(附代码调试心得)
STM32实战:无刷直流电机SPWM控制全解析与代码优化指南 从理论到实践:BLDC电机控制的核心逻辑 第一次接触无刷直流电机(BLDC)控制时,我被它优雅的工作原理所吸引——没有电刷的火花和磨损,却能实现高效的能量转换。在工业自动化、无…...
3分钟快速上手!Balena Etcher终极镜像烧录工具完全指南
3分钟快速上手!Balena Etcher终极镜像烧录工具完全指南 【免费下载链接】etcher Flash OS images to SD cards & USB drives, safely and easily. 项目地址: https://gitcode.com/GitHub_Trending/et/etcher Balena Etcher是一款革命性的跨平台镜像烧录工…...
AnythingtoRealCharacters2511效果展示:动漫角色真人化案例
AnythingtoRealCharacters2511效果展示:动漫角色真人化案例 你有没有想过,如果自己喜欢的动漫角色真的出现在现实世界里,会是什么样子?不是那种粗糙的3D建模,也不是简单的滤镜叠加,而是看起来就像用专业相…...
ARM嵌入式开发:寄存器操作与函数指针实战
## 1. 嵌入式开发中的寄存器操作技巧### 1.1 寄存器地址访问方法 在ARM架构嵌入式开发中,直接操作硬件寄存器是底层开发的核心技能。通过C语言访问特定内存地址的标准做法是使用指针类型转换:c #define GSTATUS1 (*(volatile unsigned int *)0x560000B0)…...
AnotherRedisDesktopManager:提升Redis管理效率的全方位解决方案
AnotherRedisDesktopManager:提升Redis管理效率的全方位解决方案 【免费下载链接】AnotherRedisDesktopManager qishibo/AnotherRedisDesktopManager: Another Redis Desktop Manager 是一款跨平台的Redis桌面管理工具,提供图形用户界面,支持…...
VoxCPM-1.5-WEBUI场景应用:智能客服、有声读物、教育视频配音
VoxCPM-1.5-WEBUI场景应用:智能客服、有声读物、教育视频配音 1. 开篇:语音合成技术的平民化革命 还记得那些机械感十足的AI语音吗?生硬的语调、奇怪的停顿、模糊的发音,让听众不得不竖起耳朵才能勉强听懂。如今,随着…...
Qwen2.5-Coder-1.5B代码修复实战:常见Bug自动诊断与修复
Qwen2.5-Coder-1.5B代码修复实战:常见Bug自动诊断与修复 你有没有过这样的经历?深夜赶项目,代码跑起来一堆红字,对着报错信息一头雾水,查了半天文档还是找不到问题在哪。或者,接手一个老项目,里…...
Windows 11下保姆级安装Isaac Sim 4.5.0与Isaac Lab避坑全记录(含CUDA 12.8配置)
Windows 11下Isaac Sim 4.5.0与Isaac Lab全流程部署指南(RTX 4090实测版) 对于机器人仿真和AI开发领域的从业者来说,NVIDIA Isaac Sim和Isaac Lab无疑是当前最强大的工具组合之一。然而,当我在自己的RTX 4090显卡上首次尝试部署这…...
音乐解密技术探秘:从加密困境到跨平台解决方案
音乐解密技术探秘:从加密困境到跨平台解决方案 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库: 1. https://github.com/unlock-music/unlock-music ;2. https://git.unlock-music.dev/um/web 项目地址: https://gitc…...
