优达学城自动驾驶课程项目——车道检测

  汽车在道路上行驶需要遵循一定的行驶规则,路面的车道则起到规范汽车行驶规则的作用。车道的种类有很多种,如单行线、双行线,虚线、网格线等,不同颜色、形状的车道线代表着不同的行驶规则,汽车和行人可以根据这些规则来使用道路,避免冲突。因此,准确检测并识别车道类型,并按照相应规则正确行驶,是汽车实现自动驾驶的基础。

  优达学城的自动驾驶项目课程包含了一个车道线检测项目,其主要目的就是教给无人车如何检测并识别车道,本文档将该项目内容进行总结整理。

  车道线检测方法主要分为两类:(1)基于道路特征的车道线检测;(2)基于道路模型车道线检测。基于道路特征的车道线检测作为主流检测方法之一,主要是利用车道线与道路环境的物理特征差异进行图像的分割与处理,从而突出车道线特征,以实现车道线的检测。该方法复杂度较低,实时性较高,但容易受到道路环境干扰。基于道路模型的车道线检测主要是基于不同的二维或三维道路图像模型(如直线型、抛物线型、样条曲线型、组合模型等),采用相应方法确定各模型参数,然后进行车道线拟合。该方法对特定道路的检测具有较高的准确度,但局限性强、运算量大、实时性较差。

  本项目采用的是基于道路灰度特征的车道线检测方法。主要流程如下:

(1)灰度图像转换

  自动驾驶车载摄像头实时拍摄的照片为RGB格式,为了能够提取其灰度特征,首先要将3通道的RGB图形转换为单通道的gray图。这里可以借助python中的opencv工具包来实现这一转换。采用的代码如下:

image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

  其中,image是摄像机采集的RGB原始图像(左图),image_gray是转换后的灰度图像(右图)。

(2)边缘提取

  完成RGB图形和灰度图的转换之后,图片在计算机中被看作是一组由像素值组成的矩阵,像素值是介于0~255之间的数据,其中0代表图片中的纯黑色,255代表纯白色。但是,这样的数据组不能被计算机理解,接下来需要进行图形的边缘提取。

  对图形进行边缘提取的目的是找出图形中的各物体的轮廓特征。本项目采用canny边缘检测技术来完成图形的边缘提取,该方法的主要流程图如下:

  其中,消除噪声模块主要用于去除图形中的噪点,避免噪点被识别为轮廓;计算像素梯度为canny算法的核心,通过计算各处的梯度值来判读图形中颜色的变化;通过非极大值抑制则可以去除虚假的边缘点,而只保留最可能成为边缘的像素点;最后通过设置双滞后阈值来去除伪边缘,进一步增强车道检测的准确性。 下图是完成边缘提取之后的图形,可以看出图形中的物体轮廓及线条都已经被刻画出来,只保留线条的图形看上去更加简洁,也更容易被计算机识别。

(3)划定region of interest(roi)

  虽然原图像中的线条及物体轮廓已经描绘出来了,但是我们始终要记得项目的目的:检测车道线!

  也就是说,图形中除了车道线以外的部分都不是我们感兴趣的目标。在进行下一步之前,我们可以通过划定感兴趣领域(roi)来简化图形。

  这里问题来了:划定感兴趣领域是必须的吗?答案是否定的,即使我们不进行这一步操作依然能实现最终的目标,但是通过划定roi,我们可以大大缩减图形中的线条数量,从而使接下来的计算量大大减小;此外,把无关内容抛弃掉之后,我们同样也就减小了了计算机出现错误的可能性。

  另外一个问题是:如何选择roi?

  这个问题其实是没有固定答案的,例如在本项目中,我们假定汽车采集图像用的摄像头是安装在汽车的正前方的,大部分情况下汽车在道路上行驶于两条相邻的车道线中间(除非需要变道行驶),因此我们可以认为只需在图形的中间选定一块区域即可。

  roi的形状不是固定的,根据实际需求的不同,可以选择三角形、矩形框、圆形、椭圆形、不规则多边形等等。这里为了简单,采用了三角形。三角形在原图中的位置可以参照下图:

  三角形的大小是可以调整的。

  划定好roi之后,可以编写rigion_of_interest函数,将roi之外的线条去掉,只保留roi内部的线条。由于摄像头拍出来的车道线有透视效应,因此形状类似于三角形,因此可以用三角形作为roi。最终得到的过滤后的图形为:

  可以看到图形得到大大精简,只保留了部分车道线,远方物体的轮廓线没有被保留。

(4)Hough变换

  至此,汽车摄像机拍到的原始RGB图形已经逐步被简化为只保留车道线的图形,看上去我们的工作已经完成。这里还有一个问题需要提及,计算机可以通过比较像素值识别图形中的白色点,然后计算线条的斜率来绘制图形。然而,如果存在一条车道线与水平方向垂直,那么这时候线条的斜率趋近于无穷大,这中特殊情况计算机是无法处理的。

  为了解决这一问题,需要对图片进行霍夫变换(Hough Transform)。霍夫变换的原理这里不再赘述,读者可以在网上查阅相关资料。总之,霍夫变换主要解决车道线斜率无穷大的情况。在python的霍夫变换opencv模块中,有函数可以直接完成图形的霍夫变换,函数调用代码如下:

img_hough = cv2.HoughLinesP(img, rho, theta, threshold, np.array([]), minLineLength,maxLineGap)

  函数的参数中,img为需要进行霍夫变换的图形;rho和theta分别为距离和角度的分辨率;阈值threshold控制将一条线判定为直线的最少点数;minLineLength为将一条线识别为直线的最低长度,即只有线条长度大于该值时才将线条标记出来;maxLineGap则为线段上两点之间的最大阈值,如果两点之间的距离大于该值,则认为两点不属于同一条直线。经过霍夫变换后,得到的图形为:

   由于在本例中不存在车道线斜率无穷大的情况,因此变换前后的图形无差别。为了强行加以区分,这里把原来的白色改为了蓝色。

(5)画车道线

  现在,图形中的车道线已经被识别出来,接下来只需要将车道线刻画在原图上,以便于检查识别效果即可。

  可以看到,在原图中的车道线已经被识别出来,且效果非常好!

  由于划定了roi,远处的车道线没有别标记出来。但是不用担心,汽车在行驶过程中,车道线是实时识别的,因此可以通过不断更新将远处的车道线识别出来。 为了进一步验证使用该方法进行车道检测的效果,我们重新选择一张图看看效果:

  通过这一实例可以验证,该方法可以比较完美的检测车道线。(左右两幅图色调有所不同,这是由于图像读取函数造成的。)

**************************************** 分割线 ****************************************

>>>>>>视频检测

  以上部分是对单张图片进行车道检测的方法。在实际应用中,需要在汽车行驶过程中进行实时车道检测,从而避免汽车偏离车道。此时汽车摄像机采集到的信息往往以视频的形式呈现,因此需要在视频中识别出车道线。这听上去好像有点复杂,不过我们完全不用担心,因为摄像头采集到的视频本质上就是多张图片的叠加,因此只需要对视频进行分割,将单位时间内的视频分为多张图片的叠加,然后将每张图片分别按照上述方法进行车道检测,最后将结果再重新叠加为视频即可。

  当然,对于不懂视频编辑的新手来说,怎样才能将一段视频分割为图片,然后再合成视频呢?这里不得不夸一下强大的python,python已经提前准备好了VideoFileClip工具,只需按规则调用相关函数,即可完成图片的提取与视频的合成。然后采用图片车道线提取方法,对各张图片进行处理即可。下面的代码中,example1_output是在我的电脑上存储处理后视频的地址;clip1后面的地址是待处理的视频的地址。

example1_output = ‘.../test_videos_output/solidWhiteRight1.mp4‘
clip1 = VideoFileClip(".../test_videos/solidWhiteRight.mp4")
print clip1
example1_clip = clip1.fl_image(process_image) #NOTE: this function expects color images!!
%time example1_clip.write_videofile(example1_output, audio=False)

>>>>>>视频检测结果展示

  处理后的视频为本文件夹中的solidWhiteRight_output.mp4文件。可以看到,视频处理结果令人满意,道路左右两侧的实线和虚线均被检测出来。

**************************************** 分割线 ****************************************

  本项目中还提供了另外一段由汽车前置摄像头采集到的视频,并命名为challenge.mp4(可在本文件夹中查找)。这段视频中路面存在阴影及破损的情况,给道路线检测带来干扰。采用上述方法,对该视频进行处理,处理结果可查看文件challenge——output.mp4。从视频中可以看出,在第3-6秒钟的时间区间内,道路线检测结果非常不理想,主要表现为:

  (1)错误的将树枝阴影识别为道路线;

  (2)将汽车前沿识别为道路线;

  (3)在道路有破损的路面上,无法识别出道路线。这些问题会严重影响自动驾驶汽车的行驶,因此需要想办法加以改进。

>>>>>>改进方法

  (1)增大Canny函数的阈值

  python中调用Canny函数需要输入一大一小两个阈值,当某一像素点的梯度值小于较小阈值时,该像素点被剔除;当梯度值大于较大阈值时,像素点被保留;梯度值位于两个阈值之间时,另行考虑。因此,这里同时增大两个阈值的值,可以将梯度较小的像素点去除,从而排除掉树枝在地上的阴影(因为这些阴影的梯度值往往小于车道线的梯度值)。

  (2)将黄线转换为白线

  在道路破损部分,车道线无法识别的原因是黄色的车道线与路面颜色对比不明显,即车道线上的像素点梯度值不够大导致被剔除。为了解决该问题,这里首先通过编写函数将黄色的线转换为白色的线,来提高车道线上像素点的梯度值,从而提高像素点被识别的概率。函数代码如下:

def yellow_transform(image):
    image_hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
    lower_yellow = np.array([40, 100, 20])
    upper_yellow = np.array([100, 255, 255])
    mask = cv2.inRange(image_hsv, lower_yellow, upper_yellow)
    return mask

>>>>>>结果验证

  改进之后,我们在文件名文challenge.mp4的视频上进行验证,为了使效果更加明显,这里对原视频进行处理,使其更暗从而使检测出的车道线更容易在图上观察到。

  最后的结果为本文件夹中命名为challenge_output1.mp4的文件。

  可以看出,经过改进之后,原来被错误的识别为车道线的树枝阴影大部分被忽略。在车道破损部分,有些车道线可以被检测出来。虽然结果依然不算完美,仍然存在很多问题,但是与原来的结果相比已经产生明显提升,因此可以认为我们的改进方法是有效的。但是改进之后的程序运算量会加大,运算时间也会延长,这就需要更快的设备来完成运算。这也是改进方法的弊端。

# coding:UTF-8
# importing some useful packages
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import cv2
% matplotlib inline
import math

def region_of_interest(img, vertices):
    """
    Applies an image mask.

    Only keeps the region of the image defined by the polygon
    formed from `vertices`. The rest of the image is set to black.
    `vertices` should be a numpy array of integer points.
    """
    # defining a blank mask to start with
    mask = np.zeros_like(img)
    # defining a 3 channel or 1 channel color to fill the mask with depending on the input image
    if len(img.shape) > 2:
        channel_count = img.shape[2]  # i.e. 3 or 4 depending on your image
        ignore_mask_color = (255,) * channel_count
    else:
        ignore_mask_color = 255
    # filling pixels inside the polygon defined by "vertices" with the fill color
    cv2.fillPoly(mask, vertices, ignore_mask_color)

    # returning the image only where mask pixels are nonzero
    masked_image = cv2.bitwise_and(img, mask)
    return masked_image

def draw_lines(img,lines,color,thickness):
    for line in lines:
        for x1,y1,x2,y2 in line:
            cv2.line(img,(x1,y1),(x2,y2),color,thickness)

# 霍夫变换函数
def hough_lines(img):
    """
    `img` should be the output of a Canny transform.

    Returns an image with hough lines drawn.
    """
    rho = 2
    theta = np.pi/180
    threshold = 15
    min_line_len = 60
    max_line_gap = 30
    lines = cv2.HoughLinesP(img, rho, theta, threshold, np.array([]), minLineLength=min_line_len,
                            maxLineGap=max_line_gap)

    line_img = np.zeros((img.shape[0], img.shape[1], 3), dtype=np.uint8)
    draw_lines(line_img, lines, [255,0,0], 2)
    cv2.imshow(‘hough_image‘,line_img)
    return lines,line_img

def Lane_finding(image):
    image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    image_blur = cv2.GaussianBlur(image_gray, (5,5), 0)
    low_threshold = 50
    high_threshold = 150
    image_canny = cv2.Canny(image_blur, low_threshold, high_threshold)
    cv2.imshow(‘image_canny‘, image_canny)
    # 图像像素行数
    rows = image_canny.shape[0]  # 540行
    # 图像像素列数
    cols = image_canny.shape[1]  # 960列
    left_bottom = [0, rows]  # [0,540]
    right_bottom = [cols, rows]  # [960,540]
    apex = [cols / 2, rows*0.6]  # [480,310]
    vertices = np.array([[left_bottom, right_bottom, apex]], np.int32)
    roi_image = region_of_interest(image_canny, vertices)
    cv2.imshow(‘roi_image‘, roi_image)
    lines,hough_image = hough_lines(roi_image)
    # 将得到线段绘制在原始图像上
    line_image = np.copy(image)
    draw_lines(line_image, lines, [255, 0, 0], 2)
    # line_image = cv2.addWeighted(line_image, 0.8, hough_image, 1, 0)
    cv2.imshow(‘src‘, line_image)
    cv2.waitKey(0)
    return hough_image

image = mpimg.imread("/Users/zhangzheng/Desktop/lane_lines_finding/test_images/solidYellowLeft.jpg")

if __name__ == ‘__main__‘:
    Lane_finding(image)

原文地址:https://www.cnblogs.com/key1994/p/11695519.html

时间: 2024-10-09 18:27:06

优达学城自动驾驶课程项目——车道检测的相关文章

优达学城机器学习工程师纳米学位项目介绍

本文由 meelo 原创,请务必以链接形式注明 本文地址,简书同步更新地址 一对一的项目辅导是优达学城(udacity)纳米学位的一大亮点.本文将简要介绍优达学城机器学习工程师纳米学位的6个项目.项目覆盖了机器学习的主要领域,包括回归分析.分类.聚类.增强学习及深度学习. 项目 0: 预测泰坦尼克号乘客生还率 这个项目需要你手动地实现一个简单的机器学习模型——决策树.1912年泰坦尼克号在第一次航行中与冰山碰撞沉没,泰坦尼克号乘客生还数据集记录了之中891个乘客的性别.年龄.社会阶级.配偶数量等

优达学城数据分析师纳米学位——P3项目知识点整理及代码分析

P3 OpenStreetMap 项目思路整理 P3项目的核心在于数据的整理 data cleaning 数据清洗,数据来源于开源的OpenStreetMap平台,该平台上的很多数据都是开发者自行输入的,难免会造成数据的混乱和缺失,错误,也就是所说的dirty data 脏数据 human involved data cleaning的关注点 validity completeness accuracy consistency uniformity validity 有效性 数据是否符合常理 人

优达学城数据分析师纳米学位——第一课总结

从1月13号信誓旦旦的付款了第一位的纳米学位到今天已经一周多的时间了,可以发现自己在完成任务的时候更多的在乎的是不是时间上达到了要求,而没有过多的关注于实质的内容.有时候看到课程的小节数很多就有一种畏惧感和烦躁的心情,逐渐的说服自己取放弃,这其实是一种观念上的偏差.可能是因为自己的性格比较急躁,很多事情都想要迅速的完成并且还能够保证质量,但是实际来说,只要方法得当,最后的成果总会和你投入的时间成正比,放平心态,一步一步慢慢来. 下面对第一课所学的内容做一个梳理和总结. 研究方法 数据可视化 集中

Udacity(优达学城) 300块红包优惠券

纳米学位:来自硅谷的名企官方课程 7天免费试用结束后,在"我的教室->设置->纳米学位->续费"页面上的优惠码区域,输入AF55BA53,立即减300元:

优达学城数据分析师纳米学位——第二课 jupyter notebook的使用

shift+Enter Control+Enter shift+tab 查看代码功能 tab显示相关包中的命令名称 ESC转换为命令操作 s 保存快捷键 命令行 小键盘图片 保存类型 Markdown html python文件 Markdown 单元格 使得代码更加易读  LaTeX free software可以编辑数学公式和符号 '配置Jupyter notebook' 6/11-markdown 单元格

优达学城-并行编程-Unit2 通信模块、同步机制、原子操作

(一). Parallel communication Patterns 在上一章CUDA系列学习(二)CUDA memory & variables中我们介绍了memory和variable的不同类型,本章中根据不同的memory映射方式,我们将task分为以下几种类型:Map, Gather, Scatter, Stencil, transpose. 1.1 Map, Gather, Scatter Map: one input - one output Gather: several in

优达学城-并行编程-Unit2 硬件内存

GPU负责给SM分配wrap,SM以并行方式运行程序 在一个SM上跑的所有线程可能合作解决一个子问题(错的,不一定的) 一个单Kernel程序在多个wrap上运行,包含X线程块和Y线程块,可以确定x y先后跑的顺序或是在哪个SM上跑吗? 答:伐晓得(这是cuda的小秘密= =||) GPU的优越性: 1.快速切换SM运行,无法知其间通信 2.可扩展性强,GPU越大,任务分散越广 CUDA存储器类型: 每个线程拥有自己的register and loacal memory; 每个线程块拥有一块sh

目前加尼福尼亚自动驾驶公司测试公司————20150529

获准在加州测试自动驾驶汽车的公司 科技公司和汽车制造商正在竞相开发能够自主驾驶,不需要人类干预的汽车.市场对于这类汽车的兴趣已经协助刺激了人工智能和汽车专业人士的需求.无人车开发是一个耗费资金的项目,这可能会让部分风险投资家望而却步. Zoox不予置评.另据<华尔街日报>报道,香港资产管理公司AID Partners Capital Holdings在本轮融资中向Zoox投资2000万美元.Zoom拥有140名员工,包括Alphabet.苹果以及特斯拉前员工. 在 变得低调之前,Zoox曾展示

Google Waymo 2017自动驾驶安全技术报告(一)

2017年10月Google Waymo向美国交通部提交了一份43页的安全报告,报告中详细说明了Waymo如何装备和训练自动驾驶车辆,从而避免驾驶中的一般和意外情况发生.这份报告对Waymo的自动驾驶技术进行了详细的解读,希望能够对自动驾驶从业者带来一些启发. 自动驾驶技术的必要性 2013年在全球有120万人死于交通事故:2016年美国有37461人死于道路交通事故:2015年美国有240万人在交通事故中受伤:94%美国发生的交通事故中由于人为失误引起;2/3的人在一生中至少遭遇一次酒驾事故: