6.方法测试

在这个部分我们要整体的测试我们的程序,对前面的知识和内容有一个整体的应用和概括。

这是Udacity提供的相应资料,在code文件夹中有一个Rover_Project_Test_Notebook.ipynb文件,提供了输出视频的笔记本文件。

由于个人喜好的原因,我选择了pycharm2019来运行此程序。

(1)方法测试程序概述

在这个部分我们需要完成的项目如下

  1. 首先运行笔记本中的每个单元格,检查代码和每个单元格的结果。
  2. 在“训练模式”中运行模拟器并记录一些数据。注意:只需要使用一些示例图像,几百张即可。
  3. 将数据目录路径(下面的2个单元格)更改为保存数据的目录
  4. 测试数据上提供的功能
  5. 编写新功能(或修改现有功能)以报告和绘制障碍物和岩石样本(黄色岩石)的检测结果
  6. 使用适当的步骤/函数填充process_image()函数,以从原图像转换为worldmap。
  7. 使用moviepy函数运行调用process_image()的单元格以创建视频输出
  8. 如果绘制工作可以进行,则继续修改perception.py和decision.py,让流浪者号自主导航并以自动模式进行绘制。

首先我们需要获取ffmpeg工具

import imageioimageio.plugins.ffmpeg.download()

运行此程序以下载ffmpeg工具。

但我在运行这个程序时遇到了一个问题。

报错

imageio.ffmpeg.download() has been deprecated. Use 'pip install imageio-ffmpeg' instead.'‘

经查阅,该错误是由版本更新引起的错误,解决办法(在Windows上)为

pip install imageio==2.4.1

现在再一次运行我们的程序,如果imageio正确安装且电脑中没有安装ffmpeg,程序会自动下载安装

import imageioimageio.plugins.ffmpeg.download()

python会自动下载ffmpeg,如果下载不成功或者速度太慢可以选择到相应网站下载,单击这里进行下载。

ffmpeg应当放到AppData目录下。

(2)读入以保存的数据和世界地图

我们定义一个名为 Databucket() 类来存储测量数据、图像路径和图像。

当我们实例化这个类时,我们将得到一个名为 data 的全局变量,我们将在之后的 process_image() 函数中来引用其中的数据。

其程序如下:

import pandas as pd
df = pd.read_csv('.../Roversim/Roverdata/robot_log.csv', delimiter=';', decimal='.')
csv_img_list = df["Path"].tolist()
# 读入世界地图并使用它创建一个3通道的图像
ground_truth = mpimg.imread('.../RoboND-Rover-Project-master/calibration_images/map_bw.png')
ground_truth_3d = np.dstack((ground_truth*0, ground_truth*255, ground_truth*0)).astype(np.float)# 创建一个类作为Databucket,读取csv文件中保存的数据并填充此对象。
# worldmap被实例化为200*200个网格,其对应200m*200m的空间。
class Databucket():def __init__(self):self.images = csv_img_list  self.xpos = df["X_Position"].valuesself.ypos = df["Y_Position"].valuesself.yaw = df["Yaw"].valuesself.count = 0 # 运行索引self.worldmap = np.zeros((200, 200, 3)).astype(np.float)self.ground_truth = ground_truth_3d # Ground truth worldmap# 实例化一个databucket,这将是一个全局变量,
# 我们可以在接下来的process_image()函数中使用
data = Databucket()

(3)图像处理函数

1)process_image()函数

编写process_image()函数,以执行图像分析和映射。我们只需要把对应漫游者号的位置等映射到worldmap上去就可以。

在之前的程序中,我们小车的位置和偏转角是随机生成的,但是这里就需要我们来读取csv文件中的数据,将相应的透视变换之后的图像映射到世界地图上去。

换句话说, 我们将各个图像传递到 process_image() 函数并以此来构建一个名为 output_image 的图像,该图像将存储为视频的一帧。

下面是经过更改后的 process_image() 函数:

# 定义图片处理函数
def process_image(img):output_image = np.zeros((img.shape[0] + data.worldmap.shape[0],img.shape[1] * 2, 3))# 定义第一张图为imgoutput_image[0:img.shape[0], 0:img.shape[1]] = img# 定义第二张图为img经过透视变换后的图像warped = perspect_transform(img, src, dst)output_image[0:img.shape[0], img.shape[1]:] = warpedgray_warped = cv2.cvtColor(warped, cv2.COLOR_RGB2GRAY)ret, img_thresh = cv2.threshold(gray_warped, 160, 255, cv2.THRESH_BINARY)test_image = np.expand_dims(img_thresh, axis=2)output_image[180:340, img.shape[1]:, 0] = img_threshxpix, ypix = rover_coords(img_thresh)worldmap = data.worldmapx_world, y_world = pix_to_world(xpix, ypix, data.xpos[data.count], data.ypos[data.count], data.yaw[data.count],data.worldmap.shape[0], 20 )worldmap[y_world, x_world] += 1map_add = cv2.addWeighted(ground_truth_3d, 1, worldmap, 0.2, 0)output_image[img.shape[0]:, 0:data.worldmap.shape[1]] = map_addcv2.putText(output_image, "Test!", (20, 20),cv2.FONT_HERSHEY_COMPLEX, 0.4, (255, 255, 255), 1)# 跟踪Databucket中的索引if data.count < len(data.images) - 1:data.count += 1return output_image

2)cv2.addWeighted

此函数是为了使两个图像叠加使用的,用在我们将小车的透视变换后的图像映射到世界地图上。

dst = cv2.addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]])

参数说明:

  • src1 - 第一个输入数组。
  • alpha - 第一个数组元素的权重。
  • src2 - 与src1具有相同大小和通道编号的第二个输入数组。
  • beta - 第二个数组元素的权重。
  • dst - 与输入数组具有相同大小和通道数的输出数组。
  • gamma - 标量加到每个总和。
  • dtype - 输出数组的可选深度; 当两个输入数组具有相同的深度时,dtype可以设置为-1,这相当于src1.depth()

此函数可以用一下矩阵表达式来代替:

dst = src1 * alpha + src2 * beta + gamma;

(4)输出测试视频

因为我们要对特定的颜色进行图像颜色阈值处理,比如之后选择特定的黄色的岩石样本,所以我图像二值化选择使用numpy来完成而不是cv2。其程序如下:

def color_thresh(img, rgb_thresh=(160, 160, 160)):color_select = np.zeros_like(img[:,:,0])above_thresh = (img[:,:,0] > rgb_thresh[0]) \& (img[:,:,1] > rgb_thresh[1]) \& (img[:,:,2] > rgb_thresh[2])color_select[above_thresh] = 1return color_selectthreshed = color_thresh(warped)
plt.imshow(threshed, cmap='gray')

以下是最终程序

import numpy as np
import cv2
import pandas as pd
import matplotlib.image as mpimg
from moviepy.editor import VideoFileClip
from moviepy.editor import ImageSequenceClip##颜色阈值
# 使用Numpy定义二值化图像函数
def color_thresh(img, rgb_thresh=(160, 160, 160)):img_thresh = np.zeros_like(img[:, :, 0])above_thresh = (img[:, :, 0] > rgb_thresh[0]) \& (img[:, :, 1] > rgb_thresh[1]) \& (img[:, :, 2] > rgb_thresh[2])img_thresh[above_thresh] = 1return img_thresh##透视变换
# 定义图像映射函数,将摄像头的图像映射到平面坐标中去
def perspect_transform(img, src, dst):M = cv2.getPerspectiveTransform(src, dst)  # 定义变换矩阵img_perspect = cv2.warpPerspective(img, M, (img.shape[1], img.shape[0]))return img_perspect##坐标变换
# 定义从图像坐标转换函数
def rover_coords(binary_img):ypos, xpos = binary_img.nonzero()x_pixel = -(ypos - binary_img.shape[0]).astype(np.float)y_pixel = -(xpos - binary_img.shape[1]/2 ).astype(np.float)return x_pixel, y_pixel# 定义旋转操作函数
def rotate_pix(xpix, ypix, yaw):yaw_rad = yaw * np.pi / 180xpix_rotated = (xpix * np.cos(yaw_rad)) - (ypix * np.sin(yaw_rad))ypix_rotated = (xpix * np.sin(yaw_rad)) + (ypix * np.cos(yaw_rad))return xpix_rotated, ypix_rotated# 定义平移操作函数
def translate_pix(xpix_rot, ypix_rot, xpos, ypos, scale):xpix_translated = (xpix_rot / scale) + xposypix_translated = (ypix_rot / scale) + yposreturn xpix_translated, ypix_translated# 定义综合函数,将旋转和平移函数进行结合,并限制了图像范围
def pix_to_world(xpix, ypix, xpos, ypos, yaw, world_size, scale):xpix_rot, ypix_rot = rotate_pix(xpix, ypix, yaw)xpix_tran, ypix_tran = translate_pix(xpix_rot, ypix_rot, xpos, ypos, scale)x_pix_world = np.clip(np.int_(xpix_tran), 0, world_size - 1)y_pix_world = np.clip(np.int_(ypix_tran), 0, world_size - 1)return x_pix_world, y_pix_world# 定义转换为极坐标函数
def to_polar_coords(xpix, ypix):dist = np.sqrt(xpix**2 + ypix ** 2)angles = np.arctan2(ypix, xpix)return dist, angles# 参考图像,用作透视变换
filename = '.../RoboND-Rover-Project-master/calibration_images/example_grid1.jpg'
image = cv2.imread(filename)dst_size = 5
bottom_offset = 0src = np.float32([[14, 140], [301, 140], [200, 96], [118, 96]])
dst = np.float32([[image.shape[1]/2 - dst_size, image.shape[0] - bottom_offset],[image.shape[1]/2 + dst_size, image.shape[0] - bottom_offset],[image.shape[1]/2 + dst_size, image.shape[0] - 2*dst_size - bottom_offset],[image.shape[1]/2 - dst_size, image.shape[0] - 2*dst_size - bottom_offset],])# 透视变换
warped = perspect_transform(image, src, dst)df = pd.read_csv('.../Roverdata/robot_log.csv', delimiter=';', decimal='.')
csv_img_list = df["Path"].tolist() # 创建一个关于图像的路径列表
# 读取worldmap,并创建一个三维图像
ground_truth = mpimg.imread('.../RoboND-Rover-Project-master/calibration_images/map_bw.png')
ground_truth_3d = np.dstack((ground_truth*0, ground_truth*255, ground_truth*0)).astype(np.float)# 定义一个类来存储诸如漫游者号位置,方向角等数据
class Databucket():def __init__(self):self.images = csv_img_listself.xpos = df["X_Position"].valuesself.ypos = df["Y_Position"].valuesself.yaw = df["Yaw"].valuesself.count = 0self.worldmap = np.zeros((200, 200, 3)).astype(np.float)self.ground_truth = ground_truth_3d# 实例化Databucket类
data = Databucket()# 定义图片处理函数
def process_image(img):output_image = np.zeros((img.shape[0] + data.worldmap.shape[0],img.shape[1] * 2, 3))# 定义第一张图为摄像头原图imgoutput_image[0:img.shape[0], 0:img.shape[1]] = img# 定义第二张图为img经过透视变换后的图像warped = perspect_transform(img, src, dst)output_image[0:img.shape[0], img.shape[1]:] = warpedgray_warped = cv2.cvtColor(warped, cv2.COLOR_RGB2GRAY)ret, img_thresh = cv2.threshold(gray_warped, 160, 255, cv2.THRESH_BINARY)test_image = np.expand_dims(img_thresh, axis=2)output_image[180:340, img.shape[1]:, 0] = img_thresh# 漫游者号的坐标系,在每一个图像中都不同xpix, ypix = rover_coords(img_thresh)worldmap = data.worldmapx_world, y_world = pix_to_world(xpix, ypix, data.xpos[data.count], data.ypos[data.count], data.yaw[data.count], data.worldmap.shape[0], 20 )# 相应位置颜色+1worldmap[y_world, x_world] += 1map_add = cv2.addWeighted(ground_truth_3d, 1, worldmap, 0.2, 0)output_image[img.shape[0]:, 0:data.worldmap.shape[1]] = map_addcv2.putText(output_image, "Test_Video", (20, 20),cv2.FONT_HERSHEY_COMPLEX, 0.4, (255, 255, 255), 1)# 跟踪Databucket中的索引if data.count < len(data.images) - 1:data.count += 1return output_image# 将处理过的图像制作成视频,使用moviepy
output = '.../test_mapping.mp4'clip = ImageSequenceClip(data.images, fps=60)
new_clip = clip.fl_image(process_image)# 只接受彩色图片
new_clip.write_videofile(output, audio=False)

输出的视频结果如下:

Udacity机器人软件工程师课程笔记(三)-样本搜索和找回-基于漫游者号模拟器-使用moviepy输出测试视频相关推荐

  1. Udacity机器人软件工程师课程笔记(五)-样本搜索和找回-基于漫游者号模拟器-自主驾驶

    9.自主驾驶 在接下来的环节中,我们要实现漫游者号的自动驾驶功能. 完成这个功能我们需要四个程序,第一个为感知程序,其对摄像头输入的图片进行变换处理和坐标变换使用.第二个程序为决策程序,功能是帮助漫游 ...

  2. Udacity机器人软件工程师课程笔记(一)-样本搜索和找回-基于漫游者号模拟器

    Robotics Software engineer编程笔记(一) 使用Udacity提供的漫游者号模拟器创建环境地图,寻找样本. 该项目是根据美国国家航空航天局(NASA)的样本返回挑战进行建模的. ...

  3. Udacity机器人软件工程师课程笔记(六)-样本搜索和找回-基于漫游者号模拟器-优化和样本找回

    10.优化和样本找回 (1)优化概述 在之前的一篇笔记中,我们已经实现了基本的漫游者号的自主驾驶功能.但是因为我们的感知子函数和决策子函数都过于简单,使漫游者号不能很好的自动驾驶和样本找回. 这篇笔记 ...

  4. Udacity机器人软件工程师课程笔记(四)-样本搜索和找回-基于漫游者号模拟器-决策树

    7.做出决策 我们已经建立了感知步骤Perception.py,接下来要构建决策函数decision.py . 我们利用一个基础的人工智能模型--决策树模型.其结构如下: 由于我们采用一个非常简单的模 ...

  5. Udacity机器人软件工程师课程笔记(二)-样本搜索和找回-基于漫游者号模拟器

    Robotics Software engineer编程笔记(二) 5.确定漫游者号的行进方向 (1)漫游者号如何确定自己的行进方向? 我们已经有了一个由前置摄像头得到的图像,然后可以通过对图像进行处 ...

  6. Udacity机器人软件工程师课程笔记(七)-ROS介绍和Turtlesim包的使用

    Robotics Software engineer笔记 1.ROS简介与虚拟机配置 (1)ROS简介 ROS是一款机器人软件框架,即机器人操作系统(Robot Operating System). ...

  7. Udacity机器人软件工程师课程笔记(三十五) - SLAM - 基于网格的FastSLAM

    一.SLAM介绍 即使定位和建图问题(simultaneous localization and mapping),一般简称为SLAM, 也称作(Concurrent Mapping and Loca ...

  8. Udacity机器人软件工程师课程笔记(三十六) - GraphSLAM

    一.引入 GraphSLAM是解决完整的slam问题的slam算法.这意味着该算法将恢复整个路径和地图,而不仅仅是最近的姿势和地图.这种差异使它可以考虑当前姿势与先前姿势之间的依赖性.适用于我们的Gr ...

  9. Udacity机器人软件工程师课程笔记(三十三) - 蒙特卡洛定位算法(MCL)

    一.概述 之前的文章介绍过卡尔曼滤波算法进行定位,我们知道kalman算法适合用于线性的高斯分布的状态环境中,我们也介绍了EKF,来解决在非高斯和非线性环境下的机器人定位算法.但是他们在现实应用中存在 ...

最新文章

  1. CVPR 2021 | MI-AOD: 少量样本实现高检测性能
  2. jQuery 判断鼠标键
  3. mongodump 失败且导致mongo服务挂掉【本质原因,wt文件损坏】
  4. 第218天:Angular---模块和控制器
  5. 计算机组成原理组合逻辑控制器实验报告,计算机组成原理实验报告—认识性实验 华北电力大学.doc...
  6. 20190601:第一个JDBC程序
  7. springmvc + ehcache + redis+mybatis 分布式架构
  8. 机器学习-----车标识别
  9. pyecharts动态图表嵌入ppt
  10. 服务器虚拟资源池,大型医院基于Hyper-V的虚拟化服务器资源池构建
  11. 安全问题的思考---君子不立于危墙之下
  12. SpringBoot2.x 集成 FreeMarker
  13. 全国地铁数据爬取-python
  14. “35岁危机”不再,算法岗应届生平均月薪超3.2万,人工智能行业掀抢人大战!...
  15. 如何在windows中设置定时提醒
  16. 时间序列分析中resample函数
  17. BAYKEE app开发中遇到的一些问题和解决办法
  18. opencv自动裁切_OpenCVSharp 裁剪和缩放 bitmap图像
  19. Windows Server 2019 DC 上修改域名
  20. 毕业设计结论计算机应用技术,计算机应用技术专业毕业设计论文.docx

热门文章

  1. 20181113-2 每周例行报告
  2. git cherry-pick. 如何把已经提交的commit, 从一个分支放到另一个分支
  3. 零基础学习python_异常处理(32-33课)
  4. Python3中对Dict的内存优化
  5. ERROR 1366 (HY000): Incorrect string value: '\xD5\xC5\xC8\xFD' for column 'name' at row 1
  6. VueJs开发笔记—IDE选择和优化、框架特性、数据调用、路由选项及使用
  7. 高级软件工程的第一次作业:回顾自己本科设计
  8. PAT (Basic Level) Practise (中文)-1025. 反转链表 (25)
  9. 服务器php将视频转为m3u8,php应用ffmpeg对mp4文件转换并生成m3u8视频流文件
  10. Django mysql 多线程_【实例:利用Django管理后台管理IP地址】(四)Django test+多线程+数据库+(踩坑)...