0. Introduction
这篇文章主要是一种基于canny边缘检测的传统车道线检测算法,这种算法很轻量级,实时性较好,在进行基于深度学习的车道检测学习前,实现用Traditional Method的车道检测很有意义,其主要思想如下:代码将在文章后附上。
1. Canny边缘检测
1.1 Canny的检测原理
Canny边缘检测是从不同视觉对象中提取有用的结构信息并大大减少要处理的数据量的一种技术,目前已广泛应用于各种计算机视觉系统。Canny发现,在不同视觉系统上对边缘检测的要求较为类似,因此,可以实现一种具有广泛应用意义的边缘检测技术。
- 边缘检测的一般标准包括:
① 以低的错误率检测边缘——尽可能准确的捕获图像中尽可能多的边缘
② 检测到的边缘应精确定位在真实边缘的中心。
③ 图像中给定的边缘应只被标记一次,并且在可能的情况下,图像的噪声不应产生假的边缘。边缘只要一个精确的点宽度。
- 边缘检测算法的处理流程:
- 高斯滤波,平滑图像;
为了尽可能减少噪声对边缘检测结果的影响,所以必须滤除噪声以防止由噪声引起的错误检测。为了平滑图像,使用高斯滤波器与图像进行卷积,该步骤将平滑图像,以减少边缘检测器上明显的噪声影响。
-
- 计算图像中每个像素点的梯度强度和方向;
图像中边缘可以指向各个方向,Canny算法使用四个算子来检测图像中的水平、垂直和对角边缘。边缘检测的算子(如Roberts,Prewitt,Sobel等)返回水平Gx和垂直Gy方向的一阶导数值,由此便可以确定像素点的梯度G和方向
G为梯度强度,
下面以Sobel算子为例,描述如何计算梯度强度和方向:
Sobel算子x和y方向分别为:
其中Sx表示x方向的Sobel算子,用于检测y方向的边缘; Sy表示y方向的Sobel算子,用于检测x方向的边缘(边缘方向和梯度方向垂直)。在直角坐标系中,Sobel算子的方向如下图所示。
若图像中一个3x3的窗口为A,要计算梯度的像素点为e,则和Sobel算子进行卷积之后,像素点e在x和y方向的梯度值分别为:
其中*为卷积符号,sum表示矩阵中所有元素相加求和。根据公式(1)、(2)便可以计算出像素点e的梯度和方向。
-
- 使用Non-Maximum Suppression(非极大值抑制)消除边缘检测带来的杂散响应;
如果直接把梯度作为边缘的话,将得到一个粗边缘的图像,在图像边缘区域,其附近梯度值往往都很大,这不满足上面提到的准则(最小响应标准),我们希望得到定位准确的单像素的边缘,所以将每个像素点的梯度与其梯度方向上的相邻像素比较,如果不是极大值,将其置0,否则置为某一不大于255的数,非最大值抑制能帮助保留局部最大梯度而抑制所有其他梯度值。这意味着只保留了梯度变化中最锐利的位置,如下图:
点A在边缘上(在垂直方向上)。梯度方向与边缘垂直。B点和C点处于梯度方向。因此,点A,与点B和C进行比较,点A是否形成局部最大值。如果是这样,它被认为是边缘,否则,它被抑制(归零)。
-
- 使用Double-Threshold(双阈值)检测确定真实和潜在的边缘;
- 通过抑制鼓励的弱边缘最终完成边缘检测.
这个阶段决定哪些边缘是真正的边缘,哪些不是边缘。为此,我们需要两个阈值minVal和maxVal。强度梯度大于maxVal的任何边缘肯定是边缘,低于minVal的边缘肯定是非边缘,因此被丢弃。那些位于这两个阈值之间的点,则基于这些点是否与真正的边缘部分相连接如果它们连接到“真正边缘”像素,则它们被认为是边缘的一部分。否则,他们也被丢弃。看到下面的图片:
边缘A在maxVal之上,因此被视为“真正的边缘”。虽然边C低于maxVal,但它连接到边A,所以也被认为是有效边缘,我们得到了完整的曲线。但是边B虽然高于minVal,但它并没有连接到任何“真正的边缘”,因此被丢弃。因此,我们必须相应地选择minVal和maxVal以获得正确结果,这一点非常重要。
1.2 效果
2. 做Segment
2.1 方法
Segment的主要思想是,构建一个mask,这个mask包含主要的车道区域值均为1,其余为0,将这个mask与原frame进行叠加,就可以抠出主要的车道区域。
2.2 效果
可以看到,已经成功的抠出了车道线部分的图像。
3.做霍夫变换
3.1 Hough Transform原理
霍夫变换(Hough Transform)是图像处理中的一种特征提取技术,常用来在图像中提取直线和圆等几何形状,该过程在一个参数空间中通过计算累计结果的局部最大值得到一个符合该特征的集合作为霍夫变换的结果。
- 霍夫直线变换
霍夫直线变换,比如在笛卡尔坐标系中,变量(x,y),参数(m,b),有:y=mx+b,则在霍夫空间中,变量(m,b),参数(x,y),有b=xm+y,可以看出,霍夫空间变量与参数进行互换;于是有,在笛卡尔坐标系中的一条线,y=mx+b,对应在霍夫空间,就是一点(m,b)(可以经过无穷多直线);在笛卡尔坐标系中的一个点:(x,y)(对应无穷的m,b),对应在霍夫空间中就是一条直线。
直线可以分别用直角坐标系和极坐标系来表示:
那么经过某个点(x0,y0)的所有直线都可以用这个式子来表示:
也就是说,每一个
OpenCV中,有两个API可以用来进行霍夫直线变换
①cv2.HoughLines(edges,0.8,np.pi/180,90),参数1,要检测的二值图像(一般是阈值分割或边缘检测后的图像);参数2,是距离r的精度,值越大,考虑越多的线;参数3,是角度
②cv2.HoughLinesP(edges,0.8,np.pi/180,90,minLineLength=50, maxLineGap=10),是统计概率霍夫直线变换,前面的方法又称为标准霍夫变换,它会计算图像中的每一个点,计算量比较大,另外它得到的是整一条线(r和θ),并不知道原图中直线的端点。所以提出了统计概率霍夫直线变换(Probabilistic Hough Transform),是一种改进的霍夫变换;前面参数含义相同,minLineLength:最短长度阈值,比这个长度短的线会被排除;maxLineGap:同一直线两点之间的最大距离
4. 标定车道边界
4.1 基本方法
将从hough检测到的多条线平均成一条线表示车道的左边界, 一条线表示车道的右边界。基本思想很简单,就是先将霍夫变换的线段转换为一维信息,进行多项式拟合,在将得到的截距和斜率信息进行平均,在利用数值代换转换成cv坐标系的左边界线,和右边界线;其他的代码里有详细的注释,就不过多赘述。
4.2 效果
可以看到,车道中的标示线已经被很好的标出。
5. 可视化
最后的工作就是讲标定的车道边界在原始视频文件中输出,效果如下:
6.代码
#-*- coding: utf-8 -*-