目錄
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)
灰度圖和黑白圖:
這裏主要用到了兩個關鍵的函數:
- rgb2gray:轉換爲灰度圖
- 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 《自車座標系下的物體相對和絕對位置和速度計算》