MATLAB基于视觉实现车道线检测

1 概述

在自动驾驶中,毫米波雷达、激光雷达以及摄像头都可用于环境感知,但受限于对图形的识别能力,对于车道及其分类通常由摄像头实现(不考虑高精地图和定位)。以下结合MATLAB官方实例介绍利用视觉感知和自动驾驶工具箱基于视觉实现车道线识别和分类功能。

2 实现

2.1 摄像头参数初始化

摄像头参数包括内参和外参,这里主要构造一个单目相机的对象,代码如下:

% 内参
focalLength    = [309.4362, 344.2161]; % [fx, fy] in pixel units
principalPoint = [318.9034, 257.5352]; % [cx, cy] optical center in pixel coordinates
imageSize      = [480, 640];           % [nrows, mcols]
camIntrinsics = cameraIntrinsics(focalLength, principalPoint, imageSize);

% 外参
height = 2.1798;    % mounting height in meters from the ground
pitch  = 14;        % pitch of the camera in degrees

% 构造
sensor = monoCamera(camIntrinsics, height, 'Pitch', pitch);

以上过程完成了一个单目相机的实例化,参数来自于标定(不在本文范围内),参数的含义这里不再详述,具体的原理与例程可以参考博文《相机内参坐标系及其在MATLAB 中的表示》《单目相机(Mono camera)在MATLAB中的表示与实例》

另外这里默认车辆坐标系采用“右-前-天坐标(RFU)”坐标系,车辆坐标系的原点选在了摄像头所在位置的正下方的地面上。

2.2 导入视频帧

将以上摄像头拍摄到的视频帧导入到MATLAB的工作空间,代码如下:

% 导入视频
videoName = 'caltech_cordova1.avi';
videoReader = VideoReader(videoName);

% 读取感兴趣的视频帧
timeStamp = 0.06667;                   % time from the beginning of the video
videoReader.CurrentTime = timeStamp;   % point to the chosen frame
frame = readFrame(videoReader); % read frame at timeStamp seconds
imshow(frame) % display frame

在这里插入图片描述

2.3 创建鸟瞰图(birdsEyeView)

创建鸟瞰图,代码如下:

% 在车辆坐标系下定义转换成BirdsEyeView的区域,前方3-30米,左右各6米,配置鸟瞰图大小属性
distAheadOfSensor = 30; % in meters, as previously specified in monoCamera height input
spaceToOneSide    = 6;  % all other distance quantities are also in meters
bottomOffset      = 3;
outView   = [bottomOffset, distAheadOfSensor, -spaceToOneSide, spaceToOneSide]; % [xmin, xmax, ymin, ymax]
imageSize = [NaN, 250]; % output image width in pixels; height is chosen automatically to preserve units per pixel ratio
birdsEyeConfig = birdsEyeView(sensor, outView, imageSize);

% 转换为鸟瞰图
birdsEyeImage = transformImage(birdsEyeConfig, frame);
figure
imshow(birdsEyeImage)

鸟瞰图:
在这里插入图片描述

创建鸟瞰图的好处是图像比例一致,车道线宽度也是基本一致的,可以简化车道线识别的计算处理,当然创建鸟瞰图本身这个过程会牺牲一定的效率。

注意,以上鸟瞰图的创建没有考虑图形畸变,在鸟瞰图构造类里边是可以设置相关参数的。

2.4 车道线位置

2.4.1 实现过程

车道线识别的原理主要是基于车道线与车道之间颜色的差异,代码如下:

% 转换为灰度图
birdsEyeImage = rgb2gray(birdsEyeImage);
figure(1)
imshow(birdsEyeImage)

% 检测车道线
laneSensitivity = 0.25;
birdsEyeViewBW = segmentLaneMarkerRidge(birdsEyeImage, birdsEyeConfig, approxLaneMarkerWidthVehicle,...
    'ROI', vehicleROI, 'Sensitivity', laneSensitivity);
figure(2)
imshow(birdsEyeViewBW)

灰度图和黑白图:
灰度图  黑白图

这里主要用到了两个关键的函数:

  1. rgb2gray:转换为灰度图
  2. segmentLaneMarkerRidge

以下一一介绍。

2.4.2 rgb2gray

I = rgb2gray(RGB) 将真彩色图像 RGB 转换为灰度图像 I。rgb2gray 函数通过消除色调和饱和度信息,同时保留亮度,来将 RGB 图像转换为灰度图。

rgb2gray 通过计算 R、G 和 B 分量的加权和,将 RGB 值转换为灰度值:

0.2989 * R + 0.5870 * G + 0.1140 * B

这些权重与 rgb2ntsc 函数用于计算 Y 分量的权重相同。

在舍入到小数点后 3 位之后,rgb2gray 中用来计算灰度值的系数与 Rec.ITU-R BT.601-7 中用来计算亮度 (E’y) 的系数相同。

Rec.ITU-R BT.601-7 使用以下公式计算 E’y:

0.299 * R + 0.587 * G + 0.114 * B

以上是MATLAB帮助的官方解释,计算方法比较简单,如果不熟悉原理,这个函数可以看作黑箱即可,总之是可以将彩色图像中的RGB分量转换为灰度图中的灰度值(图像的表示有RGB、YUV、YIQ、灰度图、二值图等等)。

2.4.3 segmentLaneMarkerRidge

该函数的是将输入的灰度图转换为二值图,也就是黑白图,这样我们就可以进一步方便车道线的识别,转换前需要设置好ROI、敏感度系数Sensitivity值以及车道线的理想宽度approxMarkerWidth 。该函数在MATLAB中是可以直接打开的,我们透过代码可以看到其关键步骤如下:

function birdsEyeBW = segmentLaneMarkerRidge(varargin) %#codegen
1. 参数解析
[birdsEyeImage, ROI, T, tau] = parseInputs(varargin{:});
2. 车道线特征强化
L = emphasizeLaneFeatures(birdsEyeImage, tau);
3. 阈值设置与二值化图像
BW = thresholdLaneFeatureImage(L, ROI, T);
birdsEyeBW = cleanupBinaryMask(BW, ROI);
end

这里的重点是第二步:强化!方法实现如下:

function L = emphasizeLaneFeatures(I, tau)
Ipad = padarray(I, [0 double(tau)+1], 'replicate');
Ileft  = single(Ipad(:,1:end-2*(tau+1)));
Iright = single(Ipad(:,1+2*(tau+1):end));
L = 2*single(I) - (Ileft+Iright) - (abs(Ileft - Iright));
L = imnormalize(L);
end

该函数实际参考了论文《Road environment modeling using robust perspective analysis and recursive Bayesian segmentation》,论文中的形式如下:
在这里插入图片描述
实际就是通过以上公式,使得非车道线区域部分对应的图形列接近于0,而车道线部分则有差值,从而更方便归一化后通过阈值来得到二值化图。感兴趣的可以进一步查看代码和论文。

2.5 车道线建模

通过以上过程获取二值化的车道线图形,为了减少数据量、计算方便、融合等需求,通常需要将二值化的图像进一步将车道线用多项式拟合表示,这里采用了二次曲线拟合。过程如下:

% 将像素坐标系下车道线点转化到车辆坐标系
[imageX, imageY] = find(birdsEyeViewBW);
xyBoundaryPoints = imageToVehicle(birdsEyeConfig, [imageY, imageX]);

% 拟合出最多两条车道线的二次曲线
maxLanes      = 2; % look for maximum of two lane markers
boundaryWidth = 3*approxLaneMarkerWidthVehicle; % expand boundary width
[boundaries, boundaryPoints] = findParabolicLaneBoundaries(xyBoundaryPoints,boundaryWidth, ...
    'MaxNumBoundaries', maxLanes, 'validateBoundaryFcn', @validateBoundaryFcn);

得到两条曲线的拟合与类型识别结果如下:
在这里插入图片描述
在这里插入图片描述
可以看出,识别结果不但给出了车道线的二次曲线的拟合系数,还给出了车道线类型、范围、强度等参数。车道线的二次曲线拟合采用的是RANSAC算法(后续待细述)。

最后,将拟合结果的曲线绘制到鸟瞰图和原图中,结果如下:

在这里插入图片描述
这里我们也可以发现点小问题:图片中,实际是双黄线的情况下,程序识别成了虚线。这里程序没有使用findParabolicLaneBoundaries的结果,反而自己写了一个classifyLaneTypes的函数导致该图片的左车道线识别类型错误,但并不代表整体识别率低。因此,这里作为一个小疑点放一边,待后续有时间进一步分析。

3 总结

至此,车道线识别与分类的介绍到此结束,基本上将前述相关博文都串了起来,包括坐标系及其转换、相机内外参模型、鸟瞰图、车道线识别与分类等。

参考

1 MATLAB官网——《Visual Perception Using Monocular Camera》
2 MATLAB官网——《findParabolicLaneBoundaries》
3 《相机内参坐标系及其在MATLAB 中的表示》
4 《单目相机(Mono camera)在MATLAB中的表示与实例》
5 《Road environment modeling using robust perspective analysis and recursive Bayesian segmentation》
6 《自车坐标系下的物体相对和绝对位置和速度计算》

发布了45 篇原创文章 · 获赞 102 · 访问量 25万+

猜你喜欢

转载自blog.csdn.net/zhoucoolqi/article/details/105447397