Python深度强化学习实战 ——OpenAI Gym-CarRacing自动驾驶项目

     

  • 💭 写在前面:本篇是关于 OpenAI Gym-CarRacing 自动驾驶项目的博客,面向掌握 Python 并有一定的深度强化学习基础的读者。GYM-Box2D CarRacing 是一种在 OpenAI Gym 平台上开发和比较强化学习算法的模拟环境。它是流行的 Box2D 物理引擎的一个版本,经过修改以支持模拟汽车在赛道上行驶的物理过程。本篇是 CarRacing 系列博客的代码篇,提供 lane_dection 部分的完整代码。 

📜 本章目录:

Ⅰ. 项目环境准备

0x00 实验说明

0x01 模板下载

Ⅱ. 代码:车道检测功能的实现

 0x00 引入:lane_dection 部分的实现

0x01 完整代码

0x01 运行结果演示

0x02 转灰度图像:cur_gray

0x03 边缘检测:edge_detection

0x04 寻找边缘检测结果中的局部最大值:find_maxima_gradient_rowwise

🔗 OpenAI Gym-CarRacing 系列博客


Ⅰ. 项目环境准备

0x00 实验说明

🔗 Conda 安装:【Python】前置:Conda 安装教学

🔗 项目环境安装:Gym-CarRacing 环境安装

🚩 实践目标:实现一个模块化组件框架,落实简化版的模块化流水线。了解基本概念,并积累开发一个简单的自驱应用程序的经验。

🔨 环境选用:OpenAI GYM

  • https://www.gymlibrary.ml/
  • 我们将基于 Box2D CarRacing 实现,Box2D CarRacing 基本信息如下:
    • Action:转向、加速、刹车
    • Sensor input:96x96x3​​  屏幕(显示汽车的状态和路径信息)

​​

0x01 模板下载

* 提供基础框架,只需要在 TODO 位置填写代码即可!

🔗 模板下载:CSDN资源:Box2D CarRacing lane-dection 项目模板

Ⅱ. 代码:车道检测功能的实现

 0x00 引入:lane_dection 部分的实现

🚩 实践目标:

  • 实现一个模块化组件框架,落实简化版的模块化流水线。
  • 了解基本概念,并积累开发一个简单的自驱应用程序的经验。

​​​​​​​

📜 尝试:

  • 为汽车上方的部分找到一个好的裁剪,一个好的方法来分配车道边界的边缘,一个好的梯度阈值和样条平滑度的参数选择。
  • 尝试找到失败的案例。

0x01 完整代码

💬 参考代码:lane_detection.py

from turtle import distance
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import find_peaks
from scipy.interpolate import splprep, splev
from scipy.optimize import minimize
import timeclass LaneDetection:'''Lane detection module using edge detection and b-spline fittingargs: cut_size (cut_size=65) cut the image at the front of the carspline_smoothness (default=10)gradient_threshold (default=14)distance_maxima_gradient (default=3)使用边缘检测和b样条拟合的车道检测模块参数:cut_size(cut_size=65)在汽车前部剪切图像spline_smoothness(默认值=10)gradient_threshold(默认值=14)distance_maxima_gradient(默认值=3)'''def __init__(self, cut_size=65, spline_smoothness=10, gradient_threshold=14, distance_maxima_gradient=3):self.car_position = np.array([48,0])self.spline_smoothness = spline_smoothnessself.cut_size = cut_sizeself.gradient_threshold = gradient_thresholdself.distance_maxima_gradient = distance_maxima_gradientself.lane_boundary1_old = 0self.lane_boundary2_old = 0## 将状态图像转化为灰度图像def cut_gray(self, state_image_full):'''##### TODO #####This function should cut the image at the front end of the car (e.g. pixel row 65) and translate to gray scaleinput:state_image_full 96x96x3output:gray_state_image 65x96x1此功能应在汽车前端切割图像(例如像素行65),并转换为灰度输入:状态图像完整96x96x3输出:灰度_状态_图像65x96x1'''copy_img = state_image_full[:self.cut_size, :]   red, green, blue = 0.2989, 0.5870, 0.1140return np.dot(copy_img[...,:3], [red, green, blue])[::-1]def edge_detection(self, gray_image):'''##### TODO #####In order to find edges in the gray state image, this function should derive the absolute gradients of the gray state image.Derive the absolute gradients using numpy for each pixel. To ignore small gradients, set all gradients below a threshold (self.gradient_threshold) to zero. input:gray_state_image 65x96x1output:gradient_sum 65x96x1为了在灰度图像中找到边缘,该函数应导出灰度图像的绝对梯度。使用numpy为每个像素导出绝对梯度。要忽略小渐变,请将阈值(self.gradient_threshold)以下的所有渐变设置为0。'''gradient = np.gradient(gray_image)gradient_sum = abs(gradient[0]) + abs(gradient[1])gradient = gradient_sum < self.gradient_thresholdgradient_sum[gradient] = 0return gradient_sumdef find_maxima_gradient_rowwise(self, gradient_sum):'''##### TODO #####This function should output arguments of local maxima for each row of the gradient image.You can use scipy.signal.find_peaks to detect maxima. Hint: Use distance argument for a better robustness.input:gradient_sum 65x96x1output:maxima (np.array) shape : (Number_maxima, 2)这个函数应该为渐变图像的每一行输出局部最大值的参数。您可以使用scipy.signal。查找峰值以检测最大值。提示:使用距离参数可以获得更好的鲁棒性。# 距离参数cuz车道应至少相隔3像素# find_peaks返回`x`中满足所有给定条件的峰值指数。'''argmaxima = []pixel = 3        # 相隔参数i = 0while (i < gradient_sum.shape[0]):top, _ = find_peaks(gradient_sum[i], distance = pixel)argmaxima.append(top)i += 1return argmaximadef find_first_lane_point(self, gradient_sum):'''Find the first lane_boundaries points above the car.Special cases like just detecting one lane_boundary or more than two are considered. Even though there is space for improvement ;) input:gradient_sum 65x96x1output: lane_boundary1_startpointlane_boundary2_startpointlanes_found  true if lane_boundaries were found找到汽车上方的第一个车道边界点。特殊情况下,如只检测一个或两个以上的车道边界。尽管还有改进的空间;)输入:梯度_总和65x96x1输出:车道边界1_起点车道边界2起点如果找到车道边界,则lanes_found为true'''# Variable if lanes were found or notlanes_found = Falserow = 0# loop through the rowswhile not lanes_found:# Find peaks with min distance of at least 3 pixel argmaxima = find_peaks(gradient_sum[row],distance=3)[0]# if one lane_boundary is foundif argmaxima.shape[0] == 1:lane_boundary1_startpoint = np.array([[argmaxima[0],  row]])if argmaxima[0] < 48:lane_boundary2_startpoint = np.array([[0,  row]])else: lane_boundary2_startpoint = np.array([[96,  row]])lanes_found = True# if 2 lane_boundaries are foundelif argmaxima.shape[0] == 2:lane_boundary1_startpoint = np.array([[argmaxima[0],  row]])lane_boundary2_startpoint = np.array([[argmaxima[1],  row]])lanes_found = True# if more than 2 lane_boundaries are foundelif argmaxima.shape[0] > 2:# if more than two maxima then take the two lanes next to the car, regarding least squareA = np.argsort((argmaxima - self.car_position[0])**2)lane_boundary1_startpoint = np.array([[argmaxima[A[0]],  0]])lane_boundary2_startpoint = np.array([[argmaxima[A[1]],  0]])lanes_found = Truerow += 1# if no lane_boundaries are foundif row == self.cut_size:lane_boundary1_startpoint = np.array([[0,  0]])lane_boundary2_startpoint = np.array([[0,  0]])breakreturn lane_boundary1_startpoint, lane_boundary2_startpoint, lanes_founddef lane_detection(self, state_image_full):'''##### TODO #####This function should perform the road detection args:state_image_full [96, 96, 3]out:lane_boundary1 splinelane_boundary2 spline此功能应执行道路检测参数:state_image_full [96, 96, 3]输出:lane_boundary1 splinelane_boundary2 spline'''# to graygray_state = self.cut_gray(state_image_full)# edge detection via gradient sum and thresholdinggradient_sum = self.edge_detection(gray_state)maxima = self.find_maxima_gradient_rowwise(gradient_sum)# first lane_boundary pointslane_boundary1_points, lane_boundary2_points, lane_found = self.find_first_lane_point(gradient_sum)# if no lane was found,use lane_boundaries of the preceding step# l1 = lane_boundary1_points# l2 = lane_boundary2_pointsif lane_found:##### TODO ######  in every iteration: # 1- find maximum/edge with the lowest distance to the last lane boundary point # 2- append maximum to lane_boundary1_points or lane_boundary2_points# 3- delete maximum from maxima# 4- stop loop if there is no maximum left #    or if the distance to the next one is too big (>=100)'''#在每次迭代中:#1-查找到最后一个车道边界点的最小距离的最大/边缘#2-将最大值附加到lane_boundary1_points或lane_boondary2_point斯#3-从maxima中删除maximum#4-如果没有最大剩余# ,则停止循环#或者如果到下一个的距离太大(>=100)'''l1 = lane_boundary1_pointsl2 = lane_boundary2_pointsrow = 1lim = 65while (row < lim): max_row = maxima[row]if len(max_row) < 2:break#根据与先前车道预测的距离对点进行排序#此外,argsort还返回可以按顺序迭代的索引#因此,我们在排序后使用A[0]和B[0]arrayA, arrayB = np.argsort(pow(max_row - l1[0][0], 2)), np.argsort(pow(max_row - l2[0][0], 2))p1, p2 = np.array([[max_row[arrayA[0]], row]]), np.array([[max_row[arrayB[0]], row]])lane_boundary1_points, lane_boundary2_points = np.append(lane_boundary1_points, p1, axis=0), np.append(lane_boundary2_points, p2, axis=0)l1, l2 = p1, p2row += 1# lane_boundary 1# lane_boundary 2##################### TODO ###### spline fitting using scipy.interpolate.splprep # and the arguments self.spline_smoothness# # if there are more lane_boundary points points than spline parameters # else use perceding spline'''使用 scipy.interpolate.splprep  进行样条拟合#以及自变量self.spline_splity#如果车道边界点比样条曲线参数多#否则使用perceding样条线'''if lane_boundary1_points.shape[0] > 4 and lane_boundary2_points.shape[0] > 4:# Pay attention: the first lane_boundary point might occur twice# lane_boundary 1lane_boundary1, _ = splprep([lane_boundary1_points[1:,0], lane_boundary1_points[1:,1]], s=self.spline_smoothness, k=2)# lane_boundary 2lane_boundary2, _ = splprep([lane_boundary2_points[1:,0], lane_boundary2_points[1:,1]], s=self.spline_smoothness, k=2)else:lane_boundary1 = self.lane_boundary1_oldlane_boundary2 = self.lane_boundary2_old################else:lane_boundary1 = self.lane_boundary1_oldlane_boundary2 = self.lane_boundary2_oldself.lane_boundary1_old = lane_boundary1self.lane_boundary2_old = lane_boundary2# output the splinereturn lane_boundary1, lane_boundary2def plot_state_lane(self, state_image_full, steps, fig, waypoints=[]):'''Plot lanes and way points'''# evaluate spline for 6 different spline parameters.t = np.linspace(0, 1, 6)lane_boundary1_points_points = np.array(splev(t, self.lane_boundary1_old))lane_boundary2_points_points = np.array(splev(t, self.lane_boundary2_old))plt.gcf().clear()plt.imshow(state_image_full[::-1])plt.plot(lane_boundary1_points_points[0], lane_boundary1_points_points[1]+96-self.cut_size, linewidth=5, color='orange')plt.plot(lane_boundary2_points_points[0], lane_boundary2_points_points[1]+96-self.cut_size, linewidth=5, color='orange')if len(waypoints):plt.scatter(waypoints[0], waypoints[1]+96-self.cut_size, color='white')plt.axis('off')plt.xlim((-0.5,95.5))plt.ylim((-0.5,95.5))plt.gca().axes.get_xaxis().set_visible(False)plt.gca().axes.get_yaxis().set_visible(False)fig.canvas.flush_events()# t = np.linspace(0, 1, 5) # t = [0, 0.25, 0.5, 0.75, 1]
# Interpolated_lane_boundary_points = np.array(splev(t, self.lane_boundary))

0x01 运行结果演示

cd 到 skeleton 文件夹的路径下,输入 python test_lane_detection 运行代码:

🚩 运行结果:

💻 GIF:

0x02 转灰度图像:cur_gray

cut_gray 函数需要我们实现将状态图像转化为灰度图像。

💬 参考代码:

 def cut_gray(self, state_image_full):copy_img = state_image_full[:self.cut_size, :]   red, green, blue = 0.2989, 0.5870, 0.1140return np.dot(copy_img[...,:3], [red, green, blue])[::-1]

0x03 边缘检测:edge_detection

💬 参考代码:

    def edge_detection(self, gray_image):'''##### TODO #####In order to find edges in the gray state image, this function should derive the absolute gradients of the gray state image.Derive the absolute gradients using numpy for each pixel. To ignore small gradients, set all gradients below a threshold (self.gradient_threshold) to zero. input:gray_state_image 65x96x1output:gradient_sum 65x96x1'''gradient = np.gradient(gray_image)gradient_sum = abs(gradient[0]) + abs(gradient[1])gradient = gradient_sum < self.gradient_thresholdgradient_sum[gradient] = 0return gradient_sum

0x04 寻找边缘检测结果中的局部最大值:find_maxima_gradient_rowwise

为渐变图像的每一行输出局部最大值的参数,可以使用 scipy.signal 查找峰值以检测最大值。

* 提示:使用距离参数(distance)可以获得更好的鲁棒性。

  • 距离参数 cuz 车道应至少相隔 3 像素
  • find_peaks 返回 `x` 中满足所有给定条件的峰值指数。

💬 参考代码:

    def find_maxima_gradient_rowwise(self, gradient_sum):'''##### TODO #####This function should output arguments of local maxima for each row of the gradient image.You can use scipy.signal.find_peaks to detect maxima. Hint: Use distance argument for a better robustness.input:gradient_sum 65x96x1output:maxima (np.array) shape : (Number_maxima, 2)'''argmaxima = []pixel = 3        # 相隔参数i = 0while (i < gradient_sum.shape[0]):top, _ = find_peaks(gradient_sum[i], distance = pixel)argmaxima.append(top)i += 1return argmaxima


🔗 OpenAI Gym-CarRacing 系列博客:

【OpenAI】Python:基于 Gym-CarRacing 的自动驾驶项目(1) | 前置知识介绍 | 项目环境准备 | 手把手带你一步步实现

【OpenAI】Python:基于 Gym-CarRacing 的自动驾驶项目(2)| 车道检测功能的实现 | 边缘检测与分配 | 样条拟合

【OpenAI】Python:基于 Gym-CarRacing 的自动驾驶项目(3) | 路径训练功能的实现 | 规划与决策 | 路径平滑 | 利用公式进行目标速度预测

【OpenAI】Python:基于 Gym-CarRacing 的自动驾驶项目(4) | 车辆控制功能的实现 | 开环控制 | 闭环控制 | 启停式控制 | PID 控制 | Stanley 控制器

​​

📌 [ 笔者 ]   foxny, Akam
📃 [ 更新 ]   2023.7.8(recently)
❌ [ 勘误 ]   /* 暂无 */
📜 [ 声明 ]   由于作者水平有限,本文有错误和不准确之处在所难免,本人也很想知道这些错误,恳望读者批评指正!

📜 参考资料 

[6] Montemerlo M, Becker J, Bhat S, et alJunior: The Stanford entry in the Urban Challenge

Slide Credit: Steven Waslander

LaValle: Rapidly-exploring random trees: A new tool for path planning. Techical Report, 1998

Dolgov et al.: Practical Search Techniques in Path Planning for Autonomous Driving. STAIR, 2008.

Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. .

百度百科[EB/OL]. []. https://baike.baidu.com/.

. [EB/OL]. []. https://blog.waymo.com/2021/10/the-waymo-driver-handbook-perception.html.

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML <map> 标签

实例 带有可点击区域的图像映射: <img src="planets.jpg" border="0" usemap="#planetmap" alt="Planets" /><map name="planetmap" id="planetmap"><area shape="circle" coords=&q…

领域知识图谱的医生推荐系统:利用BERT+CRF+BiLSTM的医疗实体识别,建立医学知识图谱,建立知识问答系统

项目设计集合&#xff08;人工智能方向&#xff09;&#xff1a;助力新人快速实战掌握技能、自主完成项目设计升级&#xff0c;提升自身的硬实力&#xff08;不仅限NLP、知识图谱、计算机视觉等领域&#xff09;&#xff1a;汇总有意义的项目设计集合&#xff0c;助力新人快速实…

HTML+CSS+JavaScript:九九乘法表

一、需求如图 二、思路及代码 1、JavaScript代码 稍微刷过一点算法题的小伙伴就很容易想到这题需要利用双层for循环来实现&#xff0c;思路也是比较简单的&#xff0c;我在这里就直接放代码了 不添加CSS渲染的代码如下 <!DOCTYPE html> <html lang"en"&…

HTTP、HTTPS协议详解

文章目录 HTTP是什么报文结构请求头部响应头部 工作原理用户点击一个URL链接后&#xff0c;浏览器和web服务器会执行什么http的版本持久连接和非持久连接无状态与有状态Cookie和Sessionhttp方法&#xff1a;get和post的区别 状态码 HTTPS是什么ssl如何搞到证书nginx中的部署 加…

【探索AI未来】自动驾驶时代下的人工智能技术与挑战

自我介绍⛵ &#x1f4e3;我是秋说&#xff0c;研究人工智能、大数据等前沿技术&#xff0c;传递Java、Python等语言知识。 &#x1f649;主页链接&#xff1a;秋说的博客 &#x1f4c6; 学习专栏推荐&#xff1a;MySQL进阶之路、C刷题集、网络安全攻防姿势总结 欢迎点赞 &…

CSS学习04

文章目录 1.精灵图1.1 为什么需要精灵图1.2 精灵图&#xff08;sprites&#xff09;的使用 2.字体图标2.1 字体图标的产生2.2 字体图标的优点**2.3** **字体图标的下载****2.4** **字体图标的引入**2.5 字体图标的追加 3.CSS 三角3.1 介绍 4.CSS 用户界面样式4.1 鼠标样式 curs…

电路分析 day01 一种使能控制电路

本次分析的电路为 一种使能控制电路 &#xff08;站在别人的肩膀上学习&#xff09; 资料来源 &#xff1a; 洛阳隆盛科技有限责任公司的专利 申请号&#xff1a;CN202022418360.7 1.首先查看资料了解本次电路 1.1 电路名称&#xff1a; 一种使能控制电路 1.2 电路功能…

IOS与Android APP开发的差异性

iPhone和 Android是全球最流行的两种移动平台&#xff0c;有许多不同的开发者开发了应用程序&#xff0c;并将它们发布到市场上。虽然大多数开发者都使用了这两个平台&#xff0c;但您仍然需要了解它们的差异。 虽然 iOS和 Android两个平台都是基于 Linux&#xff0c;但它们却…

C语言 — 指针进阶篇(上)

前言 指针基础篇回顾可以详见&#xff1a; 指针基础篇&#xff08;1&#xff09;指针基础篇&#xff08;2&#xff09; 指针进阶篇分为上下两篇,上篇介绍1 — 4&#xff0c;下篇介绍5 — 6 字符指针数组指针指针数组数组传参和指针传参函数指针函数指针数组指向函数指针数组的…

Java线程状态与状态转换

前言 在Java中&#xff0c;线程是多任务处理的基本单位&#xff0c;它可以并行执行多个任务。线程的状态描述了线程在其生命周期中的不同阶段。Java线程的状态可以分为以下几种&#xff1a; 线程状态 状态解释新建状态&#xff08;New&#xff09;线程被创建但尚未启动就绪状…

复习第五课 C语言-初识数组

目录 【1】初识数组 【2】一维数组 【3】清零函数 【4】字符数组 【5】计算字符串实际长度 练习&#xff1a; 【1】初识数组 1. 概念&#xff1a;具有一定顺序的若干变量的集合 2. 定义格式&#xff1a; 数组名 &#xff1a;代表数组的首地址&#xff0c;地址常量&…

“AI+教育”:景联文科技高质量教育GPT题库助力教学创新

去年年底&#xff0c;OpenAI推出ChatGPT&#xff0c;掀起AI热潮&#xff0c;教育作为“AI”应用落地的关键场景&#xff0c;再次受到广泛关注。 “AI教育”的快速发展&#xff0c;是受到技术、需求和政策三重因素共同驱动的结果。 在技术方面&#xff0c;随着人工智能技术的不断…