树莓派,opencv,Picamera2利用舵机云台追踪特定颜色对象

news2024/12/24 8:20:07

一、需要准备的硬件

  1. Raspiberry 4b
  2. 两个SG90 180度舵机(注意舵机的角度,最好是180度且带限位的,切勿选360度舵机)
  3. 二自由度舵机云台(如下图)
  4. Raspiberry CSI 摄像头
    组装后的效果:
    在这里插入图片描述

二、项目目标

追踪特定颜色的物体:
当物体移动时,摄像头通过控制两个伺服电机(分别是偏航和俯仰)把该物体放到视界的中心位置,我在这里追踪的是一支红色的铅笔。

三、具体步骤

3.1 获得被追踪对象的颜色参数

  1. 提前准备一张图片(如下图),可以直接用树莓派的CSI摄像头拍摄并保存,具体方法可以在我之前的文章里找到
    原始图片

  2. 利用下面的代码并通过调整滑块(Trackbar)获得红色铅笔的HSV颜色参数,为接下来的颜色追踪做准备

***color_detection.py***
import cv2
path='test_full.jpg'
cv2.namedWindow("TrackBar")

def nothing(x):
    pass
#创建滑块控件
cv2.createTrackbar("Hue Min","TrackBar",0,179,nothing)
cv2.createTrackbar("Hue Max","TrackBar",179,179,nothing)
cv2.createTrackbar("Sat Min","TrackBar",0,255,nothing)
cv2.createTrackbar("Sat Max","TrackBar",255,255,nothing)
cv2.createTrackbar("Val Min","TrackBar",0,255,nothing)
cv2.createTrackbar("Val Max","TrackBar",255,255,nothing)


while True:
    #读取目标图片
    image=cv2.imread(path)
    image=cv2.resize(image,(640,480))
    imgHSV=cv2.cvtColor(image,cv2.COLOR_BGR2HSV)
    hueLow=cv2.getTrackbarPos("Hue Min","TrackBar")
    hueHigh=cv2.getTrackbarPos("Hue Max","TrackBar")
    satLow=cv2.getTrackbarPos("Sat Min","TrackBar")
    satHigh=cv2.getTrackbarPos("Sat Max","TrackBar")
    valLow=cv2.getTrackbarPos("Val Min","TrackBar")
    valHigh=cv2.getTrackbarPos("Val Max","TrackBar")
    print(hueLow,hueHigh,satLow,satHigh,valLow,valHigh)
    #创建掩膜
    mask=cv2.inRange(imgHSV,(hueLow,satLow,valLow),(hueHigh,satHigh,valHigh))
    image=cv2.bitwise_and(image,image,mask=mask)
    #显示图像
    cv2.imshow('Origial',image)
    cv2.imshow('HSV',imgHSV)
    #按q键退出
    if cv2.waitKey(1)==ord('q'):
        break
cv2.destroyAllWindows() 
  1. 运行color_detection.py,并调整滑块(TrackBar)如下图,当然你的被追踪物体的颜色不同,参数也必然不同。
    滑块调整
    这时你会发现,红色铅笔被显示出来,其它部分被掩膜遮挡,记下Hue Min, Hui Max, Sat Min, Sat Max, Val Min, Val Max这六个数值在接下来的代码中会用到。
    在这里插入图片描述

3.2 目标追踪代码

  1. 输入color_detection.py里得到的六个参数到相应位置,注释里已经注明。
***color_tracking.py***
import cv2
from picamera2 import Picamera2
import time
import numpy as np
from servo import Servo
picam2 = Picamera2()

#偏航伺服电机连接上GPIO19脚,俯仰伺服电机信号线连接到GPIO16脚上
pan=Servo(pin=19)
tilt=Servo(pin=16)

panAngle=0
tiltAngle=0

pan.set_angle(panAngle)
tilt.set_angle(tiltAngle)

#初始化pi camera
dispW=1280
dispH=720
picam2.preview_configuration.main.size = (dispW,dispH)
picam2.preview_configuration.main.format = "RGB888"
picam2.preview_configuration.controls.FrameRate=30
picam2.preview_configuration.align()
picam2.configure("preview")
picam2.start()
fps=0
pos=(30,60)
font=cv2.FONT_HERSHEY_SIMPLEX
height=1.5
weight=3
myColor=(0,0,255)

def nothing(x):
    pass

cv2.namedWindow('myTracker')
#输入color_detection.py里得到的六个参数到xxx位置,比如cv2.createTrackbar('Hue Low','myTracker',xxx,179,nothing)
cv2.createTrackbar('Hue Low','myTracker',56,179,nothing)
cv2.createTrackbar('Hue High','myTracker',179,179,nothing)
cv2.createTrackbar('Sat Low','myTracker',165,255,nothing)
cv2.createTrackbar('Sat High','myTracker',255,255,nothing)
cv2.createTrackbar('Val Low','myTracker',77,255,nothing)
cv2.createTrackbar('Val High','myTracker',255,255,nothing)


while True:
    tStart=time.time()
    #获取取摄像头图片
    frame= picam2.capture_array()
    frame=cv2.flip(frame,1)
    frameHSV=cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
    cv2.putText(frame,str(int(fps))+' FPS',pos,font,height,myColor,weight)
    hueLow=cv2.getTrackbarPos('Hue Low','myTracker')
    satLow=cv2.getTrackbarPos('Sat Low','myTracker')
    valLow=cv2.getTrackbarPos('Val Low','myTracker')
    hueHigh=cv2.getTrackbarPos('Hue High','myTracker')
    satHigh=cv2.getTrackbarPos('Sat High','myTracker')
    valHigh=cv2.getTrackbarPos('Val High','myTracker')
    lowerBound=np.array([hueLow,satLow,valLow])
    upperBound=np.array([hueHigh,satHigh,valHigh])
    myMask=cv2.inRange(frameHSV,lowerBound,upperBound)
    myMaskSmall=cv2.resize(myMask,(int(dispW/2),int(dispH/2)))
    myObject=cv2.bitwise_and(frame,frame, mask=myMask)
    myObjectSmall=cv2.resize(myObject,(int(dispW/2),int(dispH/2)))
    
    contours,junk=cv2.findContours(myMask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
    if len(contours)>0:
        contours=sorted(contours,key=lambda x:cv2.contourArea(x),reverse=True)
        #cv2.drawContours(frame,contours,-1,(255,0,0),3)
        contour=contours[0]
        x,y,w,h=cv2.boundingRect(contour)
        cv2.rectangle(frame,(x,y),(x+w,y+h),(0,0,255),3)
        #偏航电机纠偏X轴方向上的偏差,大于30度,偏航角度减小,小于-30度,偏航角度增加
        errorX=dispW/2-(x+w/2)
        if errorX>30:
            panAngle=panAngle-1
            if panAngle<-90:
                panAngle=-90
            pan.set_angle(panAngle)
        if errorX<-30:
            panAngle=panAngle+1
            if panAngle>90:
                panAngle=90
            pan.set_angle(panAngle)
        #俯仰电机纠偏Y轴方向上的偏差,大于30度,俯仰角度减小,小于-30度,俯仰角度增加
        errorY=dispH/2-(y+h/2)
        if errorY>30:
            tiltAngle=tiltAngle-1
            if tiltAngle<-90:
                tiltAngle=-90
            tilt.set_angle(tiltAngle)
        if errorY<-30:
            tiltAngle=tiltAngle+1
            if tiltAngle>90:
                tiltAngle=90
            tilt.set_angle(tiltAngle)

        
    cv2.imshow('Camera',frame)
    cv2.imshow('Mask',myMaskSmall)
    cv2.imshow('My Object',myObjectSmall)
    #按q键退出
    if cv2.waitKey(1)==ord('q'):
    	pan.stop()
        tilt.stop()
        picam2.stop()
        break
    tEnd=time.time()
    loopTime=tEnd-tStart
    fps=.9*fps + .1*(1/loopTime)
cv2.destroyAllWindows()
  1. 上述代码中的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:
        break
    sleep(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*100
    MIN_PW = 250 # 2.5/20*100
    _freq = 50 # 50 Hz, 20ms
 
    def __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 = 0
        self.max_angle = max_angle
        self.min_angle = min_angle
        self.pi.set_PWM_dutycycle(self.pin, 0)

    def set_angle(self, angle):
        if angle > self.max_angle:
            angle = self.max_angle
        elif angle < self.min_angle:
            angle = self.min_angle
        self.angle = angle
        duty = self.map(angle, -90, 90, 250, 1250)
        self.pi.set_PWM_dutycycle(self.pin, duty)


    def get_angle(self):
        return self.angle

	def 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):
    #     pass

    def map(self, x, in_min, in_max, out_min, out_max):
        return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min


if __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 = 0
    tiltAngle = 0
    pan.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)


  1. 运行object_tracking.py,移动红色铅笔,摄像头就会自动追踪该对象
    在这里插入图片描述

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

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

相关文章

视频美颜SDK技术的演变:从基础滤镜到智能特效

视频美颜SDK通过提供一系列的算法和工具&#xff0c;让开发者可以方便地集成美颜功能到他们的应用中。 一、背景&#xff1a;美颜技术的崛起 随着高清摄像设备的普及&#xff0c;用户对于自己在视频中的外观要求也变得越来越高。美颜技术应运而生&#xff0c;开始从照片领域渗…

freeRTOS使用

创建第一个FreeRTOS程序 1、官网源码下载 &#xff08;1&#xff09;进入FreeRTOS官网FreeRTOS professional services for application and RTOS development and consulting. FreeRTOS is an Open Source Code RTOS &#xff08;2&#xff09;点击下载FreeRTOS 2、处理目录 &…

千梦网创:有些事做的不如一泡尿顺畅

狗急了会跳墙&#xff0c;尿急了到路旁。 如果你有过在路边停车尿尿的经历&#xff0c;你一定体会过极度渴望是一种什么感觉。 你对那一刻的释放有着不可遏制无法压抑的情怀&#xff0c;所以不论时间地点人物情节&#xff0c;你都会风雨无阻的立即停在路边去解决你的“燃眉之…

数据结构与算法—排序算法(一)时间复杂度和空间复杂度介绍

排序算法 文章目录 排序算法1.排序算法的介绍1.1 排序的分类 2.算法的时间复杂度2.1 度量一个程序(算法)执行时间的两种方法2.2 时间频度2.2.1 忽略常数项2.2.2 忽略低次项2.2.3 忽略系数 2.3 时间复杂度2.3.1 常见的时间复杂度2.3.1.1 常数阶 O ( 1 ) O(1) O(1)2.3.1.2 对数阶…

8.STP生成树协议

8.STP生成树协议 资源被大量占用,网络卡顿,除非某条链路断开,不然会一直转发下去,不停的占用资源 同一个MAC地址,先从3口发来,又从2口发来,MAC地址表就会将旧的删掉,认为这个MAC地址属于2口所接的设备 有环路的时候,会禁用一个端口,虽然插着,但是处于阻塞状态 当另一条线路断开…

LAMP与LNMP架构

一、概述 LAMP架构是目前成熟的企业网站应用模式之一&#xff0c;指的是协同工作的一整套系统和相关软件&#xff0c;能够提供动态Web站点服务及其应用开发环境。LAMP是一个缩写词&#xff0c;具体包括Linux操作系统、Apache网站服务器、MySQL数据库服务器、PHP&#xff08;或…

viple与物理机器人(一):线控模拟

为了检测viple程序与物理机器人是否能顺利连接上 如果能顺利连接上&#xff0c;那么&#xff0c;可以通过内建事件从而控制物理机器人的前进、后退、左转、右转以及暂停。 如果不能连接上&#xff0c;首先&#xff0c;程序无法控制物理机器人&#xff0c;其次&#xff0c;当vip…

JavaEE之多线程编程:1. 基础篇

文章目录 一、关于操作系统一、认识进程 process二、认识线程三、进程和线程的区别&#xff08;重点&#xff01;&#xff09;四、Java的线程和操作系统线程的关系五、第一个多线程编程 一、关于操作系统 【操作系统】 驱动程序&#xff1a; 如&#xff1a;我们知道JDBC的驱动程…

Python 日期时间模块详解(datetime)

文章目录 1 概述1.1 datetime 类图1.2 类描述 2 常用方法2.1 获取当前日期时间&#xff1a;now()、today()、time()2.2 日期时间格式化&#xff1a;strftime()2.3 日期时间大小比较&#xff1a;>、、<2.4 日期时间间隔&#xff1a;- 3 扩展3.1 Python 中日期时间格式化符…

GEE:构建和调用自己的 js 函数库

作者&#xff1a;CSDN _养乐多_ 本文记录了在Google Earth Engine&#xff08;GEE&#xff09;上构建自己的 js 函数库的步骤。构建自己的函数库以方便代码调用和扩展。 文章目录 一、创建lib文件二、调用lib库三、附加3.1 定义函数3.2 js 库中函数互相调用 一、创建lib文件 …

05_W5500_UDP通信

上两节我们分别完成了的客户端和服务端的测试&#xff0c;这节我们要实现W5500UDP通信。 目录 1.UDP通信介绍&#xff1a; 2.UDP的通信流程: 3.代码分析: 4.测试 1.UDP通信介绍&#xff1a; UDP提供不可靠服务&#xff0c;具有TCP所没有的优势&#xff1a; UDP无连接&…

天津大学博士论文查重率要求【保姆教程】

大家好&#xff0c;今天来聊聊天津大学博士论文查重率要求&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff1a; 天津大学博士论文查重率要求 引言 作为国内知名的高等学府之一&#xff0c;天津大学一直秉持着…

kafka学习笔记--broker工作流程、重要参数

本文内容来自尚硅谷B站公开教学视频&#xff0c;仅做个人总结、学习、复习使用&#xff0c;任何对此文章的引用&#xff0c;应当说明源出处为尚硅谷&#xff0c;不得用于商业用途。 如有侵权、联系速删 视频教程链接&#xff1a;【尚硅谷】Kafka3.x教程&#xff08;从入门到调优…

uniCloud(二) 使用数据库、前端展示数据

一、在云服务空间的云数据库中新建一张表 &#xff08;1&#xff09;它有两种方式&#xff0c;我暂时手动创建一张表 &#xff08;2&#xff09;修改表结构&#xff1a;权限read为true &#xff08;3&#xff09;添加数据记录 注意&#xff1a;需要一条一条的加入

创建并测试第一个django项目并解决过程中遇到的问题

Django 是一个高级 Python Web 框架&#xff0c;它鼓励快速开发和简洁、实用的设计。它由经验丰富的开发人员构建&#xff0c;解决了 Web 开发的大部分麻烦&#xff0c;因此您可以专注于编写应用程序&#xff0c;而无需重新发明轮子。它是免费和开源的。 目录 一、django项目 …

Proxmark3 Easy救砖-20231209

事情是这样的&#xff0c;在淘宝买了个PM3&#xff0c;拿到手后刷固件的&#xff0c;一不小心刷成砖头了&#xff0c;现象就是四个灯全亮&#xff0c;插上电脑USB不识别。问商家他也不太懂&#xff0c;也是个半吊子技术&#xff0c;远程给我刷机搞了半天也没有搞定&#xff0c;…

9.MySQL 索引

目录 ​​​​​​​概述 概念&#xff1a; 单列索引 普通索引 创建索引 查看索引 删除索引 唯一索引 创建唯一索引 删除唯一索引 主键索引 组合索引 创建索引 全文索引 概述 使用全文索引 空间索引 内部原理 相关算法&#xff1a; hash算法 二叉树算法 …

Linux(17):认识与分析登录档

什么是登录档 【详细而确实的分析以及备份系统的登录文件】是一个系统管理员应该要进行的任务之一。 登录档 就是记录系统活动信息的几个文件&#xff0c;例如&#xff1a;何时、何地(来源IP)、何人(什么服务名称)、做了什么动作(讯息登录啰)。 换句话说就是&#xff1a;记录系…

谷歌云数据中心利用地热能实现能源转型突破

随着全球气候变化问题日益严重&#xff0c;各大公司纷纷寻求更加可持续的能源解决方案。作为科技巨头的谷歌&#xff0c;近日在内华达州的数据中心取得了突破性的进展&#xff0c;开始使用100%地热能供电&#xff0c;为全球数据中心能源转型树立了新的标杆。 作为全球最大的搜…

MySQL慢SQL优化思路

MySQL慢SQL优化思路 具体思路&#xff1a; 1、慢查询日志记录慢 SQL 2、explain 分析 SQL 的执行计划 3、profile 分析执行耗时 4、Optimizer Trace 分析详情 5、确定问题并采用相应的措施 1、查看慢日志 1.1 使用命令查询慢日志配置 mysql> show variables like s…