近年来,基于人工智能的车道检测算法得到了广泛的研究。与传统的基于特征的方法相比,许多方法表现出了优越的性能。然而,当使用具有挑战性的图像时,其准确率通常仍在低80%或高90%之间,甚至更低。
准确可靠的车道检测是车道保持(LK)、变道自动化(LCA)和车道偏离警告(LDW)功能的关键特性。车道检测的研究可以追溯到20世纪80年代。世纪之交后,LDW和LK已经商业化,有些车辆甚至有LCA。DARPA和早期ADAS产品发起的自动驾驶挑战进一步推动了车道检测系统的发展。然而,由于不利的光照/天气条件和其他物体的存在,车道检测仍然是一个具有挑战性的问题。
![8877e740995033ea051cab19b1c6ac40.png](https://i-blog.csdnimg.cn/blog_migrate/d4f8e4093894a0ce4579ac66b62eb49d.jpeg)
车道检测可通过使用单目摄像机、立体摄像机、激光雷达等实现[4]。相机因其丰富的内容功能和低廉的价格而最受欢迎。
深度学习(DL)提出了一种新的数据驱动方法,并且比大多数基于特征的方法获得了更好的性能。虽然DL系统在许多应用中取得了优异的性能,但它们经常被用作"黑匣子",其性能没有保证。这限制了它们在安全关键任务中的应用,例如自动驾驶的车道检测。
![aaf27fa08e3ff60c1bd6dc1de3ed34fa.png](https://i-blog.csdnimg.cn/blog_migrate/766350943aab34562a90d0637603a581.jpeg)
我们也可以从静态的路标和路标中推断出路标和路标。基于特征的方法,如ELAS,通常在执行车道检测/跟踪任务之前预先检测所有可能的场景线索。对于基于卷积神经网络(CNN)的方法,这种场景信息在网络结构中是隐藏/隐含的。如果能先了解场景布局,将整个图像分割成几何区域,再聚焦于车道标识区域,则分类精度有望提高。
![af170476d0ebe5e05e3d614bf9d906ef.png](https://i-blog.csdnimg.cn/blog_migrate/f409a2b60bab6aa8c06327ae7d9fef52.jpeg)
另一个重要的决定是CNN应该生成什么样的车道标签。许多现有的基于CNN的方法生成像素级的车道标记标志、车道区域掩码或参数化车道线。
![c88ab1a78233d799d4e08d4c1a908ce7.png](https://i-blog.csdnimg.cn/blog_migrate/6a69970e1b7fc18860d7c751db6e3013.jpeg)
对于大多数基于CNN的车道检测方法,输出是图像视图中像素级的车道实例掩码。然而,自主驾驶的期望输出是控制相关参数,即车辆横向偏移、航向角和曲率。为了填补这一空白,需要一些后处理程序,例如,反透视图(IPM)和车道模型拟合。由于车辆是运动的,道路并不总是平坦的,光是摄像机的内参数和外参数不足以计算摄像机与世界坐标之间的变换矩阵。需要更好的车道模型或附加程序,如消失点估计。
OpenCV+python实现的车道检测
深度学习加速了车道检测的精度,本文先介绍一下基于OpenCV的车道检测原理,当然精度虽然没有深度学习的高,但具体思想还是有类似的地方
import cv2import numpy as npdef canny(frame): gray = cv2.cvtColor(frame,cv2.COLOR_RGB2GRAY) blur = cv2.GaussianBlur(gray,(5,5),0) canny = cv2.Canny(blur,50,150) return canny
首先,我们建立几个子函数,canny子函数用来接收一个需要检测的照片,并使用高斯滤波函数对图像进行处理
高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。
cv2.GussianBlur()函数
语法:GaussianBlur(src,ksize,sigmaX [,dst [,sigmaY [,borderType]]])-> ds
t——src输入图像;图像可以具有任意数量的通道,这些通道可以独立处理,但深度应为CV_8U,CV_16U,CV_16S,CV_32F或CV_64F。
——dst输出图像的大小和类型与src相同。
——ksize高斯内核大小。 ksize.width和ksize.height可以不同,但它们都必须为正数和奇数,也可以为零,然后根据sigma计算得出。
——sigmaX X方向上的高斯核标准偏差。
——sigmaY Y方向上的高斯核标准差;
如果sigmaY为零,则将其设置为等于sigmaX;
如果两个sigmas为零,则分别从ksize.width和ksize.height计算得出;
为了完全控制结果,而不管将来可能对所有这些语义进行的修改,建议指定所有ksize,sigmaX和sigmaY。
然后使用cv2.Canny函数进行边缘检测
edge = cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient ]]])
参数解释
· image:源图像
· threshold1:阈值1
· threshold2:阈值2
· apertureSize:可选参数,Sobel算子的大小
其中,较大的阈值2用于检测图像中明显的边缘,但一般情况下检测的效果不会那么完美,边缘检测出来是断断续续的。所以这时候用较小的第一个阈值用于将这些间断的边缘连接起来。
函数返回的是二值图,包含检测出的边缘,最后子函数返回边缘检测的2值化图片
![9de83ed7fd5b985c145d7b789b647e9f.png](https://i-blog.csdnimg.cn/blog_migrate/374a140b44c25dd099942b75d12cdcbd.jpeg)
代码截图
def region_of_in(frame): height = frame.shape[0] polygons = np.array([[(0,height),(500,0),(800,0),(1300,550),(1100,height)]]) mask = np.zeros_like(frame) cv2.fillPoly(mask,polygons,255) masked = cv2.bitwise_and(frame,mask) return masked
此子涵主要用于处理边缘检测后的图片,以便获取mask,只保留车道线
![174e7074827345a159080fbb05eb774f.png](https://i-blog.csdnimg.cn/blog_migrate/eed79d59eaa7701932e883cf2c93d0d3.jpeg)
代码截图
def display_line(frame,lines): line_image = np.zeros_like(frame) if lines is not None: for line in lines: x1,y1,x2,y2 = line.reshape(4) cv2.line(line_image,(x1,y1),(x2,y2),(0,255,0),1) return line_image
此子函数主要用于检测车道线,并显示
![e925dba04a39043d8a0cf58c440381d8.png](https://i-blog.csdnimg.cn/blog_migrate/3901a79d779467a1074d60e9b3a5ffba.jpeg)
代码截图
img = cv2.imread('7.jpg')image = np.copy(img)canny = canny(image)cropped = region_of_in(canny)lines = cv2.HoughLinesP(cropped,1,np.pi/180,100,minLineLength = 5, maxLineGap=300)line_image = display_line(image,lines)frame = cv2.addWeighted(image,0.8,line_image,1,1)cv2.imshow('canny',frame)cv2.waitKey(0)
我们利用3个子函数对一张照片进行车道检测,首先我们读取一张照片,使用canny子函数进行图片边缘车道检测,然后使用region_of_in子函数进行mask的检测
cv2.HoughLinesP()函数可以查找直线段,我们把边缘检测的图片给到cv2.HoughLinesP()检测图片中的直线,然后使用display子函数显示检测到的直线
cv2.HoughLinesP()函数原型:HoughLinesP(image, rho, theta, threshold, lines=None, minLineLength=None, maxLineGap=None) · image: 必须是二值图像,推荐使用canny边缘检测的结果图像; · rho: 线段以像素为单位的距离精度,double类型的,推荐用1.0 · theta: 线段以弧度为单位的角度精度,推荐用numpy.pi/180 · threshod: 累加平面的阈值参数,int类型,超过设定阈值才被检测出线段,值越大,基本上意味着检出的线段越长,检出的线段个数越少。根据情况推荐先用100试试· lines:这个参数的意义未知,发现不同的lines对结果没影响,但是不要忽略了它的存在 · minLineLength:线段以像素为单位的最小长度,根据应用场景设置 · maxLineGap:同一方向上两条线段判定为一条线段的最大允许间隔(断裂),超过了设定值,则把两条线段当成一条线段,值越大,允许线段上的断裂越大,越有可能检出潜在的直线段
![b9be8ec51c6da4c16ae6a859e332a01f.png](https://i-blog.csdnimg.cn/blog_migrate/55acd8c6b1713117f679cd10f07805bf.jpeg)
代码截图
最后,我们使用图像混合加权实现图片的融合,主要函数为cv2.addWeighted函数
cv2.addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]]) → dst
参数说明· src1 – first input array.· alpha – weight of the first array elements.· src2 – second input array of the same size and channel number as src1.· beta – weight of the second array elements.· dst – output array that has the same size and number of channels as the input arrays.· gamma – scalar added to each sum.· dtype – optional depth of the output array; when both input arrays have the same depth, dtype can be set to -1, which will be equivalent to src1.depth().
此函数可以用一下矩阵表达式来代替:
dst = src1 * alpha + src2 * beta + gamma;
由参数说明可以看出,被叠加的两幅图像必须是尺寸相同、类型相同的;并且,当输出图像array的深度为CV_32S时,这个函数就不适用了
以上检测方法,只能检测直线的车道线,当检测圆弧过渡的车道线,就不是那么适合了,使用此方法只能简单的对车道检测,有时其检测结果也会出现不尽人意的时候
![4336f8ef0de9cc34612a2cab599ce6cf.png](https://i-blog.csdnimg.cn/blog_migrate/5c84a68d6047217d66def8d67a6ab8ee.jpeg)
车道检测