需要讓小車保持車道行駛,首先需要進行車道線識別。
也可參看論文(上傳到資源里):自動駕駛汽車車道檢測與預測的技術解析-基于圖像處理和Hough變換的方法
1 車道識別流程
想進行車道線識別,并且希望在圖像中選擇一個特定的區域進行處理(例如只處理道路區域),可以通過以下步驟對代碼進行修改。我們將使用 ROI(Region of Interest)來限制處理范圍,并優化車道線檢測的邏輯。
具體步驟:
-
ROI(Region of Interest):
-
使用?
roi
?變量定義感興趣區域,格式為?[x, y, width, height]
。 -
通過?
roiFrame = frame(roi(2):roi(2)+roi(4), roi(1):roi(1)+roi(3), :)
?提取 ROI 區域。
-
-
高斯濾波:
-
使用?
imgaussfilt
?對灰度圖像進行高斯濾波,以減少噪聲。
-
-
Canny 邊緣檢測:
-
使用?
edge
?函數進行 Canny 邊緣檢測,閾值范圍為?[0.1, 0.2]
,可以根據實際情況調整。
-
-
霍夫變換:
-
使用?
hough
?和?houghpeaks
?檢測直線。 -
使用?
houghlines
?提取直線,并設置?FillGap
?和?MinLength
?參數以過濾短線段。
-
-
坐標轉換:
-
將 ROI 中的直線坐標轉換回原圖坐標,以便在原圖上繪制檢測到的車道線。
-
-
繪制車道線:
-
使用?
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);%高度 yroiFrame = 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');endhold 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;endend% 如果當前線段沒有合并到任何線段中,則添加到合并列表if ~isMergedmergedLines = [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 < minLeftDistanceminLeftDistance = 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 < minRightDistanceminRightDistance = 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;
代碼說明
-
線段分類:
-
根據線段的角度 (
theta
) 和中點位置,將線段分為左車道線和右車道線。 -
左車道線通常具有負角度,右車道線通常具有正角度。
-
-
選擇最接近圖像中心的車道線:
-
計算每條線段的中點,并選擇最接近圖像水平中心的左車道線和右車道線。
-
這樣可以避免選擇相鄰車道的車道線。
-
-
繪制車道線:
-
使用藍色繪制左車道線,紅色繪制右車道線。
-
參數調整建議
-
角度分類閾值:
-
如果車道線的角度分布不明顯,可以調整角度分類的閾值。
-
例如,將左車道線的角度范圍設置為?
-90° 到 -10°
,右車道線的角度范圍設置為?10° 到 90°
。
-
-
圖像中心范圍:
-
如果車道線距離圖像中心較遠,可以適當增加選擇車道線的范圍。
-
優化方向:
-
動態角度分類:
-
根據車道線的實際分布動態調整角度分類的閾值。
-
-
車道線擬合:
-
使用多項式擬合(如二次曲線)對選定的車道線進行平滑處理。
-
-
多車道處理:
-
如果需要檢測多車道,可以根據距離和角度進一步分類車道線。
-
合并結果
3 相機坐標轉換
? 后續就需要對車道線進行坐標轉換,轉為車輛坐標系。
相機標定:相機掛在小車上,用棋盤格標定。
下載30mm*30mm棋盤格進行標定 。
參考書籍:Zhengyou Zhang, A Flexible New Technique for Camera Calibration, 掌握標定原理。
待續!