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.mzph.cn/news/323.shtml

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

相关文章

灌区信息化智能测控一体化闸门系统解决方案

一、方案背景 闸门是节水灌溉工程中重要组成部分。在农田灌区中&#xff0c;一方面存在传统手摇闸门&#xff0c;未能实现自动化、数字化&#xff0c;另一方面部分灌区闸站虽然部分实现了自动化控制&#xff0c;但是由于闸站较多&#xff0c;有些位置较为偏僻&#xff0c;部分水…

Jmeter接口关联(一)【使用json层级方式提取值】与python中使用层级方式提取值 完成接口关联

文章目录 前言一、按照 json 的路径来提取 ​​​​​​​&#xff08;1&#xff09;成功匹配到数据的案例&#xff08;按照层级匹配&#xff09;&#xff08;2&#xff09;失败未匹配到数据的案例&#xff08;没有按照层级匹配&#xff09;json提取器二、使用完整的接口关联&a…

selenium自动化测试工具

Selenium是一个用于测试网站的自动化测试工具&#xff0c;支持各种浏览器包括Chrome、Firefox、Safari等主流界面浏览器&#xff0c;同时也支持phantomJS无界面浏览器。 查看chrome版本&#xff0c;114.05735.199 去 http://chromedriver.storage.googleapis.com/index.html 网…

密码学证明方案寒武纪大爆发——扩容、透明性和隐私的变革潜力

1. 引言 前序博客有&#xff1a; ZKP大爆炸 本文主要参考&#xff1a; StarkWare 2023年6月博客 Cambrian Explosion of Cryptographic Proofs----The transformative potential for scalability, transparency, and privacy2023年3月Eli Ben-Sasson在The 13th BIU Winter …

nginx页面优化与防盗链

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、nginx页面优化1.版本号1.1 查看版本号1.2 修改版本号1.2.1 修改配置文件1.2.2 修改源码文件&#xff0c;重新编译安装 2.nginx的日志分割3.nginx的页面压缩3.1 …

微软亚洲研究院推出AI编译器界“工业重金属四部曲”

编者按&#xff1a;编译器在传统计算科学中一直是一个重要的研究课题。在人工智能技术快速发展和广泛应用的今天&#xff0c;人工智能模型需要部署在多样化的计算机硬件架构上。同时&#xff0c;训练和部署大型人工智能模型时又对硬件性能有着更高的要求&#xff0c;有时还需根…

macOS Ventura 13.5beta5(22G5072a)发布

系统介绍 黑果魏叔 7 月 11 日消息&#xff0c;苹果今日向 Mac 电脑用户推送了 macOS 13.5 开发者预览版 Beta 5 更新&#xff08;内部版本号&#xff1a;22G5072a&#xff09;&#xff0c;本次更新距离上次发布隔了 12 天。 macOS Ventura 带来了台前调度、连续互通相机、Fa…

1g的视频怎么做二维码?较大视频如何生成二维码?

现在很多参与评选活动时&#xff0c;会制作好相关的视频内容&#xff0c;然后生成二维码之后&#xff0c;发送给活动管理人员从而参与评选。在根据要求录制视频时&#xff0c;有些视频会因为时间太长&#xff0c;导致文件过大&#xff0c;那么如何将超过1g的等视频生成二维码&a…

基于DEF生成LIB的方法

基于DEF生成LIB的方法 [生成64位lib] lib /def:libcurl-x64.def /MACHINE:x64 /OUT:libcurl-x64.lib[生成32位lib] lib /def:libcurl-x64.def /OUT:libcurl-x64.lib

OpenCV 图像处理算法和技术的应用实践

OpenCV 图像处理算法和技术的应用实践 导语一、图像滤波算法二、图像分割技术三、特征提取与描述算法四、实践示例&#xff1a;图像风格转换总结 导语 图像处理算法和技术在计算机视觉和图像处理领域发挥着重要作用&#xff0c;通过对图像进行分析、增强和转换&#xff0c;可以…

2023机器人操作系统(ROS)暑期学校预热-线下时间/地点-(转发)

原文地址&#xff1a; https://mp.weixin.qq.com/s/McjBgCpecL6OMgpcrPyY_Q 中国机器人操作系统&#xff08;ROS&#xff09;暑期学校自2015年举办以来&#xff0c;被中国机器人业界和学界&#xff0c;以及ROS开源基金会誉为除了ROSCon之外规模最大、参与人数最多、最成功的RO…

什么是Heatmap(热图)图表?用DHTMLX可实现快速构建

DHTMLX Chart是DHTMLX最新发布的JavaScript UI小部件库的核心内容之一&#xff0c;这个图表小部件收到了几个重要的更新&#xff0c;但其中最引人注目的是一个新的数据可视化选项——日历热图。 DHTMLX专注于JavaScript和HTML5 UI小部件和库&#xff0c;以帮助开发人员更快地构…

基于springboot+vue的疫情管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

不外传秘诀| docker 快速搭建常用的服务环境

本文主要给大家介绍如何使用 docker 搭建常用的服务环境&#xff0c; 包括mysql,reedis,nginx,jenkins 等常用的环境&#xff0c;下面直接进入主题。 1、MySQL 部署 ①搜索 MySQL 镜像 docker search mysql ②拉取 MySQL 镜像 docker pull mysql:5.7 ③创建容器&#xf…

基于STM32单片机的智能家居烟雾温度火灾防盗报警的设计与实现

功能介绍 以STM32单片机作为主控系统&#xff1b;LCD1602液晶显示屏来显示显示测得的值&#xff1b;SR501人体红外感应是否有人进行防盗&#xff1b;通过烟雾传感器MQ-2获取前的烟雾值&#xff1b;通过DHT11温湿度传感器来获取当前的温湿度&#xff1b;所有的信息通过通过esp82…

php通过IP获取用户当前所在城市

php获取当前用户所在城市 php通过ip免申请api获取所在城市的代码包括省市区sql数据 <?php function getName($pinyin,$lv){$servername "localhost";$username "root";$password "root";$dbname "ttx";try {$conn new PDO(…

机器学习15:神经网络-Neural Networks

神经网络是特征交叉的更复杂版本。本质上&#xff0c;神经网络会学习适当的特征组合。本文主要介绍神经网络的结构、隐藏层、激活函数等内容。 目录 1.神经网络&#xff1a;结构 2.隐藏层 3.激活函数 3.1 常用激活函数 3.2 小结 4.神经网络小练习 4.1 第一个神经网络 …

Jina AI 受邀出席 WAIC 2023「科技无障碍」论坛,与行业专家共话 AI 普惠未来

7 月 6 日&#xff0c;2023 世界人工智能大会&#xff08;WAIC&#xff09;在上海世博中心及世博展览馆开幕&#xff0c;并在浦东张江、徐汇西岸设分会场&#xff0c;同步在闵行等产业集聚区开展同期活动。本届大会由上海市人民政府和国家发改委、工信部、科技部、国家网信办、…

基于JSP+Servlet的医药药品管理系统

用户类型&#xff1a;双角色角色&#xff08;患者、管理员[医生]&#xff09; 设计模式&#xff1a;MVC&#xff08;jspservletjavabean) 项目架构&#xff1a;B/S架构 开发语言&#xff1a;Java语言 主要技术&#xff1a;jsp、servlet、jdbc、jsp、html5、jquery、css、js…

RabbitMQ之交换机

RabbitMQ之交换机 1. Exchanges1.1 Exchanges 概念1.2 Exchanges 的类型1.3 无名 exchange 2. 临时队列3. 绑定&#xff08;bindings&#xff09;4. Fanout4.1 Fanout 介绍4.2 Fanout 实战 5. Direct exchange5.1 Direct exchange 介绍5.2 多重绑定5.3 实战 6. Topics6.1 之前类…