亚博microros小车-原生ubuntu支持系列:23 人脸识别追踪
背景知识:
本节跟上一篇的物体识别追踪类似,换了opencv的函数来做人脸识别
函数定义如下:
detectMultiScale(image, scaleFactor, minNeighbors, flags, minSize, maxSize)
scaleFactor参数控制每个图像序列的缩放比例。该参数决定了在每个图像序列中检测窗口的大小。默认值为1.1,表示每次图像被缩小10%。较小的值可以捕捉更多的细节,但也会增加计算量。较大的值可以加快检测速度,但可能会错过一些目标。
minNeighbors参数定义了每个目标至少应该有多少个邻居,才能被认为是一个目标。该参数用于过滤检测到的目标。较大的值可以过滤掉一些误检测,但可能会导致一些目标被漏检。
flags参数用于定义检测模式。它可以是以下几个值的组合:
- CASCADE_SCALE_IMAGE:使用缩放图像进行检测(默认值)。
- CASCADE_FIND_BIGGEST_OBJECT:只检测最大的目标。
- CASCADE_DO_ROUGH_SEARCH:快速搜索模式。
minSize参数用于指定检测目标的最小尺寸。目标小于该尺寸的将被忽略。该参数可以用于过滤一些过小的目标。
maxSize参数用于指定检测目标的最大尺寸。目标大于该尺寸的将被忽略。该参数可以用于过滤一些过大的目标。
1、程序说明
运行程序后,当人脸展现在画面中时,当出现方框围住人脸时,云台摄像头会跟随人脸的移动而移动。
src/yahboom_esp32ai_car/yahboom_esp32ai_car/目录下新建文face_fllow.py,代码如下
#ros lib
import rclpy
from rclpy.node import Node
from std_msgs.msg import Bool
from geometry_msgs.msg import Twist
from sensor_msgs.msg import CompressedImage, LaserScan, Image
from yahboomcar_msgs.msg import Position
from std_msgs.msg import Int32, Bool,UInt16
#common lib
import os
import threading
import math
import cv2
from yahboom_esp32ai_car.astra_common import *
from yahboomcar_msgs.msg import Position
from cv_bridge import CvBridge
from std_msgs.msg import Int32, Bool,UInt16from rclpy.time import Time
import datetime
from ament_index_python.packages import get_package_share_directory #获取shares目录绝对路径
print("import done")class faceTracker(Node):def __init__(self,name):super().__init__(name)#create the publisherself.pub_Servo1 = self.create_publisher(Int32,"servo_s1" , 10)self.pub_Servo2 = self.create_publisher(Int32,"servo_s2" , 10)#create the subscriber#self.sub_depth = self.create_subscription(Image,"/image_raw", self.depth_img_Callback, 1)self.sub_JoyState = self.create_subscription(Bool,'/JoyState', self.JoyStateCallback,1)#self.sub_position = self.create_subscription(Position,"/Current_point",self.positionCallback,1)self.bridge = CvBridge()self.minDist = 1500self.Center_x = 0self.Center_y = 0self.Center_r = 0self.Center_prevx = 0self.Center_prevr = 0self.prev_time = 0self.prev_dist = 0self.prev_angular = 0self.Joy_active = Falseself.Robot_Run = Falseself.img_flip = Falseself.dist = []self.encoding = ['8UC3']self.linear_PID = (20.0, 0.0, 1.0)self.angular_PID = (0.5, 0.0, 2.0)self.scale = 1000self.end = 0self.PWMServo_X = 0self.PWMServo_Y = 0self.s1_init_angle = Int32()self.s1_init_angle.data = self.PWMServo_Xself.s2_init_angle = Int32()self.s2_init_angle.data = self.PWMServo_Yself.PID_init()self.declare_param()self.last_stamp = Noneself.new_seconds = 0self.fps_seconds = 1#self.capture = cv.VideoCapture(0)#self.timer = self.create_timer(0.001, self.on_timer)#ESP32_wifiself.bridge = CvBridge()self.sub_img = self.create_subscription(CompressedImage, '/espRos/esp32camera', self.handleTopic, 1) #获取esp32传来的图像#确保角度正常处于中间for i in range(10):self.pub_Servo1.publish(self.s1_init_angle)self.pub_Servo2.publish(self.s2_init_angle)time.sleep(0.1)print("init done")def declare_param(self):#PIDself.declare_parameter("Kp",20)self.Kp = self.get_parameter('Kp').get_parameter_value().integer_valueself.declare_parameter("Ki",0)self.Ki = self.get_parameter('Ki').get_parameter_value().integer_valueself.declare_parameter("Kd",0.9)self.Kd = self.get_parameter('Kd').get_parameter_value().integer_valuedef get_param(self):self.Kd = self.get_parameter('Kd').get_parameter_value().integer_valueself.Ki = self.get_parameter('Ki').get_parameter_value().integer_valueself.Kp = self.get_parameter('Kp').get_parameter_value().integer_valueself.linear_PID = (self.Kp,self.Ki,self.Kd)# def on_timer(self):# self.get_param()# global m # m=0# global n# n=0# ret, frame = self.capture.read()# action = cv.waitKey(10) & 0xFF# start = time.time()# fps = 1 / (start - self.end)# text = "FPS : " + str(int(fps))# self.end = start# cv.putText(frame, text, (20, 30), cv.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 1)# face_patterns = cv2.CascadeClassifier('/root/yahboomcar_ws/src/yahboomcar_astra/yahboomcar_astra/haarcascade_frontalface_default.xml')# faces = face_patterns.detectMultiScale(frame , scaleFactor=1.1, minNeighbors=5, minSize=(100, 100))# if len(faces)>0:# for (x, y, w, h) in faces:# m=x# n=y# cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)# self.execute(m,n)# cv.imshow('frame', frame)# if action == ord('q') or action == 113:# self.capture.release()# cv.destroyAllWindows()#ESP32_wifidef handleTopic(self, msg):self.get_param()global m m=0global nn=0self.last_stamp = msg.header.stamp if self.last_stamp:total_secs = Time(nanoseconds=self.last_stamp.nanosec, seconds=self.last_stamp.sec).nanosecondsdelta = datetime.timedelta(seconds=total_secs * 1e-9)seconds = delta.total_seconds()*100if self.new_seconds != 0:self.fps_seconds = seconds - self.new_secondsself.new_seconds = seconds#保留这次的值start = time.time()frame = self.bridge.compressed_imgmsg_to_cv2(msg)frame = cv2.resize(frame, (640, 480))action = cv2.waitKey(10) & 0xFF#face_patterns = cv2.CascadeClassifier(get_package_share_directory('yahboom_esp32ai_car')+'/resource/haarcascade_frontalface_default.xml')faces = face_patterns.detectMultiScale(frame , scaleFactor=1.1, minNeighbors=5, minSize=(100, 100))if len(faces)>0:for (x, y, w, h) in faces:m=xn=ycv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)self.execute(m,n)end = time.time()fps = 1/((end - start)+self.fps_seconds) text = "FPS : " + str(int(fps))cv2.putText(frame, text, (10,20), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0,255,255), 2)cv2.imshow('frame', frame)if action == ord('q') or action == 113:cv2.destroyAllWindows()def PID_init(self):self.PID_controller = simplePID([0, 0],[self.linear_PID[0] / float(self.scale), self.linear_PID[0] / float(self.scale)],[self.linear_PID[1] / float(self.scale), self.linear_PID[1] / float(self.scale)],[self.linear_PID[2] / float(self.scale), self.linear_PID[2] / float(self.scale)])self.pub_Servo1.publish(self.s1_init_angle)self.pub_Servo2.publish(self.s2_init_angle)def JoyStateCallback(self, msg):if not isinstance(msg, Bool): returnself.Joy_active = msg.dataself.pub_cmdVel.publish(Twist())def positionCallback(self, msg):if not isinstance(msg, Position): returnself.Center_x = msg.anglexself.Center_y = msg.angleyself.Center_r = msg.distancedef execute(self, point_x, point_y):[x_Pid, y_Pid] = self.PID_controller.update([point_x - 320, point_y - 240])if abs(x_Pid) <1 and abs(y_Pid)<0.5: #在死区直接不动了returnif self.img_flip == True:self.PWMServo_X += x_Pidself.PWMServo_Y += y_Pidelse:self.PWMServo_X -= x_Pidself.PWMServo_Y += y_Pidif self.PWMServo_X >= 40:self.PWMServo_X = 40elif self.PWMServo_X <= -40:self.PWMServo_X = -40if self.PWMServo_Y >= 20:self.PWMServo_Y = 20elif self.PWMServo_Y <= -90:self.PWMServo_Y = -90# rospy.loginfo("target_servox: {}, target_servoy: {}".format(self.target_servox, self.target_servoy))print("servo1",self.PWMServo_X)servo1_angle = Int32()servo1_angle.data = int(self.PWMServo_X)servo2_angle = Int32()servo2_angle.data = int(self.PWMServo_Y)self.pub_Servo1.publish(servo1_angle)self.pub_Servo2.publish(servo2_angle)class simplePID:'''very simple discrete PID controller'''def __init__(self, target, P, I, D):'''Create a discrete PID controllereach of the parameters may be a vector if they have the same lengthArgs:target (double) -- the target value(s)P, I, D (double)-- the PID parameter'''# check if parameter shapes are compatabile.if (not (np.size(P) == np.size(I) == np.size(D)) or ((np.size(target) == 1) and np.size(P) != 1) or (np.size(target) != 1 and (np.size(P) != np.size(target) and (np.size(P) != 1)))):raise TypeError('input parameters shape is not compatable')#rospy.loginfo('P:{}, I:{}, D:{}'.format(P, I, D))self.Kp = np.array(P)self.Ki = np.array(I)self.Kd = np.array(D)self.last_error = 0self.integrator = 0self.timeOfLastCall = Noneself.setPoint = np.array(target)self.integrator_max = float('inf')def update(self, current_value):'''Updates the PID controller.Args:current_value (double): vector/number of same legth as the target given in the constructorReturns:controll signal (double): vector of same length as the target'''current_value = np.array(current_value)if (np.size(current_value) != np.size(self.setPoint)):raise TypeError('current_value and target do not have the same shape')if (self.timeOfLastCall is None):# the PID was called for the first time. we don't know the deltaT yet# no controll signal is appliedself.timeOfLastCall = time.perf_counter()return np.zeros(np.size(current_value))error = self.setPoint - current_valueP = errorcurrentTime = time.perf_counter()deltaT = (currentTime - self.timeOfLastCall)# integral of the error is current error * time since last updateself.integrator = self.integrator + (error * deltaT)I = self.integrator# derivative is difference in error / time since last updateD = (error - self.last_error) / deltaTself.last_error = errorself.timeOfLastCall = currentTime# return controll signalreturn self.Kp * P + self.Ki * I + self.Kd * Ddef main():rclpy.init()face_Tracker = faceTracker("FaceTracker")try:rclpy.spin(face_Tracker)except KeyboardInterrupt:passfinally:face_Tracker.destroy_node()rclpy.shutdown()
跟上一篇物体识别追踪亚博microros小车-原生ubuntu支持系列:22 物体识别追踪-CSDN博客 类似,不在逐行添加注释。
启动小车代理
sudo docker run -it --rm -v /dev:/dev -v /dev/shm:/dev/shm --privileged --net=host microros/micro-ros-agent:humble udp4 --port 8090 -v4
启动图像代理
docker run -it --rm -v /dev:/dev -v /dev/shm:/dev/shm --privileged --net=host microros/micro-ros-agent:humble udp4 --port 9999 -v4
(选做)调整舵机
ros2 run yahboom_esp32_mediapipe control_servo
启动程序
ros2 run yahboom_esp32ai_car face_fllow
当识别人脸会框选,并且二维云台跟随人脸移动,并且终端打印移动角度

bohu@bohu-TM1701:~/yahboomcar/yahboomcar_ws$ ros2 run yahboom_esp32ai_car face_fllow
import done
init done
servo1 -1.870886676904979
servo1 -3.3315064420857414
servo1 -3.8893113859842563
servo1 -4.829714884815847
servo1 -5.531316057727904
servo1 -8.270412263987003
servo1 -11.28949508811162
servo1 -14.827409042746957
servo1 -17.313175450074567
servo1 -18.47017653776488
servo1 -16.712259138142592
servo1 -15.463574207134664
servo1 -14.357884507043561
servo1 -13.564746266546917
servo1 -13.171587288582277
servo1 -13.336302497052168
servo1 -13.420888481020322
servo1 -13.046533845705673
servo1 -12.81813413213153
servo1 -12.975443377657772
servo1 -14.095269899667365
servo1 -16.35166785571329
servo1 -18.550105463860874
servo1 -20.953949676274878
servo1 -24.326369597501582
servo1 -26.64879470036452
servo1 -25.940573656940963
servo1 -25.216060965804687
servo1 -24.53637502577782
servo1 -24.821431609929228
servo1 -26.048312267650324
servo1 -27.281132833944664
servo1 -28.032283744044005
servo1 -28.896142802075563
servo1 -30.097106599839762
servo1 -30.374701850607238
servo1 -29.952807303311566
rqt查看节点如下

相关文章:
亚博microros小车-原生ubuntu支持系列:23 人脸识别追踪
背景知识: 本节跟上一篇的物体识别追踪类似,换了opencv的函数来做人脸识别 函数定义如下: detectMultiScale(image, scaleFactor, minNeighbors, flags, minSize, maxSize)scaleFactor参数控制每个图像序列的缩放比例。该参数决定了在每个…...
[7] 游戏机项目说明
[7] 游戏机项目说明 在这节课中,我们将学习如何基于FreeRTOS开发一个简单的游戏项目。我们会使用一个开源项目nwatch,它是一个基于STM32的开源手表,包含了三个游戏。我们的目标是将这个游戏移植到我们的开发板上,并逐步使用FreeR…...
Kubernetes之kube-proxy运行机制分析
一、基础知识 1.Kubernetes再创建服务时会为服务分配一个虚拟IP地址,客户端通过这个虚拟Ip地址来访问服务,而服务则负责将请求转发到后端pod上。 2.上述阐述的过程为一个反向代理的过程,但是这个反向代理和普通的反向代理的区别是它的IP地址是…...
微信小程序调用企业微信客户服务插件联通企业微信客服
需求背景:用户在小程序页面点击按钮添加企业微信的客服 相关技术:基于uniapp开发的微信小程序 插件名称:企业微信客户服务插件「联系我」插件 - 文档 - 企业微信开发者中心 仔细阅读文档「联系我」插件 - 文档 - 企业微信开发者中心 以下是我的实例代码 1.首先先小程序管…...
如何解决 javax.xml.crypto.dsig.TransformException: 转换异常问题?亲测有效的解决方法!
1. 问题分析 1.1 异常描述 javax.xml.crypto.dsig.TransformException 是在使用 Java XML 加密和签名 API 时,发生的一个常见异常。它通常出现在 XML 数字签名的转换过程中,可能是由于签名、加密或验证过程中发生了错误。 1.2 异常场景 该异常通常发…...
【AI实践】deepseek支持升级git
当前Windows 11 WSL的git是2.17,Android Studio提示需要升级到2.19版本 网上找到指导文章 安装git 2.19.2 cd /usr/src wget https://www.kernel.org/pub/software/scm/git/git-2.19.2.tar.gz tar xzf git-2.19.2.tar.gz cd git-2.19.2 make prefix/usr/l…...
git 子模块管理(一个仓库中有多个子仓库)
使用 Git 子模块管理 B 和 C 仓库 在A仓库中维护B和C仓库 进入 A 仓库: 添加 B 和 C 作为子模块: git submodule add https://your-repo-url/B.git B-repo git submodule add https://your-repo-url/C.git C-repo git commit -m "Add B and C a…...
Maven 安装配置(完整教程)
文章目录 一、Maven 简介二、下载 Maven三、配置 Maven3.1 配置环境变量3.2 Maven 配置3.3 IDEA 配置 四、结语 一、Maven 简介 Maven 是一个基于项目对象模型(POM)的项目管理和自动化构建工具。它主要服务于 Java 平台,但也支持其他编程语言…...
w196Spring Boot高校教师科研管理系统设计与实现
🙊作者简介:多年一线开发工作经验,原创团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹赠送计算机毕业设计600个选题excel文…...
Flutter初相识
资料 1、中文官网:安装和环境配置 | Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 2、线上编写网站:DartPad 构建第一个Flutter应用 class MyApp extends StatelessWidget {const MyApp({Key? key}) : super(key: key);overrideWidget bui…...
(1/100)每日小游戏平台系列
每日小游戏平台 项目简介以及地址 准备开发一个一百天小游戏平台,使用Flask构建的简单游戏导航网站,无需登录,让大家在返工的同时也可以愉快的摸鱼玩耍。 每天更新一个小游戏上传,看看能不能坚持一百天。 这些小游戏主要使用前端…...
IMX6ULL环境搭建遇到的问题和解答更新
IMX6ULL环境搭建遇到的问题 开发板:正点原子IMX6ULL 终端软件串口控制:MobaXterm 1、网络环境搭建三方互ping不通 电脑无网口,使用绿联USB转网口,接网线直连开发板,电脑WiFi上网 按文档设置的 IP 地址,以…...
具身智能学习规划
具身智能(Embodied Intelligence)强调智能体通过身体与环境的动态交互实现学习和决策,是人工智能、机器人学、认知科学和神经科学交叉的前沿领域。其核心在于打破传统AI的“离身认知”,将智能与物理实体、感知-运动系统紧密结合。…...
kafka生产端之拦截器、分区器、序列化器
文章目录 拦截器序列化器分区器 拦截器 拦截器(Interceptor)是早在Kafka0.10.0.0中就已经引入的一个功能,Kafka一共有两种拦截器:生产者拦截器和消费者拦截器。本节主要讲述生产者拦截器的相关内容,有关消费者拦截器的…...
BFS算法篇——广度优先搜索,探索未知的旅程(上)
文章目录 前言一、BFS的思路二、BFS的C语言实现1. 图的表示2. BFS的实现 三、代码解析四、输出结果五、总结 前言 广度优先搜索(BFS)是一种广泛应用于图论中的算法,常用于寻找最短路径、图的遍历等问题。与深度优先搜索(DFS&…...
FPGA VGA timing
概念 VGA(Video Graphics Array)时序是控制VGA接口显示图像的关键参数,它主要包括行时序和场时序两部分。以下是对VGA时序的详细解释: 一、VGA接口简介 VGA接口是IBM公司在1987年推出的一种使用模拟信号的视频传输标准,具有成本低、结构简单、应用灵活等优点,至今仍被广…...
pytest生成报告no tests ran in 0.01s
除了基本的环境配置、用例名要以test_开头,有个地方是我自己忽略了,在执行时没有指定用例文件,所以没有找到。 if __name__ __main__:pytest.main(["testcases/test_demo.py","-svq", __file__, --alluredir./allure-r…...
Django开发入门 – 0.Django基本介绍
Django开发入门 – 0.Django基本介绍 A Brief Introduction to django By JacksonML 1. Django简介 1) 什么是Django? 依据其官网的一段解释: Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. …...
数巅科技中标科学城数科集团AI辅助企业数字化转型评估诊断
自2023年以来,财政部和工信部连续发布通知,强调要做好中小企业数字化转型城市试点工作,鼓励试点城市大力支持优质数字化服务商,研发攻关一批“小快轻准”数字化产品和解决方案,助力制造业关键领域的中小企业实现数字化…...
Linux proc虚拟文件系统
文章目录 简介proc常用节点pid节点procfs接口参考 简介 测试环境:Linux dev-PC 5.18.17-amd64-desktop-hwe #20.01.00.10 SMP PREEMPT_DYNAMIC Thu Jun 15 16:17:50 CST 2023 x86_64 GNU/Linux proc虚拟文件系统是linux内核提供的一种让用户和内核内部数据结构进行交…...
idea整合deepseek实现AI辅助编程
1.File->Settings 2.安装插件codegpt 3.注册deepseek开发者账号,DeepSeek开放平台 4.按下图指示创建API KEY 5.回到idea配置api信息,File->Settings->Tools->CodeGPT->Providers->Custom OpenAI API key填写deepseek的api key Chat…...
局域网内别的电脑怎么连接到对方的mysql数据库
要让局域网内的其他电脑连接到一台主机上的 MySQL 数据库,你需要进行一些配置,包括 MySQL 服务器的设置、权限调整,以及客户端连接的步骤。以下是详细的步骤说明: 1. 确保 MySQL 服务器允许远程连接 默认情况下,MySQL 服务器可能只允许本地连接(localhost)。你需要修改…...
加速汽车软件升级——堆栈刷写技术的应用与挑战
一、背景和挑战 | 背景: 当前汽车市场竞争激烈,多品牌并存,新车发布速度加快,价格逐渐降低,功能日益多样化。随着车辆功能的不断提升与优化,ECU(电子控制单元)的代码量也随之增加&…...
2. UVM的基本概念和架构
文章目录 前言1. UVM的基本概念1.1 UVM的核心组件1.2 UVM的基本架构1.3 UVM的工作流程 2. UVM的架构2.1 UVM的层次结构2.2 UVM的组件交互 3. 总结 前言 首先,得确定UVM的基本概念和架构包含哪些关键部分。我回忆起UVM的核心组件,比如uvm_component、uvm…...
【力扣】138.随机链表的复制
AC截图 题目 代码 使用哈希存储<旧节点,新结点> /* // Definition for a Node. class Node { public:int val;Node* next;Node* random;Node(int _val) {val _val;next NULL;random NULL;} }; */class Solution { public:Node* copyRandomList(Node* hea…...
防火墙、堡垒机和NAT
在网络安全中,防火墙、堡垒机(Cloud Monitoring and Protection Machine)和网络地址转换(NAT) 是三种核心设备,用于防御外来的访问和破坏性攻击。然而,这三种设备本身也可能面临多种网络安全威胁…...
归一化与伪彩:LabVIEW图像处理的区别
在LabVIEW的图像处理领域,归一化(Normalization)和伪彩(Pseudo-coloring)是两个不同的概念,虽然它们都涉及图像像素值的调整,但目的和实现方式截然不同。归一化用于调整像素值的范围,…...
动态表格html
题目: 要求: 1.表格由专业班级学号1-10号同学的信息组成,包括:学号、姓 名、性别、二级学院、班级、专业、辅导员; 2.表格的奇数行字体为黑色,底色为白色;偶数行字体为白色,底 色为黑…...
通过k8s请求selfsubjectrulesreviews查询权限
当前是通过kubelet进行查询 curl --cacert /etc/kubernetes/pki/ca.crt \ --cert /var/lib/kubelet/pki/kubelet-client-current.pem \ --key /var/lib/kubelet/pki/kubelet-client-current.pem \ -d - \ -H "Content-Type: application/json" \ -H Accept: applicat…...
Leetcode 3447. Assign Elements to Groups with Constraints
Leetcode 3447. Assign Elements to Groups with Constraints 1. 解题思路2. 代码实现 题目链接:3447. Assign Elements to Groups with Constraints 1. 解题思路 这一题的话思路上我是预先算出可能数字对应的element,然后只要一次query就行了。 而至…...
