使用yolov8+ROS实现路标检测自动驾驶(jetson系列)

老师布置了一个实验,要我们用实验室的ros小车和深度学习实现自动驾驶。我靠,还自动驾驶,

心想着做一个路标检测的应付一下就行了。

实验设备:履带式差速ros小车,jetson nano , 2d激光雷达,usb相机

我们没有路标道具,也没有路道两侧的线,我是不会花钱买的,所以继续水一下,下载没有背景的路标数据集,训练测试,检测识别,用手机上的图片当做真实的物体。

在windows10训练Yolov8模型,得到最优参数,导出.onnx模型

在有英伟达显卡的windows10配置好yolov8环境,可以看我写的文章:

2.7环境配置篇

1.数据集下载:

Traffic Sign Recogntion Database (ia.ac.cn) 中国交通交通标志数据集

下载数据集,下载后发现有许多类别,并且标注格式不是yolo格式,于是先直接删除其他类别的图片和对应的标注文件,只留下我要的8个类别。然后,把格式转换成yolo格式。

 代码如下:

"""删除目录下不需要的类别,并保留需要的类别。删除图像和标签文件。"""
import os
# 需要保留的类别----------------------
keep_classes = ['002', '022', '024', '027', '031', '035', '042', '052']
new_order = ['000', '001', '002', '003', '004', '005', '006', '007'] #对保留的图像重新命名,比如002-类别名称的图片命名为000
# 删除train目录中不属于保留类别的图片
train_dir = "G:/AI211/ultralytics-main/datasets/Images/train"
test_dir = "G:/AI211/ultralytics-main/datasets/Images/test"
dataset="G:/AI211/ultralytics-main/datasets"
# 更新TsignRecgTrain4170Annotation.txt,删除与已删除图片相关的标签信息
annotation_file = "G:/AI211/ultralytics-main/datasets/TsignRecgTrain4170Annotation.txt"
updated_annotations = []
with open(annotation_file, 'r') as f:
    lines = f.readlines()

# ----------------------------------------------------
for class_dir in os.listdir(train_dir):
    classname=class_dir.split('_')[0]
    if classname not in keep_classes:
        file_path = os.path.join(train_dir, class_dir)
        os.remove(file_path)

for line in lines:
    parts = line.strip().split(';')
    image_name = parts[0]
    class_index = image_name.split('_')[0]
    if class_index in keep_classes:
        updated_annotations.append(line)
with open(annotation_file, 'w') as f:
    for line in updated_annotations:
        f.write(line)



# ------------------------------------------------------------

# 定义类别映射关系(这里假设类别编号与类别名称一一对应)
class_mapping = {
    '2': '0',
    '22': '1',
    '24': '2',
    '27': '3',
    '31': '4',
    '35': '5',
    '42': '6',
    '52': '7',
}
#
annotations = []
for line in lines:
    parts = line.strip().split(';')
    image_name = parts[0]
    width = int(parts[1])
    height = int(parts[2])
    x1 = int(parts[3])
    y1 = int(parts[4])
    x2 = int(parts[5])
    y2 = int(parts[6])
    class_index = parts[7]
    filename=image_name.split('.')[0]

    # 归一化边界框坐标
    x_center = (x1 + x2) / (2.0 * width)
    y_center = (y1 + y2) / (2.0 * height)
    bbox_width = (x2 - x1)*1.0 / width  #矩形框的宽除以图片的宽
    bbox_height = (y2 - y1)*1.0 / height

    # 将类别编号转换为类别名称
    class_name = class_mapping.get(class_index)

    # 生成YOLO格式的标注数据,并添加到列表中
    #annotations.append(f"{class_name} {x_center} {y_center} {bbox_width} {bbox_height}")
    filename=os.path.join(dataset,"Annotations/"+filename)
    string=class_name + " "+str(x_center) +" "+str(y_center)+" "+str(bbox_width)+" "+str(bbox_height)+"\n"
    # 将YOLO格式的标注数据写入文件
    with open(filename+'.txt', 'w') as f:
        f.write(string)


sets_dir="G:/AI211/ultralytics-main/datasets/ImageSets"
# 把train里的文件名全部写到 train.txt的训练集目录里
for file in os.listdir(train_dir):
    file_name = os.path.join(train_dir, file)
    with open(os.path.join(sets_dir, 'train.txt'), 'a') as f:
        f.write(file_name+'\n')
# 把test里的文件名全部写到 test.txt的训练集目录里
for file in os.listdir(test_dir):
    file_name = os.path.join(test_dir, file)
    with open(os.path.join(sets_dir, 'test.txt'), 'a') as f:
        f.write(file_name+'\n')

处理好的数据放到yolov8源码文件工作区里 ,图片:ultralytics\datasets\images\train | val,标注:ultralytics\datasets\labels\train | val,然后开始写数据集的.yaml文件和yolov8框架的参数配置文件,就可开开心心的训练了

训练完毕,得到满意的结果后,我们直接把.pt模型转成.onnx模型

yolo mode=export model=model.pt  format=onnx   imgsz=640,480 half=True  opset=11

使用opset=11的目的是能使算子兼容tensorrt8以下的版本

参考:Jetson nano部署YOLOv8

在jetson nano部署模型 

 在jetson nano中配置yolov8环境:

 下载yolov8源码,安装所需的环境

GitHub - ultralytics/ultralytics: NEW - YOLOv8 

 打开源码文件pyproject.toml看看,里面有需要的库的最低版本要求。

进入源码文件pyproject.toml所在的目录,在python的虚拟环境输入命令安装:

 pip3 install -e .

安装torch和torchvision: 

sudo apt-get install -y build-essential python3-pip libnvinfer8 libnvinfer-dev libnvinfer-plugin8 libnvinfer-plugin-dev libopenblas-base libopenmpi-dev  libjpeg-dev zlib1g-dev
sudo apt-get install libjpeg-dev zlib1g-dev libpython3-dev libavcodec-dev libavformat-dev libswscale-dev
sudo apt-get install python3-pip libopenblas-base libopenmpi-dev 
sudo apt install build-essential libssl-dev zlib1g-dev libncurses5-dev libncursesw5-dev libreadline-dev libsqlite3-dev libgdbm-dev libdb5.3-dev libbz2-dev libexpat1-dev liblzma-dev libffi-dev libc6-dev

首先jetson nano中,torch只能安装在python3.6或2.7版本中(要是你直接命令安装,不是cuda版本的torch有什么用),查看你自己cuda版本,去官方下载torch

PyTorch for Jetson - Jetson &

如果你使用的是JetPack 4,yolov8环境你只能用torch1.8.0到torch1.10.0,并且只能安装在python3.6环境中。

安装torchvision:

找到与torch对应的torchvion版本,下载源码,编译安装(需要的时间久)

git clone --branch v0.11.0 https://github.com/pytorch/vision torchvision
cd torchvision
export BUILD_VERSION=0.11.0 
python3 setup.py install --user

安装后输入下面测试一下是否安装成功 

python3
import torch
print(torch.cuda.is_available())
True  成功安装GPU版本的
import torchvision

 还需要安装需要用到的python库

python3 -m pip install  dill
python3 -m pip install pycuda
python3 -m pip install ultralytics
python3 -m pip install yolo

参考:Jeston NANO 配置并安装 torch+ torchvision_jetson nano安装torch-CSDN博客

使用Yolov8原生框架部署模型,代码如下:

import cv2 as cv
import torch
import time
from ultralytics import YOLO

import rospy
from std_msgs.msg import Int8
rospy.init_node("route_sign")
cmd=rospy.Publisher('/id',Int8,queue_size=1)
int8=Int8()

model = YOLO("/home/jetson/hmbot_ws/src/yolo_project/src/model.pt")
capture = cv.VideoCapture(0)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(device)
class_id=-1

while capture.isOpened():
    #start = time.time()
    ret, frame = capture.read()
    
    
    results = model(frame)

    for result in results:
        for box in result.boxes:# 获取目标框的坐标
            x1, y1, x2, y2 = box.xyxy[0]
            box_width = x2 - x1
            if box_width < frame.shape[1]/2:
                class_id = int(box.cls[0].item())
                #cv.putText(frame, str(class_id), (int(x1), int(y1) - 5), cv.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
                #cv.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 0, 255), 2)
            else:
                class_id=-1
    int8.data=class_id
    cmd.publish(int8)
    #end = time.time()
    
    #fps = 1 / (end - start)
    #text = "FPS : " + str(int(fps))
    #cv.putText(frame, text, (30, 30), cv.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 0), 1)
    #cv.imshow("result",frame)
    #out.write(frame)
    cv.waitKey(1)

capture.release()
cv.destroyAllWindows()

线速度是正数就向前行驶,负数向后行驶。角速度是正数就向左转弯,负数向右转弯。我们把角速度固定为 1rad/s , 理论上行驶了1.57秒,就转了1.57弧度也就是90度,所以只需要具体调时间,就能控制转多少度。

 ros小车接收到cmd_vel的话题后,会根据速度行驶,所以只需要根据检测到的类别,发布封装好对应的线速度和角速度的cmd_vel话题,就可以行驶。

代码如下


import time
import rospy
from geometry_msgs.msg import Twist
import argparse
from std_msgs.msg import Int8


rospy.init_node("test")
cmd_vel=rospy.Publisher('/cmd_vel',Twist,queue_size=5)
twist=Twist()
class_id=-1

def process(x=0.0,z=0.0,mytime=0.0):
    start=time.time()
    all=0.0
    while all<=mytime:
        all=time.time()-start

        twist.linear.x =x
        twist.angular.z =z     
        cmd_vel.publish(twist)


def callback(msg):
    class_id=msg.data
    if class_id==-1: 
        #print("没有识别到,前进")
        process(x=0.2,z=0.0,mytime=0.01) 

    if class_id==0: 
        print("开始限速30")
        process(x=0.05,z=0.0,mytime=7.0)
        process(x=0.2,z=0.0,mytime=5) 
    elif class_id==1: 
        print("开始左转")
        process(x=0.0, z=1.0,mytime=5.0)  
        process(x=0.2, z=0.0,mytime=5)
    elif msg.data==2: 
        print("开始右转")
        process(x=0.05, z=-1.0,mytime=2.4)
        process(x=0.2, z=0.0,mytime=5)
    elif class_id==3: 
        print("开始环路转圈")
        process(x=0.05, z=-1.0,mytime=10.5) 
        process(x=0.2, z=0.0,mytime=5)
    elif class_id==4: 
        print("开始掉头")
        process(x=0.05, z=1.0,mytime=17.0)
        process(x=0.2, z=0.0,mytime=5)
    
    elif class_id==5:
        print("开始斑马线减速")
        process(x=0.05, z=0.0,mytime=7.0)
        process(x=0.2, z=0.0,mytime=5)
    elif class_id==6: 
        print("开始减速慢行")
        process(x=0.05, z=0.0,mytime=7.0)
        process(x=0.2, z=0.0,mytime=5)
    elif class_id==7:
        print("开始停止") 
        process(x=0.0, z=0.0,mytime=7.0)
        process(x=0.2, z=0.0,mytime=5)
    else:
        #print("没有识别到,前进")
        process(x=0.2, z=0.0,mytime=0.01)
    class_id=-1

sub=rospy.Subscriber('/id',Int8,callback=callback,queue_size=1)

rospy.spin()

 

结果发现,相机帧率只有8帧,卡卡的,勉强能用

于是,打算使用TensorRT加速推理

使用TensorRT部署

jetson nano 自带有tensorrt7,我们可以直接使用 。

注意:在哪台设备导出engine就只能在该设备使用,engine模型跟设备绑定。 

把.onnx模型导出.engine模型 ,然后使用tensorrt提供的python API或者 C++ API推理

Jetson NX + yolov5-7.0 + TensorRT加速+视频推理 - 知乎 (zhihu.com)

 看下面大佬的python推理代码,改改就能用:

tensorrtx/yolov8/yolov8_det_trt.py at master · wang-xinyu/tensorrtx · GitHub

如何你用了int8量化推理还是觉得帧率不够高 ,可以加DeepStream框架继续加速推理

DeepStream框架整理

.......未完待续

jetson nano扩展磁盘空间: NVIDIA-Jetson Nano 安装完系统后SD卡空间变小解决方法_jetson nano 系统缩小-CSDN博客

  • 14
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT小艺

如果文章对你有用,请我喝咖啡吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值