使用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博客

  • 13
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

IT小艺

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

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

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

打赏作者

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

抵扣说明:

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

余额充值