利用Python+OpenCV實現(xiàn)自動駕駛汽車的車道線檢測
對于所有想知道如何在一篇文章中涵蓋這一概念的人,我想說,在你深入探索之前,事情聽起來很復雜。我不會說這篇文章非常簡單,但是它的確是建立在非常基礎的計算機視覺概念之上的。
先決條件是什么?具備一些基本的OpenCV知識會很好。如果沒有,請不要擔心,我將嘗試解釋我將使用的OpenCV函數(shù),并為你提供參考,以更詳細地檢查它們。本文的每一節(jié)將介紹一個最終將在程序的主要部分中使用的函數(shù)。此外,在本文中,我將使用圖像演示所有內(nèi)容。你可以重用相同的代碼來使用視頻(因為視頻只是圖像的集合)。
步驟1:邊緣檢測我們將使用Canny邊緣檢測。如果你不確定這是什么,看看我之前的文章,它以實用的方式解釋了這一點。https://medium.com/analytics-vidhya/image-simplification-through-binarization-in-opencv-1292d91cae12def canyEdgeDetector(image):
edged = cv2.Canny(image, 50, 150)
return edged
這是我們應用Canny邊緣檢測后的輸出結(jié)果
檢測Canny邊緣后輸出步驟2:定義ROI(感興趣區(qū)域)駕駛時,為了讓汽車保持在車道上,你只關注當前道路的下一個100米。而且,你也不關心護欄另一邊的路。這就是我們感興趣的區(qū)域。我們從圖像中隱藏不必要的細節(jié),只顯示能幫助我們找到車道的區(qū)域。
紅色的三角形表示我們感興趣的區(qū)域def getROI(image):
height = image.shape[0]
width = image.shape[1]
# Defining Triangular ROI: The values will change as per your camera mounts
triangle = np.a(chǎn)rray([[(100, height), (width, height), (width-500, int(height/1.9))]])
# creating black image same as that of input image
black_image = np.zeros_like(image)
# Put the Triangular shape on top of our Black image to create a mask
mask = cv2.fillPoly(black_image, triangle, 255)
# applying mask on original image
masked_image = cv2.bitwise_and(image, mask)
return masked_image
我們已經(jīng)定義了三角形ROI,它的坐標將根據(jù)你安裝在你的汽車上的攝像頭的位置而變化(嘗試只擁有那部分圖像,這將實際有助于車道檢測)。我們創(chuàng)建了一個與原始圖像相同形狀的黑色圖像:
創(chuàng)建一個與原始圖像相同形狀的黑色圖像創(chuàng)建蒙版:然后使用cv2.fillPoly()將我們的三角形(帶白色線條)放在我們的黑色圖像的頂部,創(chuàng)建一個蒙版。
創(chuàng)建一個面具在我們的原始圖像上應用蒙版,得到只有我們的ROI的裁剪圖像。
原始圖像+蒙版=具有ROI的最終圖像這一步的輸出類似于:
getROI ()之后的輸出在得到感興趣區(qū)域之前進行邊緣檢測是很重要的,否則邊緣檢測也會檢測出我們感興趣區(qū)域的邊界。步驟3:獲取圖像中的所有直線下一步是通過ROI得到圖像中的所有直線。houghlinesp()可以幫助你實現(xiàn)這一點。這個函數(shù)返回它能在輸入圖像中找到的所有直線的列表。每一行用[x1, y1, x2, y2]表示,F(xiàn)在,這看起來很簡單,但是houghlinesp檢測的基本工作原理需要一點時間來解釋。所以我不會在本文中介紹它。相反,我建議你看一看此教程(#28,#29,#30應該足以理解霍夫直線原則)。教程:https://www.youtube.com/watch?v=7m-RVJ6ABsYdef getLines(image):
lines = cv2.HoughLinesP(image, 0.3, np.pi/180, 100, np.a(chǎn)rray([]), minLineLength=70, maxLineGap=20)
return lines
必須根據(jù)你的需求調(diào)整cv2.HoughLinesP()的參數(shù)(嘗試更改和調(diào)試最適合你的)。但我認為以上這些應該在大多數(shù)情況下都適用。這一步的輸出是這樣的:
在圖像中檢測到3條線。圖像中可能檢測到數(shù)百條線。因此,調(diào)整參數(shù)以獲得盡可能少的線步驟4:一些實用函數(shù)下面的實用函數(shù)獲取圖像和線條列表,并在圖像上繪制線條。(這個步驟沒有從步驟3獲取任何輸入。相反,這只是一個將從Step5調(diào)用的實用程序步驟,因此你首先查看Step5并在需要時訪問該步驟)。def displayLines(image, lines):
if lines is not None:
for line in lines:
x1, y1, x2, y2 = line.reshape(4) #converting to 1d array
cv2.line(image, (x1, y1), (x2, y2), (255, 0, 0), 10)
return image
我們定義了另一個實用函數(shù)來從它的參數(shù)(斜率和截距)得到線坐標。記住,直線用y=mx+c表示,其中m是斜率,c是截距。def getLineCoordinatesFromParameters(image, line_parameters):
slope = line_parameters[0]
intercept = line_parameters[1]
y1 = image.shape[0] # since line will always start from bottom of image
y2 = int(y1 * (3.4 / 5)) # some random point at 3/5
x1 = int((y1 - intercept) / slope)
x2 = int((y2 - intercept) / slope)
return np.a(chǎn)rray([x1, y1, x2, y2])
注意我們是如何選擇y和y的值的步驟5:平滑線條一旦我們從步驟3中獲得了直線,在這一步中我們將這些直線分成兩組(左邊和右邊)。如果你注意到步驟3的輸出圖像,那么該步驟將把Line1和line2放到左邊的組中,而Line3放到右邊的組中。
如何在車道的左側(cè)和右側(cè)獲得一條公共線分組后,我們找到該組的平均斜率(m)和截距(c),并通過調(diào)用getLineCoordinatesFromParameters() 并傳遞平均值m和平均值c來為每個組創(chuàng)建一條線。下面是完成這一切的函數(shù):def getSmoothLines(image, lines):
left_fit = [] # will hold m,c parameters for left side lines
right_fit = [] # will hold m,c parameters for right side lines
for line in lines:
x1, y1, x2, y2 = line.reshape(4)
parameters = np.polyfit((x1, x2), (y1, y2), 1)
slope = parameters[0]
intercept = parameters[1]
if slope < 0:
left_fit.a(chǎn)ppend((slope, intercept))
else:
right_fit.a(chǎn)ppend((slope, intercept))
left_fit_average = np.a(chǎn)verage(left_fit, axis=0)
right_fit_average = np.a(chǎn)verage(right_fit, axis=0)
# now we have got m,c parameters for left and right line, we need to know x1,y1 x2,y2 parameters
left_line = getLineCoordinatesFromParameters(image, left_fit_average)
right_line = getLineCoordinatesFromParameters(image, right_fit_average)
return np.a(chǎn)rray([left_line, right_line])
這是線條分組后的圖像:
線分組后輸出主代碼(逐一調(diào)用上述步驟)一旦我們準備好了各個函數(shù),我們只需要在我們的主代碼中調(diào)用它們,你就會在你的圖像中檢測到車道。image = cv2.imread("3.jpg") #Load Image
edged_image = canyEdgeDetector(image) # Step 1
roi_image = getROI(edged_image) # Step 2
lines = getLines(roi_image) # Step 3
smooth_lines = getSmoothLines(image, lines) # Step 5
image_with_smooth_lines = displayLines(image, smooth_lines) # Step 4
cv2.imshow("Output", image_with_smooth_lines)
cv2.waitKey(0)
輸出會像這樣:
具有確定車道的最最后的話終輸出你一直看到文章的結(jié)尾。對所有內(nèi)容進行排序并使其適合圖像后,你便知道如何將其用于視頻。你可能已經(jīng)意識到你可以如何巧妙地使用非;镜挠嬎銠C視覺操作來實現(xiàn)如此有用的東西。我想說的是,不要把這項工作與特斯拉這樣的大公司做的比較(他們的基礎也是類似的)。把這作為動力,也許在某個時候,你也能取得類似的成就。
END
請輸入評論內(nèi)容...
請輸入評論/評論長度6~500個字
最新活動更多
-
10月31日立即下載>> 【限時免費下載】TE暖通空調(diào)系統(tǒng)高效可靠的組件解決方案
-
即日-11.13立即報名>>> 【在線會議】多物理場仿真助跑新能源汽車
-
11月28日立即報名>>> 2024工程師系列—工業(yè)電子技術在線會議
-
12月19日立即報名>> 【線下會議】OFweek 2024(第九屆)物聯(lián)網(wǎng)產(chǎn)業(yè)大會
-
即日-12.26火熱報名中>> OFweek2024中國智造CIO在線峰會
-
即日-2025.8.1立即下載>> 《2024智能制造產(chǎn)業(yè)高端化、智能化、綠色化發(fā)展藍皮書》
推薦專題
- 高級軟件工程師 廣東省/深圳市
- 自動化高級工程師 廣東省/深圳市
- 光器件研發(fā)工程師 福建省/福州市
- 銷售總監(jiān)(光器件) 北京市/海淀區(qū)
- 激光器高級銷售經(jīng)理 上海市/虹口區(qū)
- 光器件物理工程師 北京市/海淀區(qū)
- 激光研發(fā)工程師 北京市/昌平區(qū)
- 技術專家 廣東省/江門市
- 封裝工程師 北京市/海淀區(qū)
- 結(jié)構工程師 廣東省/深圳市