訂閱
糾錯
加入自媒體

利用Python+OpenCV實現(xiàn)自動駕駛汽車的車道線檢測

對于所有想知道如何在一篇文章中涵蓋這一概念的人,我想說,在你深入探索之前,事情聽起來很復(fù)雜。我不會說這篇文章非常簡單,但是它的確是建立在非;A(chǔ)的計算機視覺概念之上的。
先決條件是什么?具備一些基本的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
這是我們應(yīng)用Canny邊緣檢測后的輸出結(jié)果

檢測Canny邊緣后輸出步驟2:定義ROI(感興趣區(qū)域)駕駛時,為了讓汽車保持在車道上,你只關(guān)注當前道路的下一個100米。而且,你也不關(guān)心護欄另一邊的路。這就是我們感興趣的區(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)建一個面具在我們的原始圖像上應(yīng)用蒙版,得到只有我們的ROI的裁剪圖像。

原始圖像+蒙版=具有ROI的最終圖像這一步的輸出類似于:

getROI ()之后的輸出在得到感興趣區(qū)域之前進行邊緣檢測是很重要的,否則邊緣檢測也會檢測出我們感興趣區(qū)域的邊界。步驟3:獲取圖像中的所有直線下一步是通過ROI得到圖像中的所有直線。houghlinesp()可以幫助你實現(xiàn)這一點。這個函數(shù)返回它能在輸入圖像中找到的所有直線的列表。每一行用[x1, y1, x2, y2]表示,F(xiàn)在,這看起來很簡單,但是houghlinesp檢測的基本工作原理需要一點時間來解釋。所以我不會在本文中介紹它。相反,我建議你看一看此教程(#28,#29,#30應(yīng)該足以理解霍夫直線原則)。教程: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)試最適合你的)。但我認為以上這些應(yīng)該在大多數(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)意識到你可以如何巧妙地使用非常基本的計算機視覺操作來實現(xiàn)如此有用的東西。我想說的是,不要把這項工作與特斯拉這樣的大公司做的比較(他們的基礎(chǔ)也是類似的)。把這作為動力,也許在某個時候,你也能取得類似的成就。
END 

聲明: 本文由入駐維科號的作者撰寫,觀點僅代表作者本人,不代表OFweek立場。如有侵權(quán)或其他問題,請聯(lián)系舉報。

發(fā)表評論

0條評論,0人參與

請輸入評論內(nèi)容...

請輸入評論/評論長度6~500個字

您提交的評論過于頻繁,請輸入驗證碼繼續(xù)

暫無評論

暫無評論

人工智能 獵頭職位 更多
掃碼關(guān)注公眾號
OFweek人工智能網(wǎng)
獲取更多精彩內(nèi)容
文章糾錯
x
*文字標題:
*糾錯內(nèi)容:
聯(lián)系郵箱:
*驗 證 碼:

粵公網(wǎng)安備 44030502002758號