目录
实验步骤与过程
1. 路沿检测方法设计
2. 路沿检测方法实现
2.1 视频图像提取
2.2 图像预处理
2.3 兴趣区域提取
2.4 边缘检测
2.5 Hough变换
2.6 线条过滤与图像输出
3. 路沿检测结果展示
4. 其他路沿检测方法
实验结论或体会
实验内容:针对给定的视频,利用图像处理基本方法实现道路路沿的检测;
提示:可利用Hough变换进行线检测,融合路沿的结构信息实现路沿边界定位(图中红色的点位置)。
实验步骤与过程
1. 路沿检测方法设计
图1 路沿检测方法思路图 |
对于路沿检测,整体思路如上所示。首先利用opencv提取出视频中的每一帧,然后对每一帧图像进行预处理。此处的预处理包含了灰度变换、图像二值化、均值滤波、再次二值化等,其目的主要在于将图像处理成路沿较容易被识别出来的状态。对图像进行预处理后需要进行兴趣区域提取。此处的兴趣区域提取,我首先根据图像的几何信息规定了一个大概的范围,然后再通过Hough变换找出路基与路标线的区域最后将此区域作为最后的兴趣区域。最后再进行常规的边缘检测与hough变换,并对结果进行过滤即可较好地检测出路沿。
2. 路沿检测方法实现
下面将根据上面的路沿检测方法的设计进行具体的实现。
2.1 视频图像提取
- 由视频属性说明
由于视频是由一帧一帧的图像所组成的,所以对一个视频做路沿检测相当于对每一帧图像都做路沿检测。一般每秒中视频有24、25、30、60帧图像,帧数越多视频越顺滑但是处理的数据量也越大。在本次实验提供的视频中,根据属性查看可知其帧数为24帧/s,其属性如下图图2所示。
图2 视频属性 |
- opencv帧数提取
在opencv中提供了一个模块用于提取视频中的每一帧,这个模块叫做Videocapture,其拥有一个必要参数——视频的地址。在建立videocapture对象后,调用其read函数其即可以以迭代器的方式返回每一帧图像。下面为videocapture的一个使用案例。
- import cv2
- # 打开视频文件
- cap = cv2.VideoCapture('./实验2实验数据/01.avi')
- # 逐帧读取视频
- while True:
- ret, frame = cap.read()
- if not ret:
- break
- # 处理当前帧
- cv2.imshow('Frame', frame)
- cv2.waitKey(1)
- # 释放资源
- cap.release()
- cv2.destroyAllWindows()
2.2 图像预处理
- 灰度变换
所提供的视频均为拥有RGB三通道的彩色视频,而在检测边缘中或许只需要一个通道即灰度图即可。当通道变多时颜色信息或许作用并不大,而且可能会影响边缘的判别。同时将图像变成灰度图还可以加快处理速度,节省计算资源。因此此处将图像转变成灰度图[1]。此处可以使用下面公式进行灰度变换:
Gray = R*0.299 + G*0.587 + B*0.114
同时也可利用opencv自带的函数进行变换,其原理一致,案例代码如下。
- gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
变换前后结果如下面两图所示,可以看到去除颜色后更容易分辨道路的边界而去除周围无用信息的影响。
图3 灰度变换前 | 图4 灰度变换后 |
- 二值化
从图像中进行观察可以清晰地看到路沿有一个重要的特征就是拥有阴影与明显地轮廓特征(表现为颜色微小地颜色变化)。因此可以利用以上的特征对图像进行处理,首先至少使得人眼可明显观察得到粗略的路沿区域。那么想到的方法是对图像进行二值化,下面进行具体的试验。首先将阈值设置为一半即127可以看到结果如图x所示,而将阈值设置为200时其结果如图x所示,可以看到前者可以清晰看出近处的路沿,而后者可以看到整条道路的路沿,但是十分粗糙,于是调整阈值以获得最佳值。
图5 二值化阈值为127时的图像 | 图6 二值化阈值为200时的图像 |
从120至200逐一调整后,发现阈值为185时较佳,其结果如下所示。
图7 阈值为185时的二值化图像 |
可以清晰看出路沿的轮廓,但是其四周却存在部分阴影,因此可以对其进行多次均值滤波后再次二值化去除,其步骤见均值二值化处理。
- 均值滤波二值化
在前面的图中可以清晰看出路沿的轮廓,但是轮廓周边却存在一些干扰的黑线,如下图所示。
图8 轮廓周边的黑线 |
因此可以尝试对二值化后的图像进行均值滤波,对这些黑边的灰度值进行弱化,然后再进行一次二值化即可去掉黑边。
- 对整幅图像进行均值二值化处理,并将参数调整至最佳其结果如下所示、
图9 均值二值化处理 |
可以发现四周的黑边去除了,但是同时远处的轮廓线也没了.因此对整张图进行均值滤波后再二值化会存在问题.于是考虑到在远处黑边的影响比较小,而且远处的宽容度无需太高,所以应该只要对右下角区域进行处理.
2. 对右下角区域进行处理,首先提取处ROI区域,其代码如下
- # 获取图像的行数和列数
- rows, cols = img_binary.shape[:2]
- # 指定右下角区域的起始和结束位置
- x_start, y_start = int(cols * 0.5), int(rows * 0.5)
- x_end, y_end = cols, rows
- # 提取右下角区域
- roi = gray[y_start:y_end, x_start:x_end]
然后对其进行均值滤波,并将roi区域幅值到整张图中。最后再次进行二值化操作,此时阈值设置为160。
- # 选定右小角区域做均值滤波
- blur = cv2.blur(roi, (5, 5))
- # 将滤波后的区域复制回原图像的右下角
- img_binary[y_start:y_end, x_start:x_end] = blur
- # 再次进行二值化操作
- _, img_binary = cv2.threshold(img_binary, 170, 255, cv2.THRESH_BINARY)
其结果如下所示。
图10 ROI区域均值滤波与二值化处理结果图 |
可以发现近处的黑边已被去除,而远方的轮廓线仍清晰可见。
2.3 兴趣区域提取
- 粗略提取
对上面的区域进行预处理后下一步就是提取兴趣区域,也就是路沿所在的区域,以排除其他区域的影响。从视频中可以看出路沿是在我们右手边的,而在其他行驶条件中,我国的道路一般也都是在右边.因此首先可以截取左向数起2/5区域作为兴趣区域。而再仔细观察可以发现路边与左边2/5处边界线成60度范围,因此可以截取如下的区域作为兴趣区。
图11 兴趣区域示意图 |
兴趣区域提取的代码如下所示,
- def get_roi(img):
- # 获取图像大小
- h, w = img.shape[:2]
- # 计算多边形顶点
- x1 = int(w / 5 * 2)
- x2 = int(w / 5 * 2)
- x3 = int(w / 5 * 2 + h*math.tan(math.pi/3))
- y1 = 50
- y2 = int(h)
- y3 = h
- pts = np.array([(x2, y1), (x3, y2), (x3, y3), (x1, y3), (x1, y2), (x2, y1)])
- mask = np.zeros((rows, cols), dtype=np.uint8)
- # 填充多边形
- cv2.fillPoly(mask, [pts], (255, 255, 255))
- roi = cv2.bitwise_and(img, img, mask=mask)
- return roi
- 精确提取
在除此提取后发现左右两边的区域或许会产生影响,因此下一步消除左右两边的边界。其思路如下图所示。主要的目的是在整个画面中只留下路沿而其他标志线的边界均去除,其实现方法在于先提取标志线与路基边缘区域,然后将此区域变成兴趣区进行截取,然后将区域外的颜色均变为白色。那么最后结果就只剩下路沿线。
图12 精确提取思路图 |
在进行均值滤波与二值化后,其结果如下所示。可以看到中间的路沿线已经去除,方便进行边缘提取与霍夫变换。
图13 去除中间路沿线 |
在得到上面的图像后进行边缘提取,最后使用掩膜进行变换得到下图。
图14 提取后的效果图 |
可以看到标志线与路基区域已经精确地截取得到。从图中可以看出可以形成三条边沿线,而我们所需要的仅仅是中间的。因此将掩膜区域外的图像变为白色,其结果如下。
图15 保留轮廓线 |
可以看到效果并不好,因此尝试压缩范围,以最后得到中间的黑线,通过改变截距的大小来进行,其代码如下。
- def adjust_line_intercept(point1, point2, c):
- x1, y1 = point1
- x2, y2 = point2
- k = (y2 - y1) / (x2 - x1)
- b = y1 - k * x1
- b += c
- y1_new = k * x1 + b
- y2_new = k * x2 + b
- return [(int(x1), int(y1_new)), (int(x2), int(y2_new))]
然而却发现结果并不佳,因为随着图像的变化,较难找到最佳的截距参数.所以区域限制的方法无太大作用,最后此方法未用到最终结果中。
2.4 边缘检测
在上面的过程中其实一直有涉及到边缘检测的部分,,的边缘检测我选择了canny边缘检测。它是一种经典的边缘检测算法。通过高斯模糊、计算梯度、非极大值抑制、双阈值检测、边缘连接几个步骤对边缘进行检测。在此次实验中,我参考了高等人[1]的方法设置了高低阈值,即使用光照强度参数 BL的0.4倍作为低阈值,1.2倍作为高阈值。最后还使用cv2.bitwise_and函数来将边缘图像edges和掩码mask进行按位与运算,从而将边缘检测结果限制在指定的区域内。其代码如下。
- bl = cv2.mean(img)[0]
- canny_low = int(0.4 * bl)
- canny_high = int(1.2 * bl)
- edges = cv2.Canny(img, canny_low, canny_high)
- edges = cv2.bitwise_and(edges, edges, mask=cv2.inRange(frame, (0, 0, 0), (200, 200, 200)))
2.5 Hough变换
霍夫变换是一种经典的图像处理算法,一般它会配合边缘检测以提取出边缘的的坐标信息形成直线或圆。在此处的路沿检测中,路沿一般是直线,所以主要使用线条的hough变换即可。为了得到更好的效果,我进行了多次调整参数。下表为调整threshold的结果统计,默认参数为threshold=100,minLineLength=100, maxLineGap=100。
表1 threshold结果统计
threshold | 结果说明 | 显示效果 |
150 | 边界线条较稀疏,路沿线可能无法显示 | |
100 | 边界线条可以正常显示 | |
50 | 线条数量多较为稠密 |
下表为改变minLineLength最短线条长度的结果。
表2 minLineLength结果统计
threshold | 结果说明 | 显示效果 |
150 | 边界线条可以正常显示 |
|
100 | 边界线条可以正常显示 | |
50 | 线条变短 |
改变maxLineGap最大线条间隔的结果,三者的改变对结果影响不大,因此不展示统计表。因此最后参数均选择为100。
2.6 线条过滤与图像输出
上面的结果中,包含了路沿的边界线,但是同时也含有两侧路基边线与路标线。因此最终输出应该进行过滤,在前面的兴趣区域提取中曾尝试过去除影响但是结果并不佳。同时在hough变换中,会存在某些异常线条,这些线条的斜率往往与路沿的差别很大。于是尝试使用斜率筛选与截距排序来对结果进行过滤。
- 斜率平均值
统计视频中线条的斜率平均值,将每个视频中线条的斜率累加然后除以线条总数据,以下为各视频线条斜率的统计结果。
表3 各视频路沿斜率统计
视频名称 | 斜率平均值 |
01.avi | 2.48 |
02.avi | 3.19 |
03.avi | 1.56 |
三者平均值为 ,在此均值范围内加减其百分之50%作为范围,即1.21~3.62。修改前后如下图所示,可以看到异常的线条给去除了。
图16 斜率限定前 | 图17 斜率限定后 |
- 路沿截距
目前所能看到的图像虽然包含了路沿线,但是也包含了其他的边界线,因此需要过滤。人工统计三个视频中路沿线截距,其结果如下表所示。
表4 各视频路沿截距统计
视频名称 | 截距范围 |
01.avi | 550-600 |
02.avi | 550-700 |
03.avi | 400-500 |
因此根据以上的条件进行过滤。以02.avi为例,其变化前后如下图所示,可以看到改变前是很多条线的,而处理后只有路沿存在线。然而这种做法却存在太大的主观性,需要根据特定的视频进行定制无法通用,存在极大的不便性。
图 18截距限定前 | 图 19截距限定后 |
3. 路沿检测结果展示
- 01.avi
图20 01.avi最终结果截图 |
- 02.avi
图21 02.avi最终结果截图 |
- 03.avi
图22 03.avi最终结果截图 |
从上面的图中可以看出,其实对于此次实验的路沿检测基本是可以完成的,但是细节上的内容还可以更进一步地完善。比如再进一步自适应兴趣区域,自动识别路沿斜率范围等。
4. 其他路沿检测方法
在查阅文献时,发现了还有很多针对路沿检测的方法,这些方法主要分为两大类。第一类大多出现在10年前,主要是利用hough变换、canny边缘检测等的传统方法来对路沿进行检测;第二类则是使用深度学习的方法对对路沿进行检测。
- 传统方法介绍
对于第传统方法,其研究主要集中在10年前,如杨[2]等人提出了一种基于边缘的道路检测算法,采用颜色和方差规则消除非道路边缘的干扰,通过Hough变换确定道路边界的位置,同时通过限定感兴趣区域,进一步提高算法效率。高[1]等人提出了一种基于Canny算子和Hough变换的路缘识别和距离测量算法,能够实时准确地检测不同类型的路缘并进行距离测量。徐[3]等人提出了一种基于直线模型的道路识别算法,采用自然边界作为道路识别的依据,可以应用在有或没有车道线的道路环境中。刘[4]等人提出了一种基于三维道路模型的道路检测和跟踪算法,利用道路标志线的颜色突变来检测道路的边界线,同时利用卡尔曼滤波来进行跟踪分析。Gao[5]等人提出了一种双阈值方法获取道路的二值图像,并采用自适应Hough变换和SUSAN算法来获取道路边界。郭[6]等人采用自适应分离、模糊C均值和模糊规则来进行道路的识别,同时采用Canny算子得到良好的车道线检测效果,应对光照变化的情况。
- 深度学习方法介绍
以上传统的这些方法大多都是在深度学习受限于计算机性能无法得到较好发展的年代发表的,这些算法都拥有较好的性能无需太多的计算资源。而如今随着深度学习的火热目前路沿检测也拥有很多的神经网络模型。下面介绍三种关于路沿检测的模型。
1. SCNN
SCNN是一种基于卷积神经网络的语义分割模型,它使用了空洞卷积来增加感受野,以便能够更好地捕捉图像中的长距离信息。为了能够处理不同尺度的图像,SCNN使用了下采样和上采样的操作。其中,下采样用于降低特征图的分辨率,以便能够在更大的感受野范围内进行信息提取。在网络结构上,SCNN采用了一种U-Net结构,在特征提取和语义分割之间添加了一个对称的上采样模块,以便能够恢复原始图像的尺寸。它还使用了交叉熵损失函数来优化网络参数,同时还引入了一些额外的约束条件,如边界损失和平滑损失,以提高模型的鲁棒性和准确性。其效果图如下所示。
|
图23 SCNN效果图 转载于https://github.com/XingangPan/SCNN |
2. LaneNet
LaneNet是一种用于车道线检测的深度学习模型,可以实现实时、高精度的车道线检测和分割。LaneNet模型主要由两个部分组成:Encoder网络和Decoder网络。Encoder网络是一个卷积神经网络(CNN),用于提取输入图像的特征。Decoder网络由两个分支组成,一个分支用于车道线二值化分割,另一个分支用于车道线实例分割。LaneNet通过将分割和实例分割任务组合在一起,可以同时检测和分割多条车道线,且可以区分同一车道线上的不同部分。LaneNet的优点在于在不同光照、天气等情况下具有较好的鲁棒性和准确性;能够处理复杂的车道线形状和多车道情况;模型参数相对较小,可以在嵌入式设备上实现实时车道线检测。此模型的结构图如下所示。
|
图24 LaneNet结构图 转载于https://github.com/amusi/awesome-lane-detection |
3. VPGNet
vpgnet在2017年的CVF会议上提出的,它使用消失点作为特征值来引导对路沿线与车道线的检测。它将消失点和车道线的位置和宽度作为输入,使用卷积神经网络对图像进行特征提取和车道线检测。其效果图如下:
|
图25 VPGNet效果图 转载于https://github.com/SeokjuLee/VPGNet |
vpgnet主要包含三个部分:车道检测分支、路标检测分支和消失点回归分支。在训练过程中,网络同时学习车道和路标的位置和类别信息以及消失点的位置信息,最终通过单次前向传递预测车道和路标的位置和类别,以及消失点的位置。此模型在不良天气条件下进行了有效的实现,其具有高精度和鲁棒性,且实时性较高。
参考文献
[1]高灿, 曾杨, 郑庆华. 基于机器视觉的路缘识别及距离测量方法研究[J]. 建设机械技术与管理, 2014 (10): 125-130.
[2]杨文杰, 胡明昊, 杨静宇. 一种快速的基于边缘的道路检测算法[J]. 计算机科学, 2006, 33(5):257-260.
[3]徐友春, 王荣本, 李克强,等. 一种基于直线模型的道路识别算法研究[J]. 中国图象图形学报:A辑, 2004, 9(7):7.
[4]刘富强, 田敏, 胡振程. 智能汽车中基于视觉的道路检测与跟踪算法[J]. 同济大学学报:自然科学版, 2007, 35(11):7.
[5]Dezhi Gao,Wei Li,Jianmin Duan,etc. A Practical Method of Road Detection for Intelligent Vehicle[C]. In:Proceedings of the IEEE International Conference on Automation and Logistics,Beijing,China,2009:980-985
[6]Jyungguo Wang,Chengjian Lin,Shy i m i ng Chen. Applying Fuzzy Method to Vision-Based Lane Detection and Departure Warning System[J]. Expert Systems with Applications,2010,37:113-126.
[7]郭春钊,山部尚孝,三田诚一. 基于立体视觉平面单应性 的智能车辆可行驶道路边界检测[J]. 自动化学报,2013, 39(4):371-380
[8]Pan, X. SCNN [Source code]. v1.0. Retrieved from https://github.com/XingangPan/SCNN
[9]MaybeShewill-CV. (2018). lanenet-lane-detection [Source code]. GitHub. https://github.com/MaybeShewill-CV/lanenet-lane-detection
[10]Lee, Seokju, et al. "VPGNet: Vanishing Point Guided Network for Lane and Road Marking Detection and Recognition." IEEE Transactions on Image Processing 28.12 (2019): 6034-6046.
[11]https://github.com/amusi/awesome-lane-detection
[12]https://blog.csdn.net/weixin_51426083/article/details/127812799
实验结论或体会
在本次的实验中,我使用了灰度变换、二值化、canny边缘检测以及hough变换等多种方法对视频的每一帧进行了处理,最后成功地对三个视频的路沿线进行了识别。虽然在整个视频中存在某些帧无法正常识别,以及线条偏离,但是大部分的视频帧都能成功识别出路沿线。对于视频的处理以及方法的调用,基本上使用的都是python的opencv库,整个实验下来我对opencv的一些函数与使用方法有了更深入地了解。
在开始实验前,我搜寻了很多关于路沿检测的文献,了解了很多传统的处理方法以及近5年来最新的路沿检测模型。在实验过程中,我并不是完全模仿前人的工作,我还创新性地提出了我自己的想法并得以实现。我认为在此次的实验中的创新点在于多次使用二值化来放大路沿特征与兴趣区域以实现对路沿检测。总而言之,此次的实验是对课上学到的知识地很好一次实践,让我对理论知识拥有更好地了解,受益无穷。