前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >挑战任务: 车道检测

挑战任务: 车道检测

作者头像
CodecWang
发布于 2021-12-07 07:35:13
发布于 2021-12-07 07:35:13
53000
代码可运行
举报
文章被收录于专栏:CodecWangCodecWang
运行总次数:0
代码可运行

挑战任务:实际公路的车道线检测。图片等可到文末引用处下载。

挑战内容

1. 在所提供的公路图片上检测出车道线并标记:

2. 在所提供的公路视频上检测出车道线并标记:

本次挑战内容来自Udacity自动驾驶纳米学位课程,素材中车道保持不变,车道线清晰明确,易于检测,是车道检测的基础版本,网上也有很多针对复杂场景的高级实现,感兴趣的童鞋可以自行了解。

挑战题不会做也木有关系,但请务必在自行尝试后,再看下面的解答噢,不然...我也没办法( ̄▽ ̄)"

挑战解答

方案

要检测出当前车道,就是要检测出左右两条车道直线。由于无人车一直保持在当前车道,那么无人车上的相机拍摄的视频中,车道线的位置应该基本固定在某一个范围内:

如果我们手动把这部分ROI区域抠出来,就会排除掉大部分干扰。接下来检测直线肯定是用霍夫变换,但ROI区域内的边缘直线信息还是很多,考虑到只有左右两条车道线,一条斜率为正,一条为负,可将所有的线分为两组,每组再通过均值或最小二乘法拟合的方式确定唯一一条线就可以完成检测。总体步骤如下:

  1. 灰度化
  2. 高斯模糊
  3. Canny边缘检测
  4. 不规则ROI区域截取
  5. 霍夫直线检测
  6. 车道计算

对于视频来说,只要一幅图能检查出来,合成下就可以了,问题不大。

图像预处理

灰度化和滤波操作是大部分图像处理的必要步骤。灰度化不必多说,因为不是基于色彩信息识别的任务,所以没有必要用彩色图,可以大大减少计算量。而滤波会削弱图像噪点,排除干扰信息。另外,根据前面学习的知识,边缘提取是基于图像梯度的,梯度对噪声很敏感,所以平滑滤波操作必不可少。

这次的代码我们分模块来写,规范一点。其中process_an_image()是主要的图像处理流程:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import cv2
import numpy as np

# 高斯滤波核大小
blur_ksize = 5
# Canny边缘检测高低阈值
canny_lth = 50
canny_hth = 150

def process_an_image(img):
    # 1. 灰度化、滤波和Canny
    gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    blur_gray = cv2.GaussianBlur(gray, (blur_ksize, blur_ksize), 1)
    edges = cv2.Canny(blur_gray, canny_lth, canny_hth)

if __name__ == "__main__":
    img = cv2.imread('test_pictures/lane.jpg')
    result = process_an_image(img)
    cv2.imshow("lane", np.hstack((img, result)))
    cv2.waitKey(0)Copy to clipboardErrorCopied

ROI截取

按照前面描述的方案,只需保留边缘图中的红线部分区域用于后续的霍夫直线检测,其余都是无用的信息:

如何实现呢?还记得图像混合中的这张图吗?

我们可以创建一个梯形的mask掩膜,然后与边缘检测结果图混合运算,掩膜中白色的部分保留,黑色的部分舍弃。梯形的四个坐标需要手动标记:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def process_an_image(img):
    # 1. 灰度化、滤波和Canny

    # 2. 标记四个坐标点用于ROI截取
    rows, cols = edges.shape
    points = np.array([[(0, rows), (460, 325), (520, 325), (cols, rows)]])
    # [[[0 540], [460 325], [520 325], [960 540]]]
    roi_edges = roi_mask(edges, points)

def roi_mask(img, corner_points):
    # 创建掩膜
    mask = np.zeros_like(img)
    cv2.fillPoly(mask, corner_points, 255)

    masked_img = cv2.bitwise_and(img, mask)
    return masked_imgCopy to clipboardErrorCopied

这样,结果图"roi_edges"应该是:

霍夫直线提取

为了方便后续计算直线的斜率,我们使用统计概率霍夫直线变换(因为它能直接得到直线的起点和终点坐标)。霍夫变换的参数比较多,可以放在代码开头,便于修改:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 霍夫变换参数
rho = 1
theta = np.pi / 180
threshold = 15
min_line_len = 40
max_line_gap = 20

def process_an_image(img):
    # 1. 灰度化、滤波和Canny

    # 2. 标记四个坐标点用于ROI截取

    # 3. 霍夫直线提取
    drawing, lines = hough_lines(roi_edges, rho, theta, threshold, min_line_len, max_line_gap)

def hough_lines(img, rho, theta, threshold, min_line_len, max_line_gap):
    # 统计概率霍夫直线变换
    lines = cv2.HoughLinesP(img, rho, theta, threshold, minLineLength=min_line_len, maxLineGap=max_line_gap)

    # 新建一副空白画布
    drawing = np.zeros((img.shape[0], img.shape[1], 3), dtype=np.uint8)
    # draw_lines(drawing, lines)     # 画出直线检测结果

    return drawing, lines

def draw_lines(img, lines, color=[0, 0, 255], thickness=1):
    for line in lines:
        for x1, y1, x2, y2 in line:
            cv2.line(img, (x1, y1), (x2, y2), color, thickness)Copy to clipboardErrorCopied

draw_lines()是用来画直线检测的结果,后面我们会接着处理直线,所以这里注释掉了,可以取消注释看下效果:

对本例的这张测试图来说,如果打印出直线的条数print(len(lines)),应该是有16条。

车道计算

这部分应该算是本次挑战任务的核心内容了:前面通过霍夫变换得到了多条直线的起点和终点,我们的目的是通过某种算法只得到左右两条车道线。

第一步、根据斜率正负划分某条线是左车道还是右车道。

斜率=\frac{y_2-y_1}{x_2-x_1}(\leq0:左,>0:右)斜率=x2​−x1​y2​−y1​​(≤0:左,>0:右)

经验之谈:再次强调,斜率计算是在图像坐标系下,所以斜率正负/左右跟平面坐标有区别。

第二步、迭代计算各直线斜率与斜率均值的差,排除掉差值过大的异常数据。

注意这里迭代的含义,意思是第一次计算完斜率均值并排除掉异常值后,再在剩余的斜率中取均值,继续排除……这样迭代下去。

第三步、最小二乘法拟合左右车道线。

经过第二步的筛选,就只剩下可能的左右车道线了,这样只需从多条直线中拟合出一条就行。拟合方法有很多种,最常用的便是最小二乘法,它通过最小化误差的平方和来寻找数据的最佳匹配函数。

具体来说,假设目前可能的左车道线有6条,也就是12个坐标点,包括12个x和12个y,我们的目的是拟合出这样一条直线:

f(x_i) = ax_i+bf(xi​)=axi​+b

使得误差平方和最小:

E=\sum(f(x_i)-y_i)^2E=∑(f(xi​)−yi​)2

Python中可以直接使用np.polyfit()进行最小二乘法拟合。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def process_an_image(img):
    # 1. 灰度化、滤波和Canny

    # 2. 标记四个坐标点用于ROI截取

    # 3. 霍夫直线提取

    # 4. 车道拟合计算
    draw_lanes(drawing, lines)

    # 5. 最终将结果合在原图上
    result = cv2.addWeighted(img, 0.9, drawing, 0.2, 0)

    return result

def draw_lanes(img, lines, color=[255, 0, 0], thickness=8):
    # a. 划分左右车道
    left_lines, right_lines = [], []
    for line in lines:
        for x1, y1, x2, y2 in line:
            k = (y2 - y1) / (x2 - x1)
            if k < 0:
                left_lines.append(line)
            else:
                right_lines.append(line)

    if (len(left_lines) <= 0 or len(right_lines) <= 0):
        return

    # b. 清理异常数据
    clean_lines(left_lines, 0.1)
    clean_lines(right_lines, 0.1)

    # c. 得到左右车道线点的集合,拟合直线
    left_points = [(x1, y1) for line in left_lines for x1, y1, x2, y2 in line]
    left_points = left_points + [(x2, y2) for line in left_lines for x1, y1, x2, y2 in line]
    right_points = [(x1, y1) for line in right_lines for x1, y1, x2, y2 in line]
    right_points = right_points + [(x2, y2) for line in right_lines for x1, y1, x2, y2 in line]

    left_results = least_squares_fit(left_points, 325, img.shape[0])
    right_results = least_squares_fit(right_points, 325, img.shape[0])

    # 注意这里点的顺序
    vtxs = np.array([[left_results[1], left_results[0], right_results[0], right_results[1]]])
    # d. 填充车道区域
    cv2.fillPoly(img, vtxs, (0, 255, 0))

    # 或者只画车道线
    # cv2.line(img, left_results[0], left_results[1], (0, 255, 0), thickness)
    # cv2.line(img, right_results[0], right_results[1], (0, 255, 0), thickness)

def clean_lines(lines, threshold):
    # 迭代计算斜率均值,排除掉与差值差异较大的数据
    slope = [(y2 - y1) / (x2 - x1) for line in lines for x1, y1, x2, y2 in line]
    while len(lines) > 0:
        mean = np.mean(slope)
        diff = [abs(s - mean) for s in slope]
        idx = np.argmax(diff)
        if diff[idx] > threshold:
            slope.pop(idx)
            lines.pop(idx)
        else:
            break

def least_squares_fit(point_list, ymin, ymax):
    # 最小二乘法拟合
    x = [p[0] for p in point_list]
    y = [p[1] for p in point_list]

    # polyfit第三个参数为拟合多项式的阶数,所以1代表线性
    fit = np.polyfit(y, x, 1)
    fit_fn = np.poly1d(fit)  # 获取拟合的结果

    xmin = int(fit_fn(ymin))
    xmax = int(fit_fn(ymax))

    return [(xmin, ymin), (xmax, ymax)]Copy to clipboardErrorCopied

这段代码比较多,请每个步骤单独来看。最后得到的是左右两条车道线的起点和终点坐标,可以选择画出车道线,这里我直接填充了整个区域:

视频处理

搞定了一张图,视频也就没什么问题了,关键就是视频帧的提取和合成,为此,我们要用到Python的视频编辑包moviepy

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
pip install moviepyCopy to clipboardErrorCopied

另外还需要ffmpeg,首次运行moviepy时会自动下载,也可手动下载。

只需在开头导入moviepy,然后将主函数改掉就可以了,其余代码不需要更改:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 开头导入moviepy
from moviepy.editor import VideoFileClip

# 主函数更改为:
if __name__ == "__main__":
    output = 'test_videos/output.mp4'
    clip = VideoFileClip("test_videos/cv2_white_lane.mp4")
    out_clip = clip.fl_image(process_an_image)
    out_clip.write_videofile(output, audio=False)Copy to clipboardErrorCopied

本文实现了车道检测的基础版本,如果你感兴趣的话,可以自行搜索或参考引用部分了解更多。

引用

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-12-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
详解车道线检测算法之传统图像处理
车道线检测算法分为传统图像处理方法和深度学习方法。本文详细介绍用传统图像处理方法来解决车道线检测问题,后文的算法源于Udacity无人驾驶课程的项目(https://www.udacity.com/),仅做参考。
3D视觉工坊
2020/11/11
1.1K0
详解车道线检测算法之传统图像处理
基于OpenCV的实时车道检测
自动驾驶汽车是人工智能领域最具颠覆性的创新之一。它们借助深度学习算法不断推动社会发展,并在移动领域创造新的机遇。自动驾驶汽车可以去任何传统汽车可以去的地方,也能像经验丰富的人类驾驶员一样完成各种操作。但是,正确的训练是非常重要的。在自动驾驶汽车的训练过程中,车道检测是其中的一个重要步骤,也是最初要完成的步骤。今天,我们将学习如何使用视频进行车道检测。
一点人工一点智能
2023/08/21
9960
基于OpenCV的实时车道检测
使用Python+OpenCV实现自动驾驶汽车的车道线检测
对于所有想知道如何在一篇文章中涵盖这一概念的人,我想说,在你深入探索之前,事情听起来很复杂。我不会说这篇文章非常简单,但是它的确是建立在非常基础的计算机视觉概念之上的。
磐创AI
2021/05/07
5.6K0
使用Python+OpenCV实现自动驾驶汽车的车道线检测
基于传统方法的车道线检测
1.canny边缘检测 基本原理:检测亮度的急剧变化(大梯度 比如从白色到黑色)在给定阈值下定义为边 预处理:转换灰度图 Canny: 降噪:噪声容易导致误检,用 5*5 的高斯滤波器(正太分布核)对图像做卷积(平滑图像) [Canny自带] 求亮度梯度:在平滑的图像上用 Sobel/Roberts/Prewitt 核沿 x 轴和 y 轴检测边缘是水平/垂直/对角线 非极大值抑制:细化边缘。检查每个像素值在先前计算的梯度方向上是否为局部最大值(相比B,C如果A是局部最大则在下一个点上检查非极大值抑制否则将
小飞侠xp
2020/03/20
1.1K0
基于传统方法的车道线检测
实战:使用 OpenCV 的自动驾驶汽车车道检测(附代码)
我们将使用 Canny 进行边缘检测。如果你不确定这是什么,请查阅相关资料,对于后文的阅读会有帮助。
小白学视觉
2022/09/28
8920
Street Lanes Finder - 检测自动驾驶汽车的车道
在今天的文章中,将使用基本的计算机视觉技术来解决对于自动驾驶汽车至关重要的街道车道检测问题。到本文结束时,将能够使用Python和OpenCV执行实时通道检测。
代码医生工作室
2019/08/01
7620
Street Lanes Finder - 检测自动驾驶汽车的车道
用霍夫变换&amp;SCNN码一个车道追踪器
大多数车道都设计得相对简单,这不仅是为了鼓励有序,还为了让人类驾驶员更容易以相同的速度驾驶车辆。因此,我们的方法可能会通过边缘检测和特征提取技术先检测出摄像机馈送回来的直线。我们将用 OpenCV(一个开源的用来实现计算机视觉算法的库)。下图是我们的方法流程的概述。
机器之心
2019/03/06
7160
用霍夫变换&amp;SCNN码一个车道追踪器
python进阶——自动驾驶寻找车道
1.若不知道怎么安装opencv或者使用的请看我的这篇文章(曾上过csdn综合热榜的top1):
淼学派对
2023/10/14
4900
python进阶——自动驾驶寻找车道
实现车道线检测
当今计算机视觉在我们的日常生活中运用的十分广泛,例如人脸识别、自动驾驶、等等 由于对自动驾驶十分感兴趣,因此就花了一些时间实现了车道线检测 环境 笔者的环境配置如下: ubuntu 16.04 python3.7 opencv >=4.0 说明:这里的系统以及python的版本都不是固定的,读者使用win10 win7也是可以的 但是python的版本一定要是3.x的版本 第三方库 这里使用的第三方库,是大家比较熟悉的opencv以及numpy import cv2 import numpy as np 函
陶陶name
2022/05/13
4440
图像边缘检测新方向--量子算法
图像边缘指的是图形周围像素灰度急剧变化的那些像素的集合,是图像最基本的特征。所谓图像边缘检测就是利用灰度值不连续的性质,以灰度突变为基础分割出目标区域,检测出符合边缘特性的边缘像素,完成图像处理。
量子发烧友
2023/02/24
6011
图像边缘检测新方向--量子算法
17: 霍夫变换
r_\theta=x_0\cdot\cos \theta+y_0\cdot\sin \thetarθ​=x0​⋅cosθ+y0​⋅sinθ
CodecWang
2021/12/07
9300
17: 霍夫变换
【C++】OpenCV:车道线检测原理与实现示例
车道线检测是自动驾驶和驾驶辅助系统中的关键任务之一。OpenCV是一个广泛使用的计算机视觉库,可以用来进行车道线检测。
DevFrank
2024/07/24
4820
基于Python利用OpenCV实现Hough变换的形状检测
在我们开始对图像应用霍夫变换之前,我们需要了解霍夫空间是什么,我们将通过一个例子来进行了解。
小白学视觉
2022/02/14
2.6K0
基于Python利用OpenCV实现Hough变换的形状检测
实战:基于霍夫变换进行线检测
最近,我们发现自己不得不在应用程序中加入文档扫描功能。在做了一些研究之后,我们偶然发现了一篇熊英写的文章,他是Dropbox机器学习团队的成员。该文章介绍了如何Dropbox的的机器学习团队通过强调他们通过去的步骤,并在每个步骤使用的算法来实现他们的文档扫描仪。通过那篇文章,我们了解了一种称为霍夫变换的方法, 以及如何将其用于检测图像中的线条。因此,在本文中,我们想解释Hough变换算法,并提供该算法在Python中的“从头开始”的实现。
小白学视觉
2021/03/30
9680
实战:基于霍夫变换进行线检测
基于OpenCV的表格文本内容提取
小伙伴们可能会觉得从图像中提取文本是一件很麻烦的事情,尤其是需要提取大量文本时。PyTesseract是一种光学字符识别(OCR),该库提了供文本图像。
小白学视觉
2022/02/14
2.8K0
基于OpenCV的表格文本内容提取
OpenCV与图像处理(四)
以下代码均在python3.6,opencv4.2.0环境下试了跑一遍,可直接运行。
Must
2020/07/28
6960
OpenCV与图像处理(四)
Python OpenCV 霍夫(Hough Transform)直线变换检测应用
在 OpenCV 中提供了两个霍夫直线检测的函数,一个是标准霍夫变换,另一个是概率霍夫变换。
玖柒的小窝
2021/09/20
2K0
Python OpenCV 霍夫(Hough Transform)直线变换检测应用
Python opencv图像处理基础总结(六) 直线检测 圆检测 轮廓发现
我还有改变的可能性 一想起这一点 我就心潮澎湃 文章目录 一、直线检测 使用霍夫直线变换做直线检测,前提条件:边缘检测已经完成 # 标准霍夫线变换 cv2.HoughLines(image, rho, theta, threshold, lines=None, srn=None, stn=None, min_theta=None, max_theta=None) image:经过边缘检测的输出图像,8位,单通道二进制源图像 rho:距离步长 theta:角度步长 threshold:阈值,只有
叶庭云
2020/09/17
8.7K0
Python opencv图像处理基础总结(六) 直线检测 圆检测 轮廓发现
【计算机视觉】【图像处理综合应用】路沿检测
用python的OpenCV实现视频文件的处理,用videoCapture打开视频文件,读取每一帧进行处理,然后用videoWriter保存成视频。
叶茂林
2023/11/27
4950
【计算机视觉】【图像处理综合应用】路沿检测
OpenCV:霍夫直线变换和霍夫圆变换
如果可以用数学形式表示形状,则霍夫变换是检测任何形状的一种比较流行的技术。即使形状有些破损或变形,也可以检测出形状。本文将讲解如何将它何作用于一条线。
用户3578099
2023/09/01
7800
OpenCV:霍夫直线变换和霍夫圆变换
推荐阅读
相关推荐
详解车道线检测算法之传统图像处理
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验