Xtrak 塔克小车巡线代码以及红绿灯识别相关小改动

news2024/11/16 2:46:29

做的小改动:

        只更改了xtark_follow_line.py

        增加了一次HSV分割来做红绿灯识别(建议到时候用手机或者平板显示红色或者绿色图片),红绿图片:

 

        将检测道路位置的方式从重心变为最接近屏幕中心的道路像素点。

        检测不到道路之后会检测上面一段区域,来处理断线

        修改速度处理函数来使得运行更平稳

答辩的PPT下载:比较简洁,非常建议使用自带的PowerPoint打开,(因为用了平滑切换)

里面有一点演示视频(小车部分)

改动前原始代码:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import rospy
import cv2
from cv_bridge import CvBridge, CvBridgeError
from sensor_msgs.msg import Image
import numpy
from geometry_msgs.msg import Twist

# 色彩矩阵,当前测试出的几种色彩
color_arry = [[100,55,90,130,215,170], # red
              [0,220,160,20,255,220],# blue
              [20,155,45,60,195,85], # green
              [75,195,195,115,235,255], # yellow
              [0,0,0,150,40,46]]    # black
# 记录颜色跟随时的误差值
diff= 0
d_diff= 0
last_diff= 0

def line_follow_init():    
    #define topic publisher and subscriber
    global color_mode, bridge, image_sub, mask_pub, result_pub, pub_cmd
    bridge = CvBridge()
    image_sub = rospy.Subscriber("/camera/rgb/image_raw", Image, callback)
    mask_pub = rospy.Publisher("/mask_image", Image, queue_size=1)
    result_pub = rospy.Publisher("/line_image", Image, queue_size=1)
    pub_cmd = rospy.Publisher('cmd_vel', Twist, queue_size=5)

    color_mode = int(rospy.get_param('~color_mode'))
    rospy.loginfo('color_mode:%d', color_mode)


def callback(data):
    global raw_image, mask_image
    # convert ROS topic to CV image formart
    # 将将ROS主题转换为CV图像格式
    raw_image = bridge.imgmsg_to_cv2(data, "bgr8")
    raw_image = cv2.resize(raw_image, (320,240), interpolation=cv2.INTER_AREA)#提高帧率
    # 将图像从 RGB 转为 HSV    
    hsv_image = cv2.cvtColor(raw_image,cv2.COLOR_RGB2HSV)

    # close operation to fit some little hole
    # 创建一个5行5列的数组
    kernel = numpy.ones((5,5),numpy.uint8)
    # 对图片进行膨胀腐蚀操作
    hsvimage_erode = cv2.erode(hsv_image,kernel,iterations=1)
    hsvimag_dilate = cv2.dilate(hsvimage_erode,kernel,iterations=1)
    # 设置图像的HSV阈值
    # h_low s_low v_low
    color_lower = numpy.array([color_arry[color_mode][0],color_arry[color_mode][1],color_arry[color_mode][2]])
    # h_upper s_upper v_upper
    color_upper = numpy.array([color_arry[color_mode][3],color_arry[color_mode][4],color_arry[color_mode][5]])
    # 得到处理后的二值化图像
    mask_image = cv2.inRange(hsvimag_dilate,color_lower,color_upper)
    masked = cv2.bitwise_and(raw_image, raw_image, mask=mask_image)
    # 图像处理函数
    image_processing()


# 对原始图像进行处理,获得我们需要的图像部分
def image_processing():
    res = raw_image
    h, w, d = res.shape
    search_top = h-20
    search_bot = h
    mask_image[0:search_top, 0:w] = 0
    mask_image[search_bot:h, 0:w] = 0
    # 计算二值化图像的重心,即几何中心
    P = cv2.moments(mask_image)
    # 得到可识别的颜色数据,进行识别和色差计算
    if P['m00'] > 0:
        ix = int(P['m10']/P['m00'])
        iy = int(P['m01']/P['m00'])
        cv2.circle(res, (ix, iy), 10, (255, 0, 255), -1)
        if cv2.circle:
            diff= ix - w/2-15
            d_diff=diff-last_diff
            twist_calculate(diff,d_diff)
    else:
        twist = Twist()
        twist.linear.x = 0
        twist.linear.y = 0
        twist.linear.z = 0
        twist.angular.x = 0
        twist.angular.y = 0
        twist.angular.z = 0
        pub_cmd.publish(twist)

    # 将实际图像和二值化图像通过话题发出
    img_msg = bridge.cv2_to_imgmsg(res, encoding="bgr8")
    img_msg.header.stamp = rospy.Time.now()
    result_pub.publish(img_msg)
    img_msg = bridge.cv2_to_imgmsg(mask_image, encoding="passthrough")
    img_msg.header.stamp = rospy.Time.now()
    mask_pub.publish(img_msg)



# 速度处理函数
def twist_calculate(twist_erro,twist_d_erro):
    twist = Twist()
    twist.linear.x = 0.2
    twist.linear.y = 0
    twist.linear.z = 0
    twist.angular.x = 0
    twist.angular.y = 0
    twist.angular.z = 0
    if twist_erro!=0:
        twist.angular.z = -float(twist_erro)*0.005-float(twist_d_erro)*0.000
    else:
        twist.angular.z = 0
    last_diff=diff
    pub_cmd.publish(twist)



if __name__ == '__main__':
    try:
        # init ROS node 
        rospy.init_node("line_follow")
        rospy.loginfo("Starting Line Follow node")
        line_follow_init()
        rospy.spin()
    except KeyboardInterrupt:
        print ("Shutting down cv_bridge_test node.")
        cv2.destroyAllWindows()

改动后代码:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import time

import rospy
import cv2
from cv_bridge import CvBridge, CvBridgeError
from sensor_msgs.msg import Image
import numpy
from geometry_msgs.msg import Twist

# 色彩矩阵,当前测试出的几种色彩
color_arry = [[100, 55, 90, 130, 215, 170],  # red
              [0, 220, 160, 20, 255, 220],  # blue
              [20, 155, 45, 60, 195, 85],  # green
              [75, 195, 195, 115, 235, 255],  # yellow
              [0, 0, 0, 150, 40, 46], ]  # black
# 记录颜色跟随时的误差值
diff = 0
d_diff = 0
last_diff = 0
up_diff = 0
red_light = False  # 遇见红灯


def line_follow_init():
    # define topic publisher and subscriber
    global color_mode, bridge, image_sub, mask_pub, result_pub, pub_cmd
    bridge = CvBridge()
    image_sub = rospy.Subscriber("/camera/rgb/image_raw", Image, callback)
    mask_pub = rospy.Publisher("/mask_image", Image, queue_size=1)
    result_pub = rospy.Publisher("/line_image", Image, queue_size=1)
    pub_cmd = rospy.Publisher('cmd_vel', Twist, queue_size=5)

    color_mode = int(rospy.get_param('~color_mode'))
    rospy.loginfo('color_mode:%d', color_mode)


def callback(data):
    global raw_image, mask_image, red_light
    # convert ROS topic to CV image formart
    # 将将ROS主题转换为CV图像格式
    raw_image = bridge.imgmsg_to_cv2(data, "bgr8")
    raw_image = cv2.resize(raw_image, (320, 240), interpolation=cv2.INTER_AREA)  # 提高帧率
    # 将图像从 RGB 转为 HSV    
    hsv_image = cv2.cvtColor(raw_image, cv2.COLOR_RGB2HSV)

    # close operation to fit some little hole
    # 创建一个5行5列的数组
    kernel = numpy.ones((5, 5), numpy.uint8)
    # 对图片进行膨胀腐蚀操作
    # hsvimage_erode = cv2.erode(hsv_image, kernel, iterations=1)
    # hsvimag_dilate = cv2.dilate(hsvimage_erode, kernel, iterations=1)
    # 设置图像的HSV阈值
    # h_low s_low v_low
    color_lower = numpy.array([color_arry[color_mode][0], color_arry[color_mode][1], color_arry[color_mode][2]])
    # h_upper s_upper v_upper
    color_upper = numpy.array([color_arry[color_mode][3], color_arry[color_mode][4], color_arry[color_mode][5]])
    # 得到处理后的二值化图像
    mask_image = cv2.inRange(hsv_image, color_lower, color_upper)
    # 红灯和绿灯的HSV并二值化
    color_red_lower = numpy.array([100, 170, 120])
    color_red_upper = numpy.array([130, 240, 240])
    color_green_lower = numpy.array([65, 220, 150])
    color_green_upper = numpy.array([80, 230, 220])
    # 自行设置,让红绿灯出现在非0条内
    h, w = mask_image.shape
    search_top = h - 140
    search_bot = h - 80
    # 没遇到红灯找红灯
    if not red_light:
        mask_red_image = cv2.inRange(hsv_image, color_red_lower, color_red_upper)
        # 自行调参
        mask_red_image = cv2.erode(mask_red_image, kernel, iterations=1)
        if numpy.amax(mask_red_image) > 0:
            print("遇到红灯")
            red_light = True
            pass
    else:  # 遇到找绿灯
        mask_green_image = cv2.inRange(hsv_image, color_green_lower, color_green_upper)
        # 自行调参
        mask_green_image = cv2.erode(mask_green_image, kernel, iterations=1)
        if numpy.amax(mask_green_image) > 0:
            print("遇到绿灯")
            red_light = False
            pass
    if red_light:  # 红灯停
        twist = Twist()
        twist.linear.x = 0
        twist.linear.y = 0
        twist.linear.z = 0
        twist.angular.x = 0
        twist.angular.y = 0
        pub_cmd.publish(twist)
    else:
        # masked = cv2.bitwise_and(raw_image, raw_image, mask=mask_image)
        # 图像处理函数
        image_processing()


# 对原始图像进行处理,获得我们需要的图像部分
def image_processing():
    global mask_image, up_diff, last_diff, diff
    res = raw_image
    h, w, d = res.shape
    search_top = h - 20
    search_bot = h
    img_up = mask_image.copy()
    mask_image[0:search_top, 0:w] = 0
    mask_image[search_bot:h, 0:w] = 0
    # 计算二值化图像
    P = [None, None]
    for i in range(w // 2 - 17):
        if P[0] is not None:
            break
        for j in range(20):
            if P[0] is not None:
                break
            if not mask_image[search_top + j, w // 2 - 15 + i] == 0:
                P = [search_top + j, w // 2 - 15 + i]
            elif not mask_image[search_top + j, w // 2 - 15 - i] == 0:
                P = [search_top + j, w // 2 - 15 - i]
    # 得到可识别的颜色数据,进行识别和色差计算
    if P[0] is not None:  # 如果在最下面找到线
        ix = int(P[1])
        iy = int(P[0])
        cv2.circle(res, (ix, iy), 10, (255, 0, 255), -1)
        if cv2.circle:
            diff = ix - w / 2
            d_diff = diff - last_diff
            twist_calculate(diff, d_diff)
    else:  # 如果在最下面没有找到线
        search_top = h - 60  # 在远处找找有没有线(断线)
        search_bot = h - 20
        mask_image = img_up[:]
        mask_image[0:search_top, 0:w] = 0
        mask_image[search_bot:h, 0:w] = 0
        for i in range(w // 2 - 17):
            if P[0] is not None:
                break
            for j in range(40):
                if P[0] is not None:
                    break
                if not mask_image[search_top + j, w // 2 - 15 + i] == 0:
                    P = [search_top + j, w // 2 - 15 + i]
                elif not mask_image[search_top + j, w // 2 - 15 - i] == 0:
                    P = [search_top + j, w // 2 - 15 - i]
        # 得到可识别的颜色数据,进行识别和色差计算
        if P[0] is not None:  # 如果在最下面找到线
            ix = int(P[1])
            iy = int(P[0])
            cv2.circle(res, (ix, iy), 10, (255, 0, 255), -1)
            if cv2.circle:
                diff = ix - w / 2
                d_diff = diff - last_diff
                twist_calculate(diff, d_diff)
        else:  # 还没找到,朝上次看见线的方向旋转
            twist = Twist()
            twist.linear.x = 0
            twist.linear.y = 0
            twist.linear.z = 0
            twist.angular.x = 0
            twist.angular.y = 0
            if up_diff > 0:
                twist.angular.z = -0.2
            else:
                twist.angular.z = +0.2
            pub_cmd.publish(twist)

    # 将实际图像和二值化图像通过话题发出
    img_msg = bridge.cv2_to_imgmsg(res, encoding="bgr8")
    img_msg.header.stamp = rospy.Time.now()
    result_pub.publish(img_msg)
    img_msg = bridge.cv2_to_imgmsg(mask_image, encoding="passthrough")
    img_msg.header.stamp = rospy.Time.now()
    mask_pub.publish(img_msg)


# 速度处理函数
def twist_calculate(twist_erro, twist_d_erro):
    global last_diff, up_diff, diff
    twist = Twist()
    twist.linear.x = 0.1
    twist.linear.y = 0
    twist.linear.z = 0
    twist.angular.x = 0
    twist.angular.y = 0
    if abs(twist_erro) < 20:  # 有偏转,向重心方向偏转
        twist.angular.z = 0
    else:
        twist.angular.z = -float(twist_erro) * 0.0025 - float(twist_d_erro) * 0.000
        up_diff = twist_d_erro
        if abs(twist_erro) > 100:  # 太大了,停下来慢慢转
            twist.linear.x = 0
    last_diff = diff
    pub_cmd.publish(twist)


if __name__ == '__main__':
    try:
        # init ROS node 
        rospy.init_node("line_follow")
        rospy.loginfo("Starting Line Follow node")
        line_follow_init()
        rospy.spin()
    except KeyboardInterrupt:
        print("Shutting down cv_bridge_test node.")
        cv2.destroyAllWindows()

 建议通过U盘拷到小车上(建议复制粘贴文本进去,不要复制粘贴文件进去)通过远程传输,远程连接,虚拟机之类的,里面的中文可能会变成乱码,暂不知道对运行有何影响

如果在小车上不能运行,请右键该文件,选择属性,第二栏,勾选可执行选项。

 

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

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

相关文章

ubuntu 22.04部署dzzoffice及安装onlyoffice插件

目录 一、配置阿里源 二、安装数据库 三、安装依赖组件 &#xff08;一&#xff09;安装php7.4 &#xff08;二&#xff09;安装apache2 四、下载 dzzoffice 五、安装dzzoffice 六、安装onlyoffice插件 &#xff08;一&#xff09;从github下载小胡版onlyoffice替代原来…

如何学习及计算机编程,入门看这一篇就够了---以c语言为例

信息时代&#xff0c;计算机变成不再是专业性很强的一门学科&#xff0c;更多的是变成了一种工具 用计算机爬取信息&#xff08;爬虫&#xff09;进行数据分析&#xff0c;数据可视化&#xff08;大数据的某个方面&#xff09;处理海量的数据&#xff0c;如excel&#xff08;百…

声音生成项目(4)——从VariantAutoencoder(VAE)到VQ-VAE矢量量化变分编码器

文章目录 论文介绍步骤具体讲解自定义矢量量化层获取最近距离的码字的索引计算推导损失函数相关参考 矢量量化层的代码实现完整代码实现 论文介绍 不同于变分编码器和自动编码器&#xff0c;vq-vae中的latent space是离散的&#xff0c;并不是连续的&#xff0c;这能够避免后验…

第3章“程序的机器级表示”:理解指针

指针是 C 语言的一个重要特色。它们提供一种统一方式&#xff0c;能够远程访问数据结构。 指针基本的概念其实非常简单&#xff0c;下面的代码说明了许多这样的概念&#xff1a; struct str { /* Example Structure */int t;char v; };union uni { /* Example Union */int t;…

大厂C++面试基础题第1辑——虚函数七题精讲之一

> “虚函数的作用” 是面向对象的C编程最基础也最核心的知识点&#xff0c;如果不能无法正确回答本题&#xff0c;则只此一题&#xff0c;不管大厂还是小厂&#xff0c;都铁定无缘了。 概述 “虚函数” 是 C面向对象三最&#xff1a;最基础、最重要、最关键的知识点。我们从…

什么是Vue的Vite构建工具?如何使用Vite进行项目开发

什么是Vue的Vite构建工具&#xff1f;如何使用Vite进行项目开发 介绍 Vite是一个由Vue.js核心团队开发的构建工具。它的目标是提供一种快速的开发体验&#xff0c;同时保持生产环境的稳定性和可靠性。Vite使用了ES模块作为开发环境的原生模块格式&#xff0c;通过在开发服务器…

C++11中的关键字constexpr

文章目录 1、constexpr修饰普通变量2、constexpr修饰函数3、constexpr修饰类的构造函数 constexpr 关键字的功能是使指定的常量表达式获得在程序编译阶段计算出结果的能力&#xff0c;而不必等到程序运行阶段。C 11 标准中&#xff0c;constexpr 可用于修饰普通变量、函数&…

【Leetcode】DP | 序列及子数组问题

300 最长递增子序列 求数组最长严格递增子序列的长度。 D [ i ] D[i] D[i]代表以 n u m s [ i ] nums[i] nums[i]结尾的最长递增子序列的长度。 D [ i ] max ⁡ j < i , n u m s [ i ] > n u m s [ j ] ( D [ j ] 1 ) D[i] \max_{j < i,\ nums[i]>nums[j]}(D[…

什么是Vue的UI框架?

什么是Vue的UI框架&#xff1f; Vue.js 是一款流行的 JavaScript 框架&#xff0c;用来构建现代的单页面应用程序&#xff08;SPA&#xff09;。Vue.js 提供了丰富的功能和 API&#xff0c;但是在构建应用程序时&#xff0c;我们还需要使用一些 UI 组件来实现复杂的交互和界面…

【分布式能源选址与定容】光伏、储能双层优化配置接入配电网研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

02- 输入、输出及运算符(C语言)

一 输入、输出 1.1 输出函数 printf 函数是一个可变参数函数&#xff0c;参数的个数不定&#xff1a;int printf(const char *format, ...) printf("%d\n", x); printf("%d %d\n", x, y); 1.2 输入函数 1.2.1 scanf函数&#xff1a;int scanf(const …

利用AI点亮副业变现:5个变现实操案例的启示

AI变现副业实操案例 宝宝起名服务AI科技热点号头像壁纸职业头像收徒&#xff1a;萌娃头像定制头像平台挂载 小说推广号流量营销号百家号AI共创计划公众号流量主 知识付费知识星球小报童&#xff1a; 整体思维导图&#xff1a; 在这里先分享五个实操案例: 宝宝起名服务AI科技热…

[MySQL]一文带你学明白数据库控制语言——DCL

前言 嗨咯&#xff0c;小伙伴大家好呀&#xff01;好几天没见了&#xff0c;周末过得怎么样啊&#xff01;之前学过的SQL语句不会都忘了吧。如果忘了的话大家可以看一下前几期的文章。本期要学习的是SQL语句中的数据库控制语句——DCL&#xff0c;学习完毕之后MySQL中的SQL语句…

探索ll-hls低延迟直播协议

HLS全称为HTTP Live Streaming&#xff0c;其中m3u8作为描述协议&#xff0c;指向一系列切片文件。支持多码流与自适应码率&#xff0c;支持广告无缝播放&#xff0c;支持CMAF协议的低延时直播&#xff0c;也支持CDN动态选择。 我们先看下HLS整体架构&#xff0c;由三部分构成…

存储技术3 数据保护: RAID

Why RAID 性能限制了磁盘驱动单独的驱动存在预期的使用寿命 MTBF测量若一个驱动器的MTBF是750 000小时&#xff0c; 阵列中有100个驱动&#xff0c; 阵列的MTBF会变成 750000 / 100 7500小时 RAID用于减缓这个问题RAID特点 增大容量高可用性增强的性能 RAID implementation…

仿微信我的列表功能菜单按钮 我的个人中心页面功能菜单

前端vue自定义仿微信我的列表功能菜单按钮 我的个人中心页面功能菜单, 下载完整代码请访问https://ext.dcloud.net.cn/plugin?id12990 效果图如下: #### 使用方法 使用方法 <!-- leftTitle:标题 icon&#xff1a;左边图标 click&#xff1a;点击事件 --> <ccMe…

【java】IO流

IO流 原理 分类 字节流与字符流 节点流与包装流 Java IO详解&#xff08;五)------包装流 - YSOcean - 博客园 (cnblogs.com)JAVA I/O流 字符流和字节流、节点流和处理流(包装流、过滤流)、缓冲流_过滤流和缓冲流,字节流的关系_X-Dragon烟雨任平生的博客-CSDN博客 字符流 i…

算法模板(4):动态规划(2)

8.树形DP 没有上司的舞会 树上最大独立集问题 Ural 大学有 N N N 名职员&#xff0c;编号为 1 ∼ N 1 \sim N 1∼N。他们的关系就像一棵以校长为根的树&#xff0c;父节点就是子节点的直接上司。每个职员有一个快乐指数&#xff0c;用整数 H i H_i Hi​ 给出&#xff0c;…

顺序查找和折半查找

顺序查找和折半查找 顺序查找 一、算法思想 顺序查找&#xff0c;又叫“线性查找”&#xff0c;通常用于线性表。 算法思想&#xff1a;从头到尾挨个找&#xff08;或者反过来也OK&#xff09; 二、算法实现 结构体定义 typedef struct{ElemType *elem;int TableLen; }SS…

SpringBoot + Vue 的留守儿童系统的研究与实现

文章目录 1.研究背景2. 技术栈3.系统分析4系统设计5系统的详细设计与实现5.1系统功能模块5.2管理员功能模块 1.研究背景 以往的留守儿童爱心的管理&#xff0c;一般都是纸质文件来管理留守儿童爱心信息&#xff0c;传统的管理方式已经无法满足现代人们的需求&#xff1b;使用留…