老师布置了一个实验,要我们用实验室的ros小车和深度学习实现自动驾驶。我靠,还自动驾驶,
心想着做一个路标检测的应付一下就行了。
实验设备:履带式差速ros小车,jetson nano , 2d激光雷达,usb相机
我们没有路标道具,也没有路道两侧的线,我是不会花钱买的,所以继续水一下,下载没有背景的路标数据集,训练测试,检测识别,用手机上的图片当做真实的物体。
在windows10训练Yolov8模型,得到最优参数,导出.onnx模型
在有英伟达显卡的windows10配置好yolov8环境,可以看我写的文章:
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部署模型
在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
如果你使用的是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框架继续加速推理
.......未完待续
jetson nano扩展磁盘空间: NVIDIA-Jetson Nano 安装完系统后SD卡空间变小解决方法_jetson nano 系统缩小-CSDN博客