《MATLAB實戰訓練營:從入門到工業級應用》工程實用篇-🚗 自動駕駛初體驗:車道線檢測算法實戰(MATLAB2016b版)
大家好!今天我要帶大家一起探索自動駕駛中一個非常基礎但又至關重要的技術——車道線檢測。我們將從零開始,一步步用MATLAB2016b實現一個完整的車道線檢測系統。準備好你的MATLAB,讓我們開始這場有趣的自動駕駛之旅吧!?
一、準備工作與環境搭建
1.1 為什么選擇MATLAB2016b?
MATLAB在圖像處理和計算機視覺領域有著強大的功能,而2016b版本穩定且兼容性好,適合教學和實驗。當然,如果你有更新的版本也完全沒問題!
1.2 需要安裝的工具箱
確保你已經安裝了以下工具箱(可以通過ver
命令查看):
- Image Processing Toolbox
- Computer Vision System Toolbox
如果沒有安裝,可以通過MATLAB的"附加功能"菜單進行安裝。
1.3 測試數據準備
我們將使用一段高速公路行車視頻作為測試數據。你可以使用自己的行車記錄儀視頻,或者自己從網上下載一個視頻:
高速公路駕駛highway_lane
二、車道線檢測基礎理論
2.1 車道線檢測的基本流程
一個典型的車道線檢測流程包括以下幾個步驟:
- 圖像獲取 📷
- 預處理(去噪、增強等) 🛠?
- 邊緣檢測 ??
- 感興趣區域(ROI)提取 🔍
- 霍夫變換檢測直線 📐
- 車道線擬合與可視化 🚦
2.2 為什么選擇霍夫變換?
霍夫變換是檢測圖像中幾何形狀(如直線、圓等)的經典算法。它能夠將圖像空間中的像素點映射到參數空間,通過累加器找出最可能的幾何形狀參數。
三、實戰開始!一步步實現車道線檢測
3.1 讀取并顯示視頻
首先,我們需要讀取視頻并顯示第一幀,看看我們的"戰場"是什么樣子:
% 創建視頻讀取對象
videoReader = VideoReader('highway_lane.mp4');% 讀取第一幀
frame = readFrame(videoReader);% 顯示原始圖像
figure('Name', '原始視頻幀');
imshow(frame);
title('原始視頻幀');
3.2 圖像預處理
原始圖像包含太多干擾信息,我們需要進行預處理:
% 轉換為灰度圖像
grayFrame = rgb2gray(frame);% 高斯濾波去噪
filteredFrame = imgaussfilt(grayFrame, 2);% 顯示預處理結果
figure('Name', '預處理結果');
subplot(1,2,1); imshow(grayFrame); title('灰度圖像');
subplot(1,2,2); imshow(filteredFrame); title('高斯濾波后');
3.3 邊緣檢測
邊緣檢測是車道線檢測的關鍵步驟,我們使用Canny算法:
% Canny邊緣檢測
edgeThreshold = [0.1, 0.2]; % 閾值可以調整
sigma = 1; % 高斯濾波參數
edges = edge(filteredFrame, 'Canny', edgeThreshold, 'both', sigma);% 顯示邊緣檢測結果
figure('Name', '邊緣檢測結果');
imshow(edges);
title('Canny邊緣檢測結果');
小技巧:閾值的選擇很重要,太低會檢測到太多噪聲,太高可能會漏掉真實的車道線。可以嘗試調整看看效果變化!
3.4 感興趣區域(ROI)提取
我們不需要分析整個圖像,只需要關注車輛前方的道路區域:
% 獲取圖像尺寸
[rows, cols] = size(edges);% 定義ROI多邊形頂點(梯形區域)
roi = [1, rows; cols/2-50, rows/2+50; cols/2+50, rows/2+50; cols, rows];% 創建ROI掩模
roiMask = poly2mask(roi(:,1), roi(:,2), rows, cols);% 應用ROI掩模
roiEdges = edges & roiMask;% 顯示ROI提取結果
figure('Name', 'ROI提取');
subplot(1,2,1); imshow(edges); hold on;
plot(roi(:,1), roi(:,2), 'r-', 'LineWidth', 2);
title('原始邊緣+ROI區域');
subplot(1,2,2); imshow(roiEdges);
title('ROI內邊緣');
3.5 霍夫變換檢測直線
現在是重頭戲——使用霍夫變換檢測直線:
% 霍夫變換參數設置
thetaResolution = 0.5; % 角度分辨率
rhoResolution = 1; % 距離分辨率
threshold = 50; % 累加器閾值
minLineLength = 30; % 最小線段長度
maxLineGap = 20; % 線段間最大間隔% 執行霍夫變換
[H, theta, rho] = hough(roiEdges, 'Theta', -90:thetaResolution:89, 'RhoResolution', rhoResolution);% 檢測峰值
peaks = houghpeaks(H, 10, 'Threshold', threshold);% 檢測線段
lines = houghlines(roiEdges, theta, rho, peaks, 'FillGap', maxLineGap, 'MinLength', minLineLength);% 顯示霍夫變換結果
figure('Name', '霍夫變換檢測結果');
imshow(frame); hold on;
for k = 1:length(lines)xy = [lines(k).point1; lines(k).point2];plot(xy(:,1), xy(:,2), 'LineWidth', 2, 'Color', 'green');
end
title('霍夫變換檢測到的直線');
3.6 車道線篩選與擬合
不是所有檢測到的直線都是車道線,我們需要篩選:
% 篩選左右車道線
leftLines = [];
rightLines = [];for k = 1:length(lines)% 計算線段斜率x1 = lines(k).point1(1);y1 = lines(k).point1(2);x2 = lines(k).point2(1);y2 = lines(k).point2(2);slope = (y2 - y1) / (x2 - x1);% 根據斜率篩選if slope < -0.3 % 左車道線通常有負斜率leftLines = [leftLines; [x1, y1; x2, y2]]; % 往后追加elseif slope > 0.3 % 右車道線通常有正斜率rightLines = [rightLines; [x1, y1; x2, y2]]; % 往后追加end
end% 擬合左右車道線(使用最小二乘法)
if ~isempty(leftLines)leftPoints = [leftLines(1:2,:); leftLines(3:4,:)];leftPoly = polyfit(leftPoints(:,2), leftPoints(:,1), 1);
endif ~isempty(rightLines)rightPoints = [rightLines(1:2,:); rightLines(3:4,:)];rightPoly = polyfit(rightPoints(:,2), rightPoints(:,1), 1);
end% 顯示最終結果
figure('Name', '最終車道線檢測結果');
imshow(frame); hold on;% 繪制左車道線
if exist('leftPoly', 'var')yLeft = [rows/2+50, rows];xLeft = polyval(leftPoly, yLeft);plot(xLeft, yLeft, 'LineWidth', 4, 'Color', 'red');
end% 繪制右車道線
if exist('rightPoly', 'var')yRight = [rows/2+50, rows];xRight = polyval(rightPoly, yRight);plot(xRight, yRight, 'LineWidth', 4, 'Color', 'blue');
endtitle('最終車道線檢測結果');
legend('左車道線', '右車道線');
四、完整視頻處理與優化
4.1 封裝為函數
讓我們把上面的代碼封裝成一個函數,方便處理視頻的每一幀:
function [leftLine, rightLine] = detectLanes(frame)% 轉換為灰度圖像grayFrame = rgb2gray(frame);% 高斯濾波filteredFrame = imgaussfilt(grayFrame, 2);% 邊緣檢測edgeThreshold = [0.1, 0.2];sigma = 1;
% edges = edge(filteredFrame, 'Canny', edgeThreshold, 'both', sigma);edges = edge(filteredFrame, 'Canny', edgeThreshold, 'both');% ROI提取[rows, cols] = size(edges);roi = [1, rows; cols/2-50, rows/2+50; cols/2+50, rows/2+50; cols, rows];roiMask = poly2mask(roi(:,1), roi(:,2), rows, cols);roiEdges = edges & roiMask;% 霍夫變換thetaResolution = 0.5;rhoResolution = 1;threshold = 50;minLineLength = 30;maxLineGap = 20;[H, theta, rho] = hough(roiEdges, 'Theta', -90:thetaResolution:89, 'RhoResolution', rhoResolution);peaks = houghpeaks(H, 10, 'Threshold', threshold);lines = houghlines(roiEdges, theta, rho, peaks, 'FillGap', maxLineGap, 'MinLength', minLineLength);% 篩選和擬合車道線leftLines = [];rightLines = [];for k = 1:length(lines)x1 = lines(k).point1(1);y1 = lines(k).point1(2);x2 = lines(k).point2(1);y2 = lines(k).point2(2);slope = (y2 - y1) / (x2 - x1);if slope < -0.3leftLines = [leftLines; [x1, y1; x2, y2]];elseif slope > 0.3rightLines = [rightLines; [x1, y1; x2, y2]];endend% 返回擬合結果leftLine = [];rightLine = [];if ~isempty(leftLines) & length(leftLines)>4leftPoints = [leftLines(1:2,:); leftLines(3:4,:)];leftLine = polyfit(leftPoints(:,2), leftPoints(:,1), 1);endif ~isempty(rightLines) & length(rightLines)>4rightPoints = [rightLines(1:2,:); rightLines(3:4,:)];rightLine = polyfit(rightPoints(:,2), rightPoints(:,1), 1);end
end
4.2 處理整個視頻
現在我們可以處理整個視頻了:
clc
close all
% 創建視頻讀取和寫入對象
videoReader = VideoReader('highway_lane.mp4');
videoWriter = VideoWriter('lane_detection_result.avi');
open(videoWriter);% 創建顯示窗口
figure('Name', '實時車道線檢測', 'Position', [100, 100, 800, 600]);while hasFrame(videoReader)% 讀取當前幀frame = readFrame(videoReader);% 檢測車道線[leftLine, rightLine] = detectLanes(frame);% 顯示結果imshow(frame); hold on;% 繪制左車道線if ~isempty(leftLine)yLeft = [size(frame,1)/2+50, size(frame,1)];xLeft = polyval(leftLine, yLeft);plot(xLeft, yLeft, 'LineWidth', 4, 'Color', 'red');end% 繪制右車道線if ~isempty(rightLine)yRight = [size(frame,1)/2+50, size(frame,1)];xRight = polyval(rightLine, yRight);plot(xRight, yRight, 'LineWidth', 4, 'Color', 'blue');endtitle('實時車道線檢測');drawnow;% 寫入視頻frameWithLanes = getframe(gcf);writeVideo(videoWriter, frameWithLanes.cdata);hold off;
end% 關閉視頻寫入器
close(videoWriter);
disp('視頻處理完成');
五、進階優化與挑戰
5.1 優化建議
我們的基礎版本已經可以工作了,但還有很大優化空間:
- 動態ROI調整:根據車輛速度調整ROI區域大小
- 顏色信息利用:結合車道線顏色(黃、白)增強檢測
- 卡爾曼濾波:平滑車道線檢測結果,減少抖動
- 曲線車道檢測:使用二次或三次多項式擬合曲線車道
5.2 常見問題與解決方案
問題1:在強光下檢測效果差
- 解決方案:使用自適應直方圖均衡化(CLAHE)增強對比度
% 替換灰度轉換和高斯濾波部分
labFrame = rgb2lab(frame);
L = labFrame(:,:,1)/100;
L = adapthisteq(L);
labFrame(:,:,1) = L*100;
enhancedFrame = lab2rgb(labFrame);
grayFrame = rgb2gray(enhancedFrame);
問題2:檢測到非車道線的邊緣
- 解決方案:增加后處理步驟,如基于車道線幾何約束的篩選
六、總結與展望
恭喜你!🎉 我們已經完成了一個完整的車道線檢測系統。雖然它看起來簡單,但這是自動駕駛的基礎模塊之一。通過這個項目,我們學習了:
- 圖像預處理技術
- 邊緣檢測算法
- 霍夫變換原理與應用
- 車道線擬合方法
未來你可以嘗試:
- 實現更復雜的車道線檢測算法
- 集成到更大的自動駕駛系統中
- 嘗試使用深度學習的方法(如LaneNet)
希望這篇教程對你有所幫助!如果有任何問題或建議,歡迎在評論區留言討論。Happy coding! 💻🚀
附錄:完整代碼下載
點擊這里下載完整MATLAB代碼包
參考文獻:
- MATLAB官方文檔
- 《計算機視覺:算法與應用》Richard Szeliski
- 《自動駕駛中的計算機視覺》系列論文