车道保持中车道线识别

发布于:2025-03-24 ⋅ 阅读:(23) ⋅ 点赞:(0)

需要让小车保持车道行驶,首先需要进行车道线识别。

也可参看论文(上传到资源里):自动驾驶汽车车道检测与预测的技术解析-基于图像处理和Hough变换的方法

1 车道识别流程

想进行车道线识别,并且希望在图像中选择一个特定的区域进行处理(例如只处理道路区域),可以通过以下步骤对代码进行修改。我们将使用 ROI(Region of Interest)来限制处理范围,并优化车道线检测的逻辑。

具体步骤:

  1. ROI(Region of Interest):

    • 使用 roi 变量定义感兴趣区域,格式为 [x, y, width, height]

    • 通过 roiFrame = frame(roi(2):roi(2)+roi(4), roi(1):roi(1)+roi(3), :) 提取 ROI 区域。

  1. 高斯滤波:

    • 使用 imgaussfilt 对灰度图像进行高斯滤波,以减少噪声。

  2. Canny 边缘检测:

    • 使用 edge 函数进行 Canny 边缘检测,阈值范围为 [0.1, 0.2],可以根据实际情况调整。

  1. 霍夫变换:

    • 使用 hough 和 houghpeaks 检测直线。

    • 使用 houghlines 提取直线,并设置 FillGap 和 MinLength 参数以过滤短线段。

  1. 坐标转换:

    • 将 ROI 中的直线坐标转换回原图坐标,以便在原图上绘制检测到的车道线。

  2. 绘制车道线:

    • 使用 plot 函数在原图上绘制检测到的车道线。

2 代码

 2.1 实现 车道识别

% 创建一个图形窗口
figure;

% 定义 ROI(Region of Interest)
roi = [200, 200, 400, 200]; % [x, y, width, height],根据你的图像调整

% 循环处理每一帧
% while(vid.FramesAcquired <= 1000) % 处理1000帧
    % 获取一帧图像
%     frame = getsnapshot(vid);
     frame=imread('test.png');
     imagesc(frame)
     title('测试图')
    % 提取 ROI 区域
    %roiFrame = frame(roi(2):roi(2)+roi(4), roi(1):roi(1)+roi(3), :);
    shape=size(pic);%图片大小
roi(1)=0.5*shape(1); %x  宽度
roi(2)=0.4*shape(2);%高度 y
    roiFrame = frame(roi(1) :1*shape(1),roi(2):1*shape(2) ,:);  

    % 转换为灰度图像
    grayFrame = rgb2gray(roiFrame);
    
    imshow(grayFrame)
    title('grayframe 感兴趣的区域大小')
    % 使用高斯滤波去噪
    filteredFrame = imgaussfilt(grayFrame, 2);
    
    % 使用Canny边缘检测
    edges = edge(filteredFrame, 'Canny', [0.05 0.35]);
    
    % 使用霍夫变换检测直线
    [H, T, R] = hough(edges);
    P = houghpeaks(H, 5, 'threshold', ceil(0.3 * max(H(:))));
    lines = houghlines(edges, T, R, P, 'FillGap', 4, 'MinLength', 5);
    
    % 在原图上绘制检测到的直线
    imshow(frame); hold on;
    for k = 1:length(lines)
        % 将 ROI 中的坐标转换回原图坐标
        xy = [lines(k).point1; lines(k).point2];
        xy(:, 1) = xy(:, 1) + roi(2); % 调整 x 坐标
        xy(:, 2) = xy(:, 2) + roi(1); % 调整 y 坐标
        
        % 绘制直线
        plot(xy(:,1), xy(:,2), 'LineWidth', 2, 'Color', 'green');
    end
    hold off;
    
    % 刷新图形窗口
    drawnow;
% end

2.2 结果

识别的车道线

2.3 车道线合并

  这里需要考虑相邻测线合并的问题。

在车道线检测中,如果遇到相邻车道线(例如左车道线和右车道线),霍夫变换可能会检测到多条线段。如果不加以区分,这些线段可能会被错误地合并为一条车道线。为了解决这个问题,我们需要对检测到的线段进行分类和过滤,确保只保留当前车道的车道线。

% 假设 lines 是 houghlines 函数返回的线段结构体
% lines 包含以下字段:point1, point2, theta, rho

% 合并线段的阈值
angleThreshold = 5; % 角度阈值(度)
distanceThreshold = 20; % 距离阈值(像素)

% 初始化合并后的线段列表
mergedLines = [];

% 遍历所有线段
for i = 1:length(lines)
    currentLine = lines(i);
    isMerged = false;
    
    % 遍历已合并的线段列表,检查是否可以合并
    for j = 1:length(mergedLines)
        mergedLine = mergedLines(j);
        
        % 计算两条线段的角度差
        angleDiff = abs(currentLine.theta - mergedLine.theta);
        
        % 计算两条线段的距离差(使用 rho 值)
        distanceDiff = abs(currentLine.rho - mergedLine.rho);
        
        % 如果角度和距离差都在阈值内,则合并线段
        if angleDiff < angleThreshold && distanceDiff < distanceThreshold
            % 合并线段:取两个端点的最小和最大坐标
            mergedLine.point1 = min(currentLine.point1, mergedLine.point1);
            mergedLine.point2 = max(currentLine.point2, mergedLine.point2);
            
            % 更新合并后的线段
            mergedLines(j) = mergedLine;
            isMerged = true;
            break;
        end
    end
    
    % 如果当前线段没有合并到任何线段中,则添加到合并列表
    if ~isMerged
        mergedLines = [mergedLines; currentLine];
    end
end

% 区分左车道线和右车道线
leftLines = [];
rightLines = [];

for k = 1:length(mergedLines)
    line = mergedLines(k);
    
    % 计算线段的中点
    midPoint = (line.point1 + line.point2) / 2;
    
    % 根据线段的角度和中点位置分类
    if line.theta < 0 % 左车道线通常具有负角度
        leftLines = [leftLines; line];
    elseif line.theta > 0 % 右车道线通常具有正角度
        rightLines = [rightLines; line];
    end
end

% 选择最接近图像中心的左车道线和右车道线
imageCenterX = size(frame, 2) / 2; % 图像的水平中心
minLeftDistance = inf;
minRightDistance = inf;
selectedLeftLine = [];
selectedRightLine = [];

% 选择最接近图像中心的左车道线
for i = 1:length(leftLines)
    line = leftLines(i);
    midPoint = (line.point1 + line.point2) / 2;
    distance = abs(midPoint(1) - imageCenterX);
    
    if distance < minLeftDistance
        minLeftDistance = distance;
        selectedLeftLine = line;
    end
end

% 选择最接近图像中心的右车道线
for i = 1:length(rightLines)
    line = rightLines(i);
    midPoint = (line.point1 + line.point2) / 2;
    distance = abs(midPoint(1) - imageCenterX);
    
    if distance < minRightDistance
        minRightDistance = distance;
        selectedRightLine = line;
    end
end

% 绘制选定的左车道线和右车道线
figure;
imagesc(frame); hold on;
if ~isempty(selectedLeftLine)
    xy = [selectedLeftLine.point1; selectedLeftLine.point2];
         xy(:, 1) = xy(:, 1) + roi(2); % 调整 x 坐标
        xy(:, 2) = xy(:, 2) + roi(1); % 调整 y 坐标
    plot(xy(:,1), xy(:,2), 'LineWidth', 2, 'Color', 'blue');
end
if ~isempty(selectedRightLine)
    xy = [selectedRightLine.point1; selectedRightLine.point2];
             xy(:, 1) = xy(:, 1) + roi(2); % 调整 x 坐标
        xy(:, 2) = xy(:, 2) + roi(1); % 调整 y 坐标
    plot(xy(:,1), xy(:,2), 'LineWidth', 2, 'Color', 'red');
end

%计算中心线
 

hold off;

代码说明

  1. 线段分类:

    • 根据线段的角度 (theta) 和中点位置,将线段分为左车道线和右车道线。

    • 左车道线通常具有负角度,右车道线通常具有正角度。

  2. 选择最接近图像中心的车道线:

    • 计算每条线段的中点,并选择最接近图像水平中心的左车道线和右车道线。

    • 这样可以避免选择相邻车道的车道线。

  3. 绘制车道线:

    • 使用蓝色绘制左车道线,红色绘制右车道线。


参数调整建议

  • 角度分类阈值:

    • 如果车道线的角度分布不明显,可以调整角度分类的阈值。

    • 例如,将左车道线的角度范围设置为 -90° 到 -10°,右车道线的角度范围设置为 10° 到 90°

  • 图像中心范围:

    • 如果车道线距离图像中心较远,可以适当增加选择车道线的范围。

优化方向:

  1. 动态角度分类:

    • 根据车道线的实际分布动态调整角度分类的阈值。

  2. 车道线拟合:

    • 使用多项式拟合(如二次曲线)对选定的车道线进行平滑处理。

  3. 多车道处理:

    • 如果需要检测多车道,可以根据距离和角度进一步分类车道线。

合并结果

3 相机坐标转换

  后续就需要对车道线进行坐标转换,转为车辆坐标系。

相机标定:相机挂在小车上,用棋盘格标定。

下载30mm*30mm棋盘格进行标定 。

参考书籍:Zhengyou Zhang, A Flexible New Technique for Camera Calibration, 掌握标定原理。

待续!


网站公告

今日签到

点亮在社区的每一天
去签到