OpenCV与AI深度学习 | 实战|OpenCV实时弯道检测(详细步骤+源码)

本文来源公众号“OpenCV与AI深度学习”,仅用于学术分享,侵权删,干货满满。

原文链接:实战|OpenCV实时弯道检测(详细步骤+源码)

0 导读

本文主要介绍如何使用 Python 和 OpenCV实现一个实时曲线道路检测系统

图片

1 背景介绍

    在任何驾驶场景中,车道线都是指示交通流量和车辆应行驶位置的重要组成部分。这也是开发自动驾驶汽车的一个很好的起点!在我之前的车道检测项目的基础上,我实现了一个曲线车道检测系统,该系统工作得更好,并且对具有挑战性的环境更加稳健。车道检测系统是使用 OpenCV 库用 Python 编写的。    

下面是实现步骤:

  • 畸变校正

  • 透视变换

  • Sobel滤波

  • 直方图峰值检测

  • 滑动窗口搜索

  • 曲线拟合

  • 覆盖检测车道

  • 应用于视频

2 畸变矫正

    相机镜头扭曲入射光以将其聚焦在相机传感器上。尽管这对于我们捕捉环境图像非常有用,但它们最终往往会稍微不准确地扭曲光线。这可能导致计算机视觉应用中的测量不准确。然而,我们可以很容易地纠正这种失真。

    我们可以使用棋盘格来标定相机然后做畸变校正:

    测试视频中使用的相机用于拍摄棋盘格的 20 张照片,用于生成畸变模型。我们首先将图像转换为灰度,然后应用cv2.findChessboardCorners()函数。我们已经知道这个棋盘是一个只有直线的二维对象,所以我们可以对检测到的角应用一些变换来正确对齐它们。用 cv2.CalibrateCamera() 来获取畸变系数和相机矩阵。相机已校准!

    然后,您可以使用它cv2.undistort()来矫正其余的输入数据。您可以在下面看到棋盘的原始图像和校正后的图像之间的差异:

下面看实现代码:

def undistort_img():
    # Prepare object points 0,0,0 ... 8,5,0
    obj_pts = np.zeros((6*9,3), np.float32)
    obj_pts[:,:2] = np.mgrid[0:9, 0:6].T.reshape(-1,2)
    # Stores all object points & img points from all images
    objpoints = []
    imgpoints = []
    # Get directory for all calibration images
    images = glob.glob('camera_cal/*.jpg')
    for indx, fname in enumerate(images):
        img = cv2.imread(fname)
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        ret, corners = cv2.findChessboardCorners(gray, (9,6), None)
        if ret == True:
            objpoints.append(obj_pts)
            imgpoints.append(corners)
    # Test undistortion on img
    img_size = (img.shape[1], img.shape[0])
    # Calibrate camera
    ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, img_size, None,None)
    dst = cv2.undistort(img, mtx, dist, None, mtx)
    # Save camera calibration for later use
    dist_pickle = {}
    dist_pickle['mtx'] = mtx
    dist_pickle['dist'] = dist
    pickle.dump( dist_pickle, open('camera_cal/cal_pickle.p', 'wb') )
def undistort(img, cal_dir='camera_cal/cal_pickle.p'):
    #cv2.imwrite('camera_cal/test_cal.jpg', dst)
    with open(cal_dir, mode='rb') as f:
        file = pickle.load(f)    mtx = file['mtx']
    dist = file['dist']
    dst = cv2.undistort(img, mtx, dist, None, mtx)
    return dst
undistort_img()
img = cv2.imread('camera_cal/calibration1.jpg')
dst = undistort(img) # Undistorted image

这是应用于道路图像的失真校正。您可能无法注意到细微的差异,但它会对图像处理产生巨大影响。

图片

3 透视变换

    在相机空间中检测弯曲车道并不是很容易。如果我们想鸟瞰车道怎么办?这可以通过对图像应用透视变换来完成。这是它的样子:

    注意到什么了吗?通过假设车道位于平坦的 2D 表面上,我们可以拟合一个多项式,该多项式可以准确地表示车道空间中的车道!这不是很酷吗?

    您可以使用cv2.getPerspectiveTransform()函数将这些变换应用于任何图像,以获取变换矩阵,并将cv2.warpPerspective()其应用于图像。下面是代码:

def perspective_warp(img,
                     dst_size=(1280,720),
                     src=np.float32([(0.43,0.65),(0.58,0.65),(0.1,1),(1,1)]),
                     dst=np.float32([(0,0), (1, 0), (0,1), (1,1)])):
    img_size = np.float32([(img.shape[1],img.shape[0])])
    src = src* img_size
    # For destination points, I'm arbitrarily choosing some points to be
    # a nice fit for displaying our warped result
    # again, not exact, but close enough for our purposes
    dst = dst * np.float32(dst_size)
    # Given src and dst points, calculate the perspective transform matrix
    M = cv2.getPerspectiveTransform(src, dst)
    # Warp the image using OpenCV warpPerspective()
    warped = cv2.warpPerspective(img, M, dst_size)
    return warped

4 Sobel滤波

   在之前的版本中,我使用颜色过滤掉了车道线。然而,这并不总是最好的选择。如果道路使用浅色混凝土代替沥青,道路很容易通过彩色滤光片,管道会将其感知为白色车道线,此方法不够稳健。

    相反,我们可以使用类似于边缘检测器的方法,这次过滤掉道路。车道线通常与道路具有高对比度,因此我们可以利用这一点。之前版本 1 中使用的Canny边缘检测器利用Sobel 算子来获取图像函数的梯度。OpenCV 文档对它的工作原理有很好的解释。我们将使用它来检测高对比度区域以过滤车道标记并忽略道路。

    我们仍将再次使用 HLS 色彩空间,这一次是为了检测饱和度和亮度的变化。sobel 算子应用于这两个通道,我们提取相对于 x 轴的梯度,并将通过梯度阈值的像素添加到表示图像中像素的二进制矩阵中。这是它在相机空间和车道空间中的样子:

 

    请注意,远离相机的图像部分不能很好地保持其质量。由于相机的分辨率限制,来自更远物体的数据非常模糊和嘈杂。我们不需要专注于整个图像,所以我们可以只使用它的一部分。这是我们将使用的图像的样子(ROI):

5 直方图峰值检测

   我们将应用一种称为滑动窗口算法的特殊算法来检测我们的车道线。但是,在我们应用它之前,我们需要为算法确定一个好的起点。如果它从存在车道像素的位置开始,它会很好地工作,但是我们如何首先检测这些车道像素的位置呢?其实很简单!

    我们将获得图像相对于 X 轴的直方图。下面直方图的每个部分都显示了图像每列中有多少个白色像素。然后我们取图像每一侧的最高峰,每条车道线一个。这是直方图的样子,在二值图像旁边:

6 滑动窗口搜索

   滑动窗口算法将用于区分左右车道边界,以便我们可以拟合代表车道边界的两条不同曲线。

    算法本身非常简单。从初始位置开始,第一个窗口测量有多少像素位于窗口内。如果像素数量达到某个阈值,它将下一个窗口移动到检测到的像素的平均横向位置。如果没有检测到足够的像素,则下一个窗口从相同的横向位置开始。这一直持续到窗口到达图像的另一边缘。

    落在窗口内的像素被赋予一个标记。在下图中,蓝色标记的像素代表右侧车道,红色标记的像素代表左侧:

7 曲线拟合

   项目的其余部分非常简单。我们分别使用 对红色和蓝色像素应用多项式回归np.polyfit(),然后检测器就完成了!

    这是曲线的样子:

8 绘制检测车道

   这是检测系统的最后一部分,用户界面!我们只需创建一个覆盖层来填充检测到的车道部分,然后我们最终可以将其应用于视频。一旦应用于视频检测,您应该会看到以下输出:

图片

9 结论

   就是这样,一个基本的弯曲车道检测器!它比以前的版本好得多,它甚至可以处理弯曲的车道!但是,它仍然会在一定程度上受到阴影和道路纹理剧烈变化的影响。在我的下一个车道检测项目中,我们将使用一些机器学习技术来开发一个非常强大的车道和车辆检测系统,谢谢!

完整代码:

https://github.com/kemfic/Curved-Lane-Lines/blob/master/P4.ipynb

参考链接:

https://www.hackster.io/kemfic/curved-lane-detection-34f771

THE END!

文章结束,感谢阅读。您的点赞,收藏,评论是我继续更新的动力。大家有推荐的公众号可以评论区留言,共同学习,一起进步。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Collection与数据结构 数据结构预备知识(一) :集合框架与时间空间复杂度

1.集合框架 1.1 什么是集合框架 Java集合框架,又被称为容器,是定义在java.util包下的一组接口和接口实现的一些类.其主要的表现就是把一些数据放入这些容器中,对数据进行便捷的存储,检索,管理.集合框架底层实现原理其实就是各种数据结构的实现方法,所以在以后的学习中,我们会…

C语言中常用的文件操作

本文将介绍常用的关于文件操作函数,如fopen,fclose,fread,fwrite,feek,ftell,rewind以及feof和ferror等文件操作操作函数,还介绍一些用于所有输入输出流的函数如fgetc,fputc,fgets,fputs,fprintf,fscanf等函数,还介绍了sscanf,sprintf函数,fe…

【C++初阶】之类和对象(中)

【C初阶】之类和对象(中) ✍ 类的六个默认成员函数✍ 构造函数🏄 为什么需要构造函数🏄 默认构造函数🏄 为什么编译器能自动调用默认构造函数🏄 自己写的构造函数🏄 构造函数的特性 ✍ 拷贝构造…

原型链-(前端面试 2024 版)

来讲一讲原型链 原型链只存在于函数之中 四个规则 1、引用类型,都具有对象特性,即可自由扩展属性。 2、引用类型,都有一个隐式原型 __proto__ 属性,属性值是一个普通的对象。 3、引用类型,隐式原型 __proto__ 的属…

Java官网64位下载:获取高效、安全的Java平台

Java官网64位下载:获取高效、安全的Java平台 Java是一种广泛应用于软件开发和跨平台应用程序的编程语言。无论是开发桌面应用程序、移动应用程序还是大型企业级系统,Java都是一种可靠且强大的选择。为了确保你获取到高效、安全的Java平台,本文…

supervision CV视觉可视化辅助工具

参考: https://supervision.roboflow.com/latest/ https://github.com/roboflow/supervision/tree/develop/examples 版本: pip install -U supervisionultralytics-8.1.35 (大于8.1才行,不然可能会有错误AttributeError: ‘Res…

第5章.零、单例与小样本提示词的编写之道

零提示、单个提示和小样本提示是用于从ChatGPT中生成文本的技术。在数据匮乏或任务全新、定义模糊之时,我们用微妙的提示,让ChatGPT从无到有,生成文本。 面对任务,空无一例:模型凭借对任务的广泛理解,独辟…

贝锐蒲公英虚拟DMZ:工业设备异地组网,解决网段冲突难题

虚拟DMZ 产品/技术的原理传统DMZ: DMZ中文名称为“隔离区”,也称“非军事化区”;它是为解决安装防火墙后外部网络不能访问内部网络服务器的问题。网关DMZ功能开启后, 将内网的一台服务器完全暴露在外网(内网某个IP绑…

在CentOS7上部署Nginx并测试指南

Nginx部署测试 Nginx简介 Nginx是俄罗斯人Igor Sysoev编写的一款高性能的HTTP和反向代理服务器。 Nginx选择了epoll和kqueue作为网络I/O模型,在高连接并发的情况下,内存、CPU等系统资源消耗非常低,运行稳定。 正向代理与反向代理 正向代…

Swift 周报 第四十八期

文章目录 前言新闻和社区苹果突然不造车了,雷军:非常震惊!分析师:马斯克或是最大赢家你会爱上的开发者活动 提案通过的提案正在审查的提案 Swift论坛推荐博文话题讨论关于我们 前言 本期是 Swift 编辑组自主整理周报的第四十八期…

【MySQL】16.事务管理(重点) -- 2

1. 事务隔离级别 如何理解隔离性1 MySQL服务可能会同时被多个客户端进程(线程)访问,访问的方式以事务方式进行一个事务可能由多条SQL构成,也就意味着,任何一个事务,都有执行前,执行中,执行后的阶段。而所…

基于Echarts的超市销售可视化分析系统(数据+程序+论文)

本论文旨在研究Python技术和ECharts可视化技术在超市销售数据分析系统中的应用。本系统通过对超市销售数据进行分析和可视化展示,帮助决策层更好地了解销售情况和趋势,进而做出更有针对性的决策。本系统主要包括数据处理、数据可视化和系统测试三个模块。…

基于随机森林与LSTM神经网络的住宅用电比较分析及预测 代码+论文 完整毕设

摘要 本文旨在探讨基于随机森林(Random Forest)与长短期记忆神经网络(Long Short-Term Memory, LSTM)的住宅用电比较分析及预测方法。随机森林是一种集成学习方法,通过构建多个决策树进行预测,具有较强的鲁…

FL Studio21.2.3.4004音乐制作及里程碑及功能介绍

**FL Studio 21.2.3.4004:音乐制作的新里程碑** 随着数字音乐制作技术的不断发展,音乐制作软件也在不断迭代升级。今天,我们将聚焦于一款广受欢迎的音乐制作软件——FL Studio 21.2.3.4004,探讨它如何成为音乐制作领域的新里程碑…

【技巧】如何设置和解除PDF的“打开密码”?

在工作中,我们经常会接触到PDF文件,对于重要的文件,往往还会设置密码保护,那PDF的“打开密码”如何设置和解除呢?下面小编分享两种方法,一起来看看吧! 方法一:使用PDF编辑器 大部分…

基于连续深度编解码器网络的医学图像鲁棒边界分割

基于连续深度编解码器网络的医学图像鲁棒边界分割 摘要引言相关工作方法-----III. PROPOSED METHOD Robust_Boundary_Segmentation_in_Medical_Images_Using_a_Consecutive_Deep_Encoder-Decoder_Network 摘要 图像分割通常用于定位目标和边界。它在许多临床应用中是必不可少的…

一步一步搭建,功能最全的权限管理系统之动态路由菜单

一、前言 这是一篇搭建权限管理系统的系列文章。 随着网络的发展,信息安全对应任何企业来说都越发的重要,而本系列文章将和大家一起一步一步搭建一个全新的权限管理系统。 说明:由于搭建一个全新的项目过于繁琐,所有作者将挑选核心…

1320亿参数,性能超LLaMA2、Grok-1!开源大模型DBRX

3月28日,著名数据和AI平台Databricks在官网正式开源大模型——DBRX。 DBRX是一个专家混合模型(MoE)有1320亿参数,能生成文本/代码、数学推理等,有基础和微调两种模型。 根据DBRX在MMLU、HumanEval和 GSM8K公布的测试…

蓝牙双模音频模块支持串口AT指令控制介绍

目录 一、BT401蓝牙音频模块简介 蓝牙音频模块支持串口AT指令控制介绍,这里推荐BT401蓝牙模块,功能简介如下: BT401模块是一款支持蓝牙、U盘、TF卡播放的5合1的解决方案。模组的亮点在支持无损音乐的播放,以及简单明了的串口控制…

婴儿专用洗衣机哪个牌子好?四大爆款婴儿洗衣机合集安利

婴儿的衣物需要特别的护理,因为婴儿的皮肤非常娇嫩,需要一个无菌,没有刺激性的洗涤环境,于是婴儿洗衣机应运而生。如果你非常注重婴儿衣物的卫生问题,那么婴儿洗衣机则是非常理想的选择。毕竟,在婴儿吃奶或…