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

2024-03-29 02:28

本文主要是介绍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,0obj_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 imagesobjpoints = []imgpoints = []# Get directory for all calibration imagesimages = 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 imgimg_size = (img.shape[1], img.shape[0])# Calibrate cameraret, 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 usedist_pickle = {}dist_pickle['mtx'] = mtxdist_pickle['dist'] = distpickle.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 purposesdst = dst * np.float32(dst_size)# Given src and dst points, calculate the perspective transform matrixM = 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!

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

这篇关于OpenCV与AI深度学习 | 实战|OpenCV实时弯道检测(详细步骤+源码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/857356

相关文章

线上Java OOM问题定位与解决方案超详细解析

《线上JavaOOM问题定位与解决方案超详细解析》OOM是JVM抛出的错误,表示内存分配失败,:本文主要介绍线上JavaOOM问题定位与解决方案的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一、OOM问题核心认知1.1 OOM定义与技术定位1.2 OOM常见类型及技术特征二、OOM问题定位工具

基于 Cursor 开发 Spring Boot 项目详细攻略

《基于Cursor开发SpringBoot项目详细攻略》Cursor是集成GPT4、Claude3.5等LLM的VSCode类AI编程工具,支持SpringBoot项目开发全流程,涵盖环境配... 目录cursor是什么?基于 Cursor 开发 Spring Boot 项目完整指南1. 环境准备2. 创建

MyBatis分页查询实战案例完整流程

《MyBatis分页查询实战案例完整流程》MyBatis是一个强大的Java持久层框架,支持自定义SQL和高级映射,本案例以员工工资信息管理为例,详细讲解如何在IDEA中使用MyBatis结合Page... 目录1. MyBATis框架简介2. 分页查询原理与应用场景2.1 分页查询的基本原理2.1.1 分

Nginx部署HTTP/3的实现步骤

《Nginx部署HTTP/3的实现步骤》本文介绍了在Nginx中部署HTTP/3的详细步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录前提条件第一步:安装必要的依赖库第二步:获取并构建 BoringSSL第三步:获取 Nginx

使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解

《使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解》本文详细介绍了如何使用Python通过ncmdump工具批量将.ncm音频转换为.mp3的步骤,包括安装、配置ffmpeg环... 目录1. 前言2. 安装 ncmdump3. 实现 .ncm 转 .mp34. 执行过程5. 执行结

SpringBoot 多环境开发实战(从配置、管理与控制)

《SpringBoot多环境开发实战(从配置、管理与控制)》本文详解SpringBoot多环境配置,涵盖单文件YAML、多文件模式、MavenProfile分组及激活策略,通过优先级控制灵活切换环境... 目录一、多环境开发基础(单文件 YAML 版)(一)配置原理与优势(二)实操示例二、多环境开发多文件版

深度解析Python中递归下降解析器的原理与实现

《深度解析Python中递归下降解析器的原理与实现》在编译器设计、配置文件处理和数据转换领域,递归下降解析器是最常用且最直观的解析技术,本文将详细介绍递归下降解析器的原理与实现,感兴趣的小伙伴可以跟随... 目录引言:解析器的核心价值一、递归下降解析器基础1.1 核心概念解析1.2 基本架构二、简单算术表达

Three.js构建一个 3D 商品展示空间完整实战项目

《Three.js构建一个3D商品展示空间完整实战项目》Three.js是一个强大的JavaScript库,专用于在Web浏览器中创建3D图形,:本文主要介绍Three.js构建一个3D商品展... 目录引言项目核心技术1. 项目架构与资源组织2. 多模型切换、交互热点绑定3. 移动端适配与帧率优化4. 可

深度解析Java @Serial 注解及常见错误案例

《深度解析Java@Serial注解及常见错误案例》Java14引入@Serial注解,用于编译时校验序列化成员,替代传统方式解决运行时错误,适用于Serializable类的方法/字段,需注意签... 目录Java @Serial 注解深度解析1. 注解本质2. 核心作用(1) 主要用途(2) 适用位置3

SpringBoot路径映射配置的实现步骤

《SpringBoot路径映射配置的实现步骤》本文介绍了如何在SpringBoot项目中配置路径映射,使得除static目录外的资源可被访问,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一... 目录SpringBoot路径映射补:springboot 配置虚拟路径映射 @RequestMapp