亚博microros小车-原生ubuntu支持系列:23 人脸识别追踪

news2025/3/15 7:30:10

背景知识:

本节跟上一篇的物体识别追踪类似,换了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,UInt16

from 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 publisher
        self.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 = 1500
        self.Center_x = 0
        self.Center_y = 0
        self.Center_r = 0
        self.Center_prevx = 0
        self.Center_prevr = 0
        self.prev_time = 0
        self.prev_dist = 0
        self.prev_angular = 0
        self.Joy_active = False
        self.Robot_Run = False
        self.img_flip = False
        self.dist = []
        self.encoding = ['8UC3']
        self.linear_PID = (20.0, 0.0, 1.0)
        self.angular_PID = (0.5, 0.0, 2.0)
        self.scale = 1000
        self.end = 0
        self.PWMServo_X = 0
        self.PWMServo_Y = 0
        self.s1_init_angle = Int32()
        self.s1_init_angle.data = self.PWMServo_X
        self.s2_init_angle = Int32()
        self.s2_init_angle.data = self.PWMServo_Y
        self.PID_init()
        self.declare_param()
        self.last_stamp = None
        self.new_seconds = 0
        self.fps_seconds = 1




        #self.capture = cv.VideoCapture(0)
        #self.timer = self.create_timer(0.001, self.on_timer)

        #ESP32_wifi
        self.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):
        #PID
        self.declare_parameter("Kp",20)
        self.Kp = self.get_parameter('Kp').get_parameter_value().integer_value
        self.declare_parameter("Ki",0)
        self.Ki = self.get_parameter('Ki').get_parameter_value().integer_value
        self.declare_parameter("Kd",0.9)
        self.Kd = self.get_parameter('Kd').get_parameter_value().integer_value

    def get_param(self):
        self.Kd = self.get_parameter('Kd').get_parameter_value().integer_value
        self.Ki = self.get_parameter('Ki').get_parameter_value().integer_value
        self.Kp = self.get_parameter('Kp').get_parameter_value().integer_value
        self.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_wifi
    def handleTopic(self, msg):
        self.get_param()
        global m 
        m=0
        global n
        n=0

        self.last_stamp = msg.header.stamp  
        if self.last_stamp:
            total_secs = Time(nanoseconds=self.last_stamp.nanosec, seconds=self.last_stamp.sec).nanoseconds
            delta = datetime.timedelta(seconds=total_secs * 1e-9)
            seconds = delta.total_seconds()*100

            if self.new_seconds != 0:
                self.fps_seconds = seconds - self.new_seconds

            self.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=x
                n=y
                cv2.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): return
        self.Joy_active = msg.data
        self.pub_cmdVel.publish(Twist())

    def positionCallback(self, msg):
        if not isinstance(msg, Position): return
        self.Center_x = msg.anglex
        self.Center_y = msg.angley
        self.Center_r = msg.distance

    def 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:  #在死区直接不动了
            return

        if self.img_flip == True:
            self.PWMServo_X += x_Pid
            self.PWMServo_Y += y_Pid
        else:
            self.PWMServo_X  -= x_Pid
            self.PWMServo_Y  += y_Pid

        if self.PWMServo_X  >= 40:
            self.PWMServo_X  = 40
        elif self.PWMServo_X  <= -40:
            self.PWMServo_X  = -40
        if self.PWMServo_Y >= 20:
            self.PWMServo_Y = 20
        elif 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 controller
        each of the parameters may be a vector if they have the same length
        Args:
        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 = 0
        self.integrator = 0
        self.timeOfLastCall = None
        self.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 constructor
        Returns:
            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 applied
            self.timeOfLastCall = time.perf_counter()
            return np.zeros(np.size(current_value))
        error = self.setPoint - current_value
        P = error
        currentTime = time.perf_counter()
        deltaT = (currentTime - self.timeOfLastCall)
        # integral of the error is current error * time since last update
        self.integrator = self.integrator + (error * deltaT)
        I = self.integrator
        # derivative is difference in error / time since last update
        D = (error - self.last_error) / deltaT
        self.last_error = error
        self.timeOfLastCall = currentTime
        # return controll signal
        return self.Kp * P + self.Ki * I + self.Kd * D



def main():
    rclpy.init()
    face_Tracker = faceTracker("FaceTracker")
    try:
        rclpy.spin(face_Tracker)
    except KeyboardInterrupt:
        pass
    finally:
        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查看节点如下

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2295947.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序调用企业微信客户服务插件联通企业微信客服

需求背景:用户在小程序页面点击按钮添加企业微信的客服 相关技术:基于uniapp开发的微信小程序 插件名称:企业微信客户服务插件「联系我」插件 - 文档 - 企业微信开发者中心 仔细阅读文档「联系我」插件 - 文档 - 企业微信开发者中心 以下是我的实例代码 1.首先先小程序管…

【AI实践】deepseek支持升级git

当前Windows 11 WSL的git是2.17&#xff0c;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…

Maven 安装配置(完整教程)

文章目录 一、Maven 简介二、下载 Maven三、配置 Maven3.1 配置环境变量3.2 Maven 配置3.3 IDEA 配置 四、结语 一、Maven 简介 Maven 是一个基于项目对象模型&#xff08;POM&#xff09;的项目管理和自动化构建工具。它主要服务于 Java 平台&#xff0c;但也支持其他编程语言…

w196Spring Boot高校教师科研管理系统设计与实现

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…

(1/100)每日小游戏平台系列

每日小游戏平台 项目简介以及地址 准备开发一个一百天小游戏平台&#xff0c;使用Flask构建的简单游戏导航网站&#xff0c;无需登录&#xff0c;让大家在返工的同时也可以愉快的摸鱼玩耍。 每天更新一个小游戏上传&#xff0c;看看能不能坚持一百天。 这些小游戏主要使用前端…

IMX6ULL环境搭建遇到的问题和解答更新

IMX6ULL环境搭建遇到的问题 开发板&#xff1a;正点原子IMX6ULL 终端软件串口控制&#xff1a;MobaXterm 1、网络环境搭建三方互ping不通 电脑无网口&#xff0c;使用绿联USB转网口&#xff0c;接网线直连开发板&#xff0c;电脑WiFi上网 按文档设置的 IP 地址&#xff0c;以…

BFS算法篇——广度优先搜索,探索未知的旅程(上)

文章目录 前言一、BFS的思路二、BFS的C语言实现1. 图的表示2. BFS的实现 三、代码解析四、输出结果五、总结 前言 广度优先搜索&#xff08;BFS&#xff09;是一种广泛应用于图论中的算法&#xff0c;常用于寻找最短路径、图的遍历等问题。与深度优先搜索&#xff08;DFS&…

Django开发入门 – 0.Django基本介绍

Django开发入门 – 0.Django基本介绍 A Brief Introduction to django By JacksonML 1. Django简介 1) 什么是Django? 依据其官网的一段解释&#xff1a; Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. …

idea整合deepseek实现AI辅助编程

1.File->Settings 2.安装插件codegpt 3.注册deepseek开发者账号&#xff0c;DeepSeek开放平台 4.按下图指示创建API KEY 5.回到idea配置api信息&#xff0c;File->Settings->Tools->CodeGPT->Providers->Custom OpenAI API key填写deepseek的api key Chat…

加速汽车软件升级——堆栈刷写技术的应用与挑战

一、背景和挑战 | 背景&#xff1a; 当前汽车市场竞争激烈&#xff0c;多品牌并存&#xff0c;新车发布速度加快&#xff0c;价格逐渐降低&#xff0c;功能日益多样化。随着车辆功能的不断提升与优化&#xff0c;ECU&#xff08;电子控制单元&#xff09;的代码量也随之增加&…

2. UVM的基本概念和架构

文章目录 前言1. UVM的基本概念1.1 UVM的核心组件1.2 UVM的基本架构1.3 UVM的工作流程 2. UVM的架构2.1 UVM的层次结构2.2 UVM的组件交互 3. 总结 前言 首先&#xff0c;得确定UVM的基本概念和架构包含哪些关键部分。我回忆起UVM的核心组件&#xff0c;比如uvm_component、uvm…

【力扣】138.随机链表的复制

AC截图 题目 代码 使用哈希存储<旧节点&#xff0c;新结点> /* // 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…

归一化与伪彩:LabVIEW图像处理的区别

在LabVIEW的图像处理领域&#xff0c;归一化&#xff08;Normalization&#xff09;和伪彩&#xff08;Pseudo-coloring&#xff09;是两个不同的概念&#xff0c;虽然它们都涉及图像像素值的调整&#xff0c;但目的和实现方式截然不同。归一化用于调整像素值的范围&#xff0c…

Ollama + AnythingLLM + Deepseek r1 实现本地知识库

1、Ollama&#xff1a;‌是一个开源的大型语言模型 (LLM)服务工具&#xff0c;旨在简化在本地运行大语言模型的过程&#xff0c;降低使用大语言模型的门槛‌。 2、AnythingLLM&#xff1a;是由Mintplex Labs Inc. 开发的一款全栈应用程序&#xff0c;旨在构建一个高效、可定制、…

Deepseek-v3 / Dify api接入飞书机器人go程序

准备工作 开通了接收消息权限的飞书机器人&#xff0c;例如我希望用户跟飞书机器人私聊&#xff0c;就需要开通这个权限&#xff1a;读取用户发给机器人的单聊消息 im:message.p2p_msg:readonly准备好飞书机器人的API key 和Secretdeepseek-v3的api keysecret&#xff1a;http…

详解策略模式

引言 实现一个目标往往有多种方式&#xff0c;比如从上海到北京&#xff0c;可以选择高铁、火车、飞机、自驾等等。同样实现一个功能我们可能也有多种方法&#xff0c;把这些方法封装为算法&#xff0c;根据不同的需求选择不同的算法&#xff08;策略&#xff09;&#xff0c;让…

2025影视泛目录站群程序设计_源码二次开发新版本无缓存刷新不变实现原理

1. 引言 本设站群程序计书旨在详细阐述苹果CMS泛目录的创新设计与实现&#xff0c;介绍无缓存刷新技术、数据统一化、局部URL控制及性能优化等核心功能&#xff0c;以提升网站访问速度和用户体验。 2. 技术概述 2.1 无缓存刷新技术 功能特点&#xff1a; 内容不变性&#x…

【RabbitMQ】RabbitMQ的下载安装及使用

安装RabbitMQ 下载网站&#xff1a;https://www.rabbitmq.com/docs/install-windows 点击后&#xff0c;会直接定位到依赖介绍位置&#xff0c;告诉你需要安装Erlang 下载Erlang Erlang也是一种编程语言&#xff0c;只是比较小众&#xff0c;但其拥有极为出色的性能 这个网站是…

Stylelint 如何处理 CSS 预处理器

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Word中Ctrl+V粘贴报错问题

Word中CtrlV粘贴时显示“文件未找到&#xff1a;MathPage.WLL”的问题 Word的功能栏中有MathType&#xff0c;但无法使用&#xff0c;显示灰色。 解决方法如下&#xff1a; 首先找到MathType安装目录下MathPage.wll文件以及MathType Commands 2016.dotm文件&#xff0c;分别复…