實(shí)戰(zhàn):環(huán)境搭建、參數(shù)調(diào)優(yōu)與GUI避坑指南)
簡(jiǎn)介這份資源面向正在做畢設(shè)、課程設(shè)計(jì)或期末大作業(yè)的學(xué)生以及希望入門計(jì)算機(jī)視覺與圖像處理方向的Python學(xué)習(xí)者提供一套可直接運(yùn)行的車道線檢測(cè)完整項(xiàng)目。源碼基于Python與OpenCV實(shí)現(xiàn)覆蓋圖像加載、灰度化與高斯濾波預(yù)處理、Canny邊緣檢測(cè)、感興趣區(qū)域提取、霍夫直線檢測(cè)、直線擬合與車道線疊加等完整流程并支持圖片與視頻兩種測(cè)試方式另附可選的PyQt5可視化界面便于直觀演示檢測(cè)效果。壓縮包共10個(gè)文件約26.9MB包含2個(gè)py源碼文件、2段mp4演示視頻、4張jpg效果對(duì)比圖以及requirements.txt依賴清單和項(xiàng)目說明文檔代碼配有詳細(xì)注釋環(huán)境依賴numpy、matplotlib、opencv-python等常見庫(kù)配置門檻較低。目前已有1535人學(xué)習(xí)下載適合作為畢設(shè)或課程設(shè)計(jì)的參考模板也可用于學(xué)習(xí)OpenCV圖像分割與模式識(shí)別的實(shí)戰(zhàn)思路。1. 車道線檢測(cè)這套源碼拿到手先別急著跑很多人從網(wǎng)上拿到「基于 PythonOpenCV 的車道線檢測(cè)源碼詳細(xì)注釋GUI演示視頻」這類壓縮包第一反應(yīng)是解壓、雙擊、跑起來(lái)看效果。結(jié)果十有八九卡在ModuleNotFoundError: No module named opencv或者窗口一閃而過或者視頻里跑得挺順、自己一跑就滿屏噪點(diǎn)。問題不在代碼在于你沒先搞清楚這套東西到底由哪幾塊拼起來(lái)、每塊對(duì)輸入有什么隱含要求。車道線檢測(cè)本質(zhì)是一條圖像處理流水線讀幀 → 灰度化 → 高斯濾波 → 邊緣檢測(cè)Canny→ 感興趣區(qū)域ROI裁剪 → 霍夫變換擬合直線 → 疊加回原圖。GUI 只是給這條流水線套了個(gè)能調(diào)參、能切視頻源的殼。它適合兩類人一是剛學(xué) OpenCV、想找一個(gè)能跑通、能改參數(shù)的完整小項(xiàng)目練手的人二是要做 ADAS 原型、需要快速驗(yàn)證 ROI 和閾值組合的人。這篇不吹效果只講怎么把它跑穩(wěn)、參數(shù)怎么調(diào)、哪里最容易翻車。2. 把環(huán)境搭對(duì)Python、OpenCV 和 GUI 依賴的版本對(duì)齊2.1 為什么 OpenCV 版本和 Python 版本必須先鎖死車道線檢測(cè)代碼里最常出問題的不是算法是環(huán)境。cv2.HoughLinesP、cv2.Canny、cv2.fillPoly這些函數(shù)在不同 OpenCV 大版本之間行為基本一致但 GUI 部分一旦用到tkinterPillow顯示就會(huì)牽扯到 NumPy 版本和 OpenCV 的 ABI 兼容。常見翻車現(xiàn)場(chǎng)是pip install opencv-python裝上了最新版結(jié)果import cv2報(bào)numpy.core.multiarray failed to import因?yàn)?NumPy 2.x 和舊版 OpenCV 編譯時(shí)鏈接的 ABI 對(duì)不上。我一般會(huì)先把版本釘死在一個(gè)經(jīng)過驗(yàn)證的組合上而不是無(wú)腦裝最新。下面這套組合在 Windows 和 Ubuntu 上都能穩(wěn)定跑通車道線檢測(cè)加 tkinter GUI組件推薦版本說明Python3.8 ~ 3.103.11 部分輪子還沒跟上新手別碰opencv-python4.5.5.64帶 GUI 的完整包不是 headlessnumpy1.23.5別升 2.xABI 坑多Pillow9.5.0tkinter 里顯示視頻幀用tkinter隨 Python 自帶Linux 下需單獨(dú)裝 python3-tk注意如果你在 Ubuntu 上跑pip install opencv-python之后 GUI 窗口可能報(bào)cv2.error: OpenCV(4.5.5) ... cant open display這不是代碼問題是缺 X11 轉(zhuǎn)發(fā)或沒裝python3-tk。服務(wù)器上跑就老老實(shí)實(shí)用 headless 版別硬開窗口。2.2 從零建環(huán)境到跑通第一幀的完整命令下面這套命令是我在干凈機(jī)器上復(fù)現(xiàn)過多次的流程Windows 用 PowerShell 或 CMDLinux 用 bash邏輯一樣。先建虛擬環(huán)境再按順序裝依賴最后驗(yàn)證cv2和tkinter都能正常導(dǎo)入。# 1. 建虛擬環(huán)境避免污染系統(tǒng) Python python -m venv lane_env # 2. 激活環(huán)境 # Windows: lane_env\Scripts\activate # Linux / macOS: source lane_env/bin/activate # 3. 先裝 numpy再裝 opencv順序反了有時(shí)會(huì)觸發(fā)重編譯 pip install numpy1.23.5 pip install opencv-python4.5.5.64 pip install Pillow9.5.0 # 4. 驗(yàn)證核心依賴 python -c import cv2; print(cv2.__version__) python -c import tkinter; print(tkinter ok)邏輯說明先建虛擬環(huán)境是為了把車道線檢測(cè)這套依賴和系統(tǒng)里其他項(xiàng)目的 OpenCV 隔離開避免版本打架。先裝 NumPy 再裝 OpenCV 是因?yàn)閛pencv-python的 wheel 在安裝時(shí)會(huì)檢查 NumPy 版本順序?qū)α四苌僖淮沃匮b。最后兩步驗(yàn)證必須都打印出版本或 ok缺一個(gè)后面 GUI 就跑不起來(lái)。參數(shù)說明opencv-python4.5.5.64這個(gè)版本號(hào)不是隨便選的它對(duì)應(yīng) OpenCV 4.5.5帶完整的 highgui 模塊cv2.imshow和cv2.VideoCapture都正常。如果你裝的是opencv-python-headlessimshow會(huì)直接報(bào)錯(cuò)因?yàn)?headless 包把 GUI 相關(guān)模塊裁掉了。Pillow 只用于 tkinter 里把 OpenCV 的 BGR 幀轉(zhuǎn)成 PhotoImage版本不用太新9.x 足夠。2.3 源碼目錄結(jié)構(gòu)怎么讀先找入口再找參數(shù)拿到壓縮包解壓后別急著改代碼。先按下面這個(gè)順序把文件過一遍通常這類項(xiàng)目會(huì)包含這些部分lane_detection/ ├── main.py # 入口命令行模式跑視頻 ├── gui_app.py # tkinter GUI 入口可選 ├── lane_detector.py # 核心檢測(cè)類Canny ROI Hough ├── utils.py # 畫線、透視變換、坐標(biāo)計(jì)算 ├── config.py # 所有閾值參數(shù)集中在這里 ├── test_videos/ # 演示視頻 └── requirements.txt # 依賴清單先打開config.py把所有閾值抄下來(lái)。車道線檢測(cè)的效果 80% 取決于這幾個(gè)數(shù)Canny 的低高閾值、ROI 梯形的四個(gè)頂點(diǎn)、Hough 的rho、theta、threshold、minLineLength、maxLineGap。然后打開lane_detector.py找到detect或process_frame方法順著調(diào)用鏈看一遍。最后再跑main.py用test_videos里的視頻驗(yàn)證。GUI 入口gui_app.py放到最后再碰因?yàn)樗皇前艘粚雍诵倪壿嫴蛔?。提示如果壓縮包里沒有requirements.txt就按 2.1 的表格手動(dòng)裝。別用pip install -r去裝一個(gè)來(lái)源不明的清單里面可能釘了和你系統(tǒng)不兼容的版本。3. 車道線檢測(cè)流水線從一幀圖像到兩條線的每一步3.1 灰度、濾波、Canny三個(gè)參數(shù)決定邊緣質(zhì)量車道線檢測(cè)的第一步是把彩色幀變成只含亮度信息的灰度圖再做高斯模糊壓噪最后用 Canny 提取邊緣。這三步里高斯核大小和 Canny 雙閾值是最需要調(diào)的。核太大車道線邊緣會(huì)被糊掉核太小噪點(diǎn)全留下來(lái)。Canny 低閾值管弱邊緣高閾值管強(qiáng)邊緣比例一般控制在 1:2 到 1:3。import cv2 import numpy as np def preprocess(frame, gaussian_ksize5, canny_low50, canny_high150): # 轉(zhuǎn)灰度車道線檢測(cè)只關(guān)心亮度變化彩色信息是干擾 gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 高斯模糊ksize 必須是奇數(shù)5 是速度和效果的平衡點(diǎn) blur cv2.GaussianBlur(gray, (gaussian_ksize, gaussian_ksize), 0) # Canny 邊緣低閾值 50 保留弱邊緣高閾值 150 過濾噪聲 edges cv2.Canny(blur, canny_low, canny_high) return edges邏輯說明cvtColor把 BGR 三通道壓成單通道后續(xù)所有操作都在單通道上做計(jì)算量直接降到三分之一。GaussianBlur的第三個(gè)參數(shù) sigma 傳 0 表示由核大小自動(dòng)推算一般不用手動(dòng)改。Canny輸出的是一張二值圖白色是邊緣黑色是背景這張圖就是后面 ROI 裁剪和霍夫變換的輸入。參數(shù)說明gaussian_ksize常用 3、5、7。視頻分辨率 720p 以下用 51080p 用 7。canny_low和canny_high沒有萬(wàn)能值白天高速場(chǎng)景 50/150 比較穩(wěn)夜間或隧道里要降到 30/100否則車道線邊緣全被當(dāng)噪聲濾掉。調(diào)的時(shí)候先固定高閾值慢慢降低閾值直到車道線連續(xù)但路面紋理不炸。3.2 ROI 梯形裁剪把天空和對(duì)面車道全扔掉Canny 出來(lái)的邊緣圖里天空、樹木、對(duì)面來(lái)車全是干擾。ROI 的作用是用一個(gè)梯形把畫面下半部分、當(dāng)前車道所在區(qū)域框出來(lái)其余全部置黑。梯形的四個(gè)頂點(diǎn)是這套代碼里最“玄學(xué)”的參數(shù)因?yàn)樗拖鄼C(jī)安裝高度、俯仰角、分辨率強(qiáng)相關(guān)。def region_of_interest(edges, vertices): # 創(chuàng)建一個(gè)和 edges 同尺寸的全黑掩膜 mask np.zeros_like(edges) # 用白色填充梯形區(qū)域其余保持黑色 cv2.fillPoly(mask, [vertices], 255) # 按位與只保留梯形內(nèi)的邊緣 masked cv2.bitwise_and(edges, mask) return masked # 以 1280x720 為例梯形頂點(diǎn)順序左下、左上、右上、右下 height, width 720, 1280 roi_vertices np.array([[ (100, height), # 左下 (width // 2 - 80, 420), # 左上地平線附近 (width // 2 80, 420), # 右上 (width - 100, height) # 右下 ]], dtypenp.int32)邏輯說明np.zeros_like生成一張和邊緣圖同尺寸的全黑圖fillPoly把梯形內(nèi)部涂白bitwise_and讓邊緣圖只在梯形白色區(qū)域保留像素。這樣天空和兩側(cè)的干擾就被物理隔離了霍夫變換只會(huì)在車道線附近找直線。參數(shù)說明四個(gè)頂點(diǎn)里左下和右下一般貼著畫面底邊左右各留 100 像素避開畫面邊緣畸變。左上和右上的 y 坐標(biāo)是地平線位置720p 下通常在 400~450 之間。x 坐標(biāo)以畫面中心為基準(zhǔn)左右各偏 80~120 像素偏太多會(huì)把相鄰車道也框進(jìn)來(lái)。調(diào) ROI 的時(shí)候把fillPoly的結(jié)果用imshow看一眼梯形上邊剛好卡在車道線消失的位置最合適。3.3 霍夫變換擬合threshold 和 minLineLength 怎么定ROI 裁剪后的邊緣圖交給HoughLinesP做概率霍夫變換輸出一堆線段。這些線段還要按斜率分成左右兩組再各自擬合成一條完整車道線。HoughLinesP的參數(shù)直接決定檢出線段的多少和長(zhǎng)短。def hough_lines(masked_edges, rho1, thetanp.pi/180, threshold30, min_line_len100, max_line_gap50): # 概率霍夫變換返回線段端點(diǎn)列表 lines cv2.HoughLinesP( masked_edges, rho, # 距離分辨率1 像素 theta, # 角度分辨率1 度 threshold, # 累加器閾值越大越嚴(yán)格 minLineLengthmin_line_len, # 線段最短長(zhǎng)度 maxLineGapmax_line_gap # 同一條線允許的最大斷裂 ) return lines if lines is not None else []邏輯說明rho和theta是霍夫空間的采樣精度1 像素和 1 度是 OpenCV 官方示例的默認(rèn)值一般不用改。threshold是累加器閾值意思是至少要有多少條邊緣像素共線才認(rèn)為是一條直線值越大檢出的線越少但越可靠。minLineLength過濾掉太短的碎線maxLineGap把同一條車道線上斷開的段連起來(lái)。參數(shù)說明threshold在 720p 下常用 20~40路面紋理復(fù)雜就往上調(diào)車道線斷續(xù)就往下調(diào)。min_line_len建議設(shè)為畫面高度的 1/6 到 1/8720p 下 100 左右。max_line_gap設(shè)為min_line_len的一半50 左右太大容易把兩條平行車道線連成一條。調(diào)完這組參數(shù)用cv2.line把檢出的線段畫出來(lái)看一眼左右各一條、斜率合理就算過。3.4 左右車道線分組與擬合斜率篩選和加權(quán)平均霍夫變換輸出的線段不分左右需要按斜率正負(fù)分組。圖像坐標(biāo)系 y 軸向下所以左車道線斜率通常為負(fù)右車道線斜率為正。分組后對(duì)每組線段的端點(diǎn)和斜率做加權(quán)平均得到一條穩(wěn)定的車道線。def separate_and_fit(lines, height, width): left_pts, right_pts [], [] for line in lines: x1, y1, x2, y2 line[0] if x2 x1: continue # 垂直線跳過避免除零 slope (y2 - y1) / (x2 - x1) if abs(slope) 0.3: continue # 太接近水平的線不是車道線 if slope 0: left_pts.append((x1, y1, x2, y2)) else: right_pts.append((x1, y1, x2, y2)) # 對(duì)每組做一次最小二乘擬合得到 y kx b left_line fit_line(left_pts, height) right_line fit_line(right_pts, height) return left_line, right_line邏輯說明先按斜率正負(fù)把線段分到左右兩組同時(shí)用abs(slope) 0.3過濾掉接近水平的干擾線。fit_line內(nèi)部把所有端點(diǎn)堆在一起做一次np.polyfit得到一條貫穿畫面的直線再按畫面底部和地平線兩個(gè) y 值反推 x 坐標(biāo)畫出完整車道線。參數(shù)說明斜率閾值 0.3 是經(jīng)驗(yàn)值對(duì)應(yīng)大約 17 度低于這個(gè)角度的線基本是路面接縫或陰影。如果視頻里彎道多polyfit的階數(shù)可以從 1 升到 2用二次曲線擬合但代碼復(fù)雜度會(huì)上去。直線擬合在高速和城市直道上夠用急彎場(chǎng)景會(huì)明顯滯后這是這套方案的邊界。4. GUI 界面怎么接tkinter 顯示視頻幀的三個(gè)關(guān)鍵點(diǎn)4.1 用 tkinter 顯示 OpenCV 幀BGR 轉(zhuǎn) RGB 再轉(zhuǎn) PhotoImageGUI 部分最常見的坑是直接把 OpenCV 的 BGR 幀塞給 tkinter結(jié)果顏色全反。正確做法是先cvtColor轉(zhuǎn) RGB再用 Pillow 轉(zhuǎn)成ImageTk.PhotoImage最后貼到 Label 上。整個(gè)過程要放在主循環(huán)里定時(shí)刷新。import tkinter as tk from PIL import Image, ImageTk import cv2 class LaneGUI: def __init__(self, root, detector): self.root root self.detector detector self.label tk.Label(root) self.label.pack() self.cap cv2.VideoCapture(0) # 0 表示默認(rèn)攝像頭 self.update_frame() def update_frame(self): ret, frame self.cap.read() if ret: # 核心檢測(cè)邏輯返回畫好車道線的幀 result self.detector.process(frame) # OpenCV 是 BGRtkinter 要 RGB rgb cv2.cvtColor(result, cv2.COLOR_BGR2RGB) img Image.fromarray(rgb) imgtk ImageTk.PhotoImage(imageimg) self.label.imgtk imgtk # 必須保留引用否則圖會(huì)消失 self.label.configure(imageimgtk) # 每 15ms 刷新一次約 60fps 上限 self.root.after(15, self.update_frame)邏輯說明update_frame是一個(gè)自遞歸的定時(shí)任務(wù)root.after讓 tkinter 在指定毫秒后再次調(diào)用自己形成視頻流。self.label.imgtk imgtk這行是血淚經(jīng)驗(yàn)不保留引用的話 Python 垃圾回收會(huì)把圖像對(duì)象回收掉窗口里就是一片空白。參數(shù)說明after(15, ...)的 15ms 對(duì)應(yīng)約 66fps實(shí)際幀率受檢測(cè)耗時(shí)限制。如果檢測(cè)一幀要 50ms刷新間隔設(shè)再小也沒用反而堆積任務(wù)。VideoCapture(0)是默認(rèn)攝像頭換成視頻文件路徑就是讀文件。GUI 里最好加一個(gè)滑塊調(diào) Canny 閾值方便實(shí)時(shí)看效果但滑塊回調(diào)里別做重計(jì)算否則界面會(huì)卡。4.2 命令行模式和 GUI 模式怎么共用同一套檢測(cè)代碼好的項(xiàng)目結(jié)構(gòu)會(huì)把檢測(cè)邏輯抽成一個(gè)類命令行入口和 GUI 入口都調(diào)這個(gè)類。這樣你調(diào)參只需要改一處兩個(gè)入口行為一致。下面是一個(gè)最小化的檢測(cè)類骨架class LaneDetector: def __init__(self, config): self.canny_low config[canny_low] self.canny_high config[canny_high] self.roi_vertices config[roi_vertices] self.hough_threshold config[hough_threshold] def process(self, frame): edges preprocess(frame, 5, self.canny_low, self.canny_high) masked region_of_interest(edges, self.roi_vertices) lines hough_lines(masked, thresholdself.hough_threshold) left, right separate_and_fit(lines, frame.shape[0], frame.shape[1]) return draw_lanes(frame, left, right)邏輯說明LaneDetector把所有可調(diào)參數(shù)收在config字典里process方法接收一幀、返回畫好線的幀。命令行入口循環(huán)讀視頻調(diào)processGUI 入口在update_frame里調(diào)process兩邊完全解耦。參數(shù)說明config字典建議直接從config.py導(dǎo)入GUI 里的滑塊改的就是這個(gè)字典的值。注意process不要在里面做imshow顯示交給調(diào)用方否則 GUI 和命令行會(huì)搶窗口。5. 避坑與排查車道線檢測(cè)最常見的 5 個(gè)翻車現(xiàn)場(chǎng)5.1 現(xiàn)象窗口一閃而過或者報(bào) NoneType 錯(cuò)誤原因cv2.VideoCapture打開視頻文件失敗返回False后面cap.read()返回None再往下傳就炸。常見于路徑里有中文、空格或者視頻編解碼器不支持。解決打開后先判斷cap.isOpened()路徑用os.path.join拼別手寫反斜杠。視頻文件先用系統(tǒng)播放器確認(rèn)能播再交給 OpenCV。5.2 現(xiàn)象車道線檢測(cè)結(jié)果滿屏亂線左右不分原因ROI 梯形畫太大把對(duì)面車道和路邊的護(hù)欄都框進(jìn)來(lái)了或者 Canny 低閾值太低路面紋理全變成邊緣。解決先把 ROI 收窄只留當(dāng)前車道再把canny_low往上調(diào) 20直到邊緣圖里只剩車道線輪廓。分組時(shí)把斜率閾值從 0.3 提到 0.5過濾掉更多斜線。5.3 現(xiàn)象GUI 窗口里圖像顏色發(fā)藍(lán)或發(fā)紅原因OpenCV 讀進(jìn)來(lái)是 BGRtkinter 和 Pillow 按 RGB 解釋通道順序反了。解決在Image.fromarray之前加cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)。如果顏色還是不對(duì)檢查是不是用了cv2.imread讀圖片但沒轉(zhuǎn)。5.4 現(xiàn)象視頻播放越來(lái)越卡內(nèi)存一直漲原因update_frame里每次都新建PhotoImage但沒釋放舊的或者VideoCapture沒在窗口關(guān)閉時(shí)release。解決self.label.imgtk imgtk會(huì)覆蓋舊引用Python 會(huì)自動(dòng)回收。窗口關(guān)閉時(shí)綁定WM_DELETE_WINDOW事件在里面調(diào)cap.release()和root.destroy()。5.5 現(xiàn)象換一個(gè)視頻就完全檢測(cè)不到線原因參數(shù)是在演示視頻上調(diào)死的換了分辨率、相機(jī)高度、光照就失效。解決把config.py里的參數(shù)按視頻來(lái)源分組或者加一個(gè)自動(dòng)模式先跑前 30 幀統(tǒng)計(jì)邊緣密度動(dòng)態(tài)調(diào) Canny 閾值。ROI 頂點(diǎn)按分辨率比例算別寫死像素值。6. 進(jìn)階技巧用滑動(dòng)窗口把直線擬合升級(jí)成彎道檢測(cè)直線擬合在直道上夠用但遇到彎道就會(huì)畫出一條穿過車道外的斜線。想提升彎道表現(xiàn)可以把霍夫變換換成滑動(dòng)窗口搜索這也是很多車道線檢測(cè)教程里提到的進(jìn)階做法。核心思路是先對(duì) ROI 內(nèi)的邊緣圖做垂直投影找到左右車道線的起始 x 位置然后從畫面底部往上逐層開窗每層窗口內(nèi)取非零像素的均值作為下一層窗口中心最后用二次多項(xiàng)式擬合所有窗口中心點(diǎn)。def sliding_window_fit(binary_edges, nwindows9, margin80, minpix40): # 下半部分做垂直投影找左右車道線起點(diǎn) histogram np.sum(binary_edges[binary_edges.shape[0]//2:, :], axis0) midpoint histogram.shape[0] // 2 leftx_base np.argmax(histogram[:midpoint]) rightx_base np.argmax(histogram[midpoint:]) midpoint window_height binary_edges.shape[0] // nwindows nonzero binary_edges.nonzero() nonzeroy, nonzerox np.array(nonzero[0]), np.array(nonzero[1]) leftx_current, rightx_current leftx_base, rightx_base left_lane_inds, right_lane_inds [], [] for window in range(nwindows): # 每層窗口的上下邊界 win_y_low binary_edges.shape[0] - (window 1) * window_height win_y_high binary_edges.shape[0] - window * window_height # 左車道窗口 win_xleft_low leftx_current - margin win_xleft_high leftx_current margin # 右車道窗口 win_xright_low rightx_current - margin win_xright_high rightx_current margin # 收集窗口內(nèi)非零像素 good_left ((nonzeroy win_y_low) (nonzeroy win_y_high) (nonzerox win_xleft_low) (nonzerox win_xleft_high)).nonzero()[0] good_right ((nonzeroy win_y_low) (nonzeroy win_y_high) (nonzerox win_xright_low) (nonzerox win_xright_high)).nonzero()[0] left_lane_inds.append(good_left) right_lane_inds.append(good_right) # 窗口內(nèi)像素夠多就重新居中 if len(good_left) minpix: leftx_current int(np.mean(nonzerox[good_left])) if len(good_right) minpix: rightx_current int(np.mean(nonzerox[good_right])) # 用所有收集到的像素做二次擬合 left_fit np.polyfit(nonzeroy[np.concatenate(left_lane_inds)], nonzerox[np.concatenate(left_lane_inds)], 2) right_fit np.polyfit(nonzeroy[np.concatenate(right_lane_inds)], nonzerox[np.concatenate(right_lane_inds)], 2) return left_fit, right_fit邏輯說明histogram統(tǒng)計(jì)下半部分每一列的非零像素?cái)?shù)峰值位置就是車道線起點(diǎn)。nwindows9把畫面從下到上切成 9 層每層開一個(gè)寬度為2*margin的窗口窗口內(nèi)像素足夠就重新計(jì)算中心這樣窗口能跟著彎道走。最后polyfit用二次多項(xiàng)式擬合所有窗口內(nèi)的像素得到一條平滑曲線。參數(shù)說明nwindows越多彎道跟蹤越細(xì)但計(jì)算量越大9 是 720p 下的常用值。margin是窗口半寬80 像素對(duì)應(yīng)車道線寬度的大致范圍太窄會(huì)丟線太寬會(huì)把相鄰車道框進(jìn)來(lái)。minpix是窗口內(nèi)最少像素?cái)?shù)低于這個(gè)值就不更新中心防止噪聲把窗口帶偏。這套滑動(dòng)窗口比霍夫變換慢但彎道表現(xiàn)明顯更好適合對(duì)實(shí)時(shí)性要求不極端的場(chǎng)景。我自己調(diào)這套代碼的習(xí)慣是先把config.py里所有參數(shù)抄到一張紙上每改一個(gè)就在旁邊記下效果別一次改三個(gè)。車道線檢測(cè)的參數(shù)之間耦合很強(qiáng)Canny 閾值一動(dòng)Hough 的 threshold 就得跟著調(diào)。GUI 里的滑塊是給你快速試的但最終值一定要寫回配置文件不然下次跑又回到默認(rèn)值。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取