Advertisement

基于MATLAB的车道线识别系统

阅读量:

MATLAB车道线识别****系统

function imgout = lanemarker(img)

global top bot

persistent tform

if isempty(tform)

movingPoints = [203 720; 585 460; 695 460 ; 1127 720];

fixedPoints = [320 720; 320 0; 960 0; 960 720];

tform = fitgeotrans(movingPoints,fixedPoints,'projective');

top = 220;

bot = 12;

end

topview = view2top(img,tform);

[flanel,flaner] = lanefinder(topview);

hpic = size(topview,1);

y = 1:hpic;

y = y';

xl = polyval(flanel,y);

xr = polyval(flaner,y);

dim = size(topview);

dim = [dim,3];

imref = imref2d(size(topview));

lanel = reshape([xl';y'],1,[]);

laner = [xr';y'];

laner = fliplr(laner);

laner = reshape(laner,1,[]);

xpic = zeros(dim,'uint8');

xpic = insertShape(xpic,'FilledPolygon',[lanel,laner],'Color',[0,255,0],'Opacity',0.3);

xpic = imwarp(xpic,tform.invert,'OutputView',imref);

img = imlincomb(1,img,1,xpic);

xpic = zeros(dim,'uint8');

xpic = insertShape(xpic,'Line',lanel,'LineWidth',20,'Color',[255,0,0],'Opacity',1);

xpic = insertShape(xpic,'Line',laner,'LineWidth',20,'Color',[255,0,0],'Opacity',1);

xpic = imwarp(xpic,tform.invert,'OutputView',imref);

imgout = imlincomb(1,img,1,xpic);

end

上面是主程序view2top函数是将图转换为俯视图的函数,就是由左图变成右边的图。view2top函数由很多函数来完成工作,下面做一些必要说明。

function topview = view2top(img,tform)

global top bot

th_sobelx = [35, 100];

th_sobely= [30, 255];

th_mag = [30, 255];

th_dir = [0.7, 1.3];

th_h = [10, 100];

th_s = [85, 255];

th_l = [0, 60];

gradient_comb = gradient_combine(img, th_sobelx, th_sobely, th_mag, th_dir);

hsl_comb = hsl_combine(img, th_h, th_s, th_l);

dim = size(img);

combined_result = zeros(dim(1:2));

combined_result = uint8(combined_result);

combined_result(top:end-bot,:,:) = comb_result(gradient_comb, hsl_comb);

% figure(1)

% imshow(combined_result)

imref = imref2d(size(combined_result));

topview = imwarp(combined_result,tform,'OutputView',imref);

% topview = topview(top:end-bot,:,:);

end

上面的函数实现了由道路图像变成车道线俯视图的过程,该函数首先将图片中的车辆线提出出来,gradient_combine和hsl_combine通过图像梯度和hsl色彩模式来提出可能的车道线comb_result来进一步优化结果。

梯度阈值提取的结果

function gradient_comb = gradient_combine(img, th_x, th_y, th_mag, th_dir)

global top bot

R = img(top:end-bot,:,:);

R = R(:,:,1);

dim = size(R);

sobelx = sobel_xy(R, 'x', th_x);

sobely = sobel_xy(R, 'y', th_y);

mag_img = mag_thresh(R, th_mag);

dir_img = dir_thresh(R, th_dir);

gradient_comb = zeros(dim,'uint8');

gradient_comb(((sobelx > 0) & (mag_img > 0) & (dir_img > 0)) ...

| ((sobelx > 0) & (sobely > 0))) = uint8(255);

end

上述函数实现了梯度阈值的过程,sobelx 给出水平阈值后的结果,sobely求出垂直梯度

阈值后的结果,mag_thresh给出梯度阈值后的结果,dir_img给出梯度方向阈值后的结果。下面给出了其中的各个结果。注意上面的阈值过程只作用于红色通道。

function hsl_comb = hsl_combine(img, th_h, th_s, th_l)

global top bot

hsl = img(top:end-bot,:,:);

hsl = rgb2hsl(hsl);

h = hsl(:,:,1);

s = hsl(:,:,2);

l = hsl(:,:,3);

dim = size(h);

h_th = ch_thresh(h, th_h);

s_th = ch_thresh(s, th_s);

l_th = ch_thresh(l, th_l);

hsl_comb = zeros(dim,'uint8');

hsl_comb(((s_th > 0) & (l_th == 0)) ...

| ((s_th == 0) & (h_th > 0) & (l_th >0))) = uint8(255);

end

上面一段函数实现了hsl色彩通道阈值提取的过程,其结果如下图所示。色彩空间中的HSL、HSV、HSB有什么区别?提到了什么是hsl色彩空间,matlab只提供了转hsv的方法没有提供rgb转hsl色彩空间的方法,该函数在下方已经提供。

hsl阈值提出的结果

function result = comb_result(grad, hsl)

dim = size(grad);

result = zeros(dim,'uint8');

result(grad>0) = uint8(100);

result(hsl>0) = uint8(255);

end

上面的函数将两种结果进行整合,得出下面的结果。最后将下图做透视变形就得出最初提到的俯视图。

得到俯视图就可以利用滑窗拟合得到左右车道线的两次多项式表示结果。

function [flanel,flaner] = lanefinder(topview)

persistent imgcounter avelanel avelaner flag

hpic = size(topview,1);

wpic = size(topview,2);

if isempty(imgcounter)

imgcounter = 0;

flag = 0;

avelanel = zeros(hpic,10);

avelaner = zeros(hpic,10);

end

hist = sum(topview);

midx = floor(wpic/2);

[~,leftx] = max(hist(1:midx));

[~,rightx] = max(hist(midx+1:end));

rightx = rightx+midx;

num = 9;

hwin = floor(hpic/num);

wwinhalf = 56;

minpix = 50;

[rowy,colx] = find(topview);

leftlane = [];

rightlane = [];

for i = num:-1:1

win_high = hwin*i;

win_low = hwin*(i-1);

vcount = rowy <= win_high & rowy > win_low;

lcount = vcount & (colx <= leftx+wwinhalf & colx > leftx-wwinhalf);

lpix = sum(lcount);

rcount = vcount & (colx <= rightx+wwinhalf & colx > rightx-wwinhalf);

rpix = sum(rcount);

if lpix > minpix

leftx = mean(colx(lcount));

leftx = round(leftx);

end

if rpix > minpix

rightx = mean(colx(rcount));

rightx = round(rightx);

end

leftlane = [leftlane; colx(lcount),rowy(lcount)];

rightlane = [rightlane; colx(rcount),rowy(rcount)];

end

flanel = polyfit(leftlane(:,2),leftlane(:,1),2);

flaner = polyfit(rightlane(:,2),rightlane(:,1),2);

t = 1:hpic;

t = t';

if flag == 0

imgcounter = imgcounter+1;

avelanel(:,imgcounter) = polyval(flanel,t);

avelaner(:,imgcounter) = polyval(flaner,t);

if imgcounter == 10

flag = 1;

end

else

avelanel = [avelanel(:,2:end),polyval(flanel,t)];

avelaner = [avelaner(:,2:end),polyval(flaner,t)];

flanel = polyfit(t,mean(avelanel,2),2);

flaner = polyfit(t,mean(avelaner,2),2);

end

% y = 1:hpic;

% xl = flanel(y);

% xr = flaner(y);

% imshow(topview)

% hold on

% plot(xl,y);

% plot(xr,y);

% hold off

end

上面的函数完成了二次多项式拟合的结果,其主要用于视频的处理,所以不仅仅利用一张图片来得到车道线的结果,而是利用了十帧图像的平均结果。下图是得出的左右车道线结果。

再将车辆线从俯视图反透视变形和原始图像叠加如下,最后给出一个视频结果。

function hsl = rgb2hsl(rgb)

dim = size(rgb);

drgb = reshape(double(rgb)/255,[],3);%change range to 0-1

mx = max(drgb,[],2);%max of the 3 colors

mn = min(drgb,[],2);%min of the 3 colors

L = (mx+mn)/2;%luminance is half of max value + min value

S = zeros(size(L));

% this set of matrix operations can probably be done as an addition...

zeroidx = (mx==mn);

S(zeroidx) = 0;

lowlidx=L <= 0.5;

calc = (mx-mn)./(mx+mn);

idx = lowlidx & (~ zeroidx);

S(idx) = calc(idx);

hilidx = L > 0.5;

calc = (mx-mn)./(2-(mx+mn));

idx = hilidx & (~ zeroidx);

S(idx) = calc(idx);

hsv = rgb2hsv(rgb);

hsv = reshape(hsv,[],3);

H = hsv(:,1);

hsl = reshape([H, S, L],dim);

hsl = uint8(hsl*255);

end

% Sobel算子在Matlab默认为 $\left\lbrack \begin{array}{ccc}1 & 2 & 1\ 0 & 0 & 0\ -1

% & -2 & -1\end{array}\right\rbrack$,强调水平方向的边缘

function binary_output = sobel_xy(img, orient, thresh)

h = fspecial('sobel'); % 垂直方向sobel算子,强调水平边

dim = size(img);

timg = double(img);

if orient == 'x'

abs_sobel = abs(imfilter(timg,fliplr(h')));

else

abs_sobel = abs(imfilter(timg,h));

end

scale_factor = max(abs_sobel(:)) / 255;

timg = reshape(abs_sobel(:) / scale_factor,dim);

scaled_sobel = uint8(timg);

binary_output = zeros(dim,'uint8');

binary_output((scaled_sobel > thresh(1)) & (scaled_sobel <= thresh(2))) = uint8(255);

end

function binary_output = mag_thresh(img, thresh)

timg = double(img);

dim = size(img);

h = fspecial('sobel');

sobelx = imfilter(timg,fliplr(h'));

sobely = imfilter(timg,h);

gradmag = sqrt(sobelx.^2 + sobely.^2);

scale_factor = max(gradmag(:)) / 255;

scaled_mag = reshape(gradmag(:) / scale_factor,dim);

binary_output = zeros(dim,'uint8');

binary_output((scaled_mag > thresh(1)) & (scaled_mag <= thresh(2))) = uint8(255);

end

function kernel = sobel_kernel(dim)

half = floor(dim/2);

t = [half:1:dim-2, dim-1, dim-2:-1:half];

sobel = zeros(dim);

for i = 1:half

sobel(i,:) = t-i+1;

end

kernel = sobel-flipud(sobel);

end

function binary_output = dir_thresh(img, thresh)

timg = double(img);

dim = size(img);

h = sobel_kernel(15);

sobelx = imfilter(timg,h');

sobely = imfilter(timg,h);

absgraddir = atan(abs(sobely) ./ abs(sobelx));

binary_output = zeros(dim,'uint8');

binary_output((absgraddir > thresh(1)) & (absgraddir <= thresh(2))) = uint8(255);

end

function binary_output = ch_thresh(ch, thresh)

dim = size(ch);

binary_output = zeros(dim,'uint8');

binary_output((ch > thresh(1)) & (ch <= thresh(2))) = uint8(255);

end

function result = comb_result(grad, hsl)

dim = size(grad);

result = zeros(dim,'uint8');

result(grad>0) = uint8(100);

result(hsl>0) = uint8(255);

end

全部评论 (0)

还没有任何评论哟~