自動駕駛

自動駕駛開發流程

實現一個智能駕駛系統,會有幾個層級:html

感知層 → 融合層 → 規劃層 → 控制層python

更具體一點爲:git

傳感器層 → 驅動層 → 信息融合層 → 決策規劃層 → 底層控制層github

 

各個層級之間都須要編寫代碼,去實現信息的轉化。算法

最基本的層級有如下幾類:採集及預處理、座標轉換、信息融合app

 

採集機器學習

傳感器跟咱們的PC或者嵌入式模塊通訊時,會有不一樣的傳輸方式。ide

好比咱們採集來自攝像機的圖像信息,有的是經過千兆網卡實現的通訊,也有的是直接經過視頻線進行通訊的。再好比某些毫米波雷達是經過CAN總線給下游發送信息的,所以咱們必須編寫解析CAN信息的代碼。函數

不一樣的傳輸介質,須要使用不一樣的協議去解析這些信息,這就是上文提到的「驅動層」性能

通俗地講就是把傳感器採集到的信息所有拿到,而且編碼成團隊可使用的數據。

 

預處理

傳感器的信息拿到後會發現不是全部信息都是有用的。

傳感器層將數據以一幀一幀、固定頻率發送給下游,但下游是沒法拿每一幀的數據去進行決策或者融合的。爲何?

由於傳感器的狀態不是100%有效的,若是僅根據某一幀的信號去斷定前方是否有障礙物(有多是傳感器誤檢了),對下游決策來講是極不負責任的。所以上游須要對信息作預處理,以保證車輛前方的障礙物在時間維度上是一直存在的,而不是一閃而過。

這裏就會使用到智能駕駛領域常用到的一個算法——卡爾曼濾波。

 

座標轉換

座標轉換在智能駕駛領域十分重要。

傳感器是安裝在不一樣地方的,好比毫米波(上圖中紫色區域)是佈置在車輛前方的;當車輛前方有一個障礙物,距離這個毫米波雷達有50米,那麼咱們就認爲這個障礙物距離汽車有50米嗎?

不是的!由於決策控制層作車輛運動規劃時,是在車體座標系下完成的(車體座標系通常之後軸中心爲O點),所以毫米波雷達檢測到的50米,轉換到自車座標系下,還須要加上傳感器到後軸的距離。最終全部傳感器的信息,都是須要轉移到自車座標系下的,這樣全部傳感器信息才能統一,供規劃決策使用。

同理,攝像機通常安裝在擋風玻璃下面,拿到的數據也是基於攝像機座標系的,給下游的數據,一樣須要轉換到自車座標系下。

自車座標系:拿出你的右手,以大拇指 → 食指 → 中指 的順序開始念 X、Y、Z

而後把手握成以下形狀:

把三個軸的交點(食指根部)放在汽車後軸中心,Z軸指向車頂,X軸指向車輛前進方向。

各個團隊可能定義的座標系方向不一致,只要開發團隊內部統一便可。

 

信息融合

信息融合是指把相同屬性的信息進行多合一操做。

好比攝像機檢測到了車輛正前方有一個障礙物,毫米波也檢測到車輛前方有一個障礙物,激光雷達也檢測到前方有一個障礙物,而實際上前方只有一個障礙物,因此咱們要作的是把多傳感器下這輛車的信息進行一次融合,以此告訴下游,前面有一輛車,而不是三輛車。

固然,信息融合中還涉及時延的補償,具體以下:

對於一些大容量數據,確實不能以很高的頻率發送(好比10Hz,100ms才發送一次)。這樣的數據對高速行駛中的汽車來講,確定會有誤差。

這些誤差咱們算一下:

傳感器檢測到前方有一個靜止障礙物,我100ms以後收到了這個傳感器的信息,告訴我這個障礙物離我有30m。若是自車這時正以60KM/h的速度行駛,則這100ms,自車行駛了60 / 3.6 * 0.1 = 1.67m。

因此實際上這個障礙與個人距離爲31.67m。

因此面對通訊中產生的時延問題,尤爲是低頻率的信息,必定要考慮時延產生的後果。

時延補償的另一個問題:程序處理時,不能保證任什麼時候候都是按固定的頻率發送的。

這取決於硬件系統當時的環境,可能溫度高了,性能降低,處理速度變慢,10Hz 的發送頻率變成了 8Hz。若是咱們的程序仍是按固定的100ms去計算時延致使的誤差,一定會出現計算錯誤的狀況。

所以咱們須要引入時間戳,即在咱們發送的信息中加入當前的系統時間,經過兩幀數據的時間差來判斷接受到的信號到底延時了多久,這種方式比根據頻率判斷來得更準確。

 

決策規劃

這一層次主要設計的是拿到融合數據後,如何正確作規劃。

規劃包含縱向控制和橫向控制。

縱向控制即速度控制,表現爲 何時加速,何時制動。

橫向控制即行爲控制,表現爲 何時換道,何時超車等。

我的對這一塊不是很瞭解,不敢妄做評論。

 

 

 

從零開始學習無人駕駛技術 --- 車道檢測

前言

我的興趣愛好,最近在學習一些無人駕駛相關的技術,便萌生了按部就班的寫一系列文章的想法,這是第一篇。文章主要會以Udacity爲主線,綜合本身在學習過程當中蒐集的各類材料,取其精華,補其不足,力求通俗易懂,理論明確,實戰有效,即做爲一個學習總結,potentially又能夠幫助對無人駕駛有興趣可是零基礎的朋友們 —— 注意這裏的零基礎是指未接觸過無人駕駛領域,本系列仍是須要一些簡單的數學和機器學習知識。

由於本文是從零開始的第一篇,這裏的車道檢測是基礎版本,須要知足幾個先決條件:(1)無人車保持在同車道的高速路中行駛(2)車道線清晰可見(3)無人車與同車道內前車保持足夠遠的距離。

TLDR (or the take-away)

一個基礎版的車道檢測步驟主要分爲如下幾點:

  • Gray Scale Transformation
  • Gaussian Smoothing
  • Canny Edge Detection
  • ROI (Region of Interest) Based Edge Filtering
  • Hough Transformation
  • Lane Extrapolation

代碼:Github連接

最後的效果以下視頻所示,其中紅線表示自動檢測到的車道。

車道檢測基礎版 - 騰訊視頻

從圖片開始談起

無人車每每配備有數個camera,常見的狀況是有一個camera固定在車的前方,用來perceive前方道路狀況,生成視頻。計算機對該視頻進行分析,綜合其餘sensor的信息,對車輛行爲進行指導。視頻是由圖片組成,若是可以成功檢測圖片上的車道,那咱們就幾乎解決了車道檢測問題。下面是一張車輛行駛過程當中的圖片,讓咱們動手吧!

import matplotlib.image as mplimg img = mplimg.imread('lane.jpg') 

Gray Scale Transformation

這個變換比較簡單,是將RGB圖片轉換成灰度圖片,用來做爲Canny Edge Detection的輸入。

import cv2 gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) # Note that if you use cv2.imread() to read image, the image will # be in format BGR. 

Gaussian Smoothing

Gaussian Smoothing是對圖片apply一個Gaussian Filter,能夠起到模糊圖片和消除噪聲的效果。其基本原理是從新計算圖片中每一個點的值,計算時取該點及其附近點的加權平均,權重符合高斯分佈。下圖左側展現了一個kernel_size = 5的Gaussian Filter,55是高斯分佈的中心點,341是網格中全部值的和。假設網格矩陣爲,圖片爲,新圖片爲,則:

I'_{ij} = \frac{1}{341}\sum^{i+2}_{m = i-2}\ \sum^{j+2}_{n=j-2} Q_{mn} I_{mn}

Gaussian Filter是一種低經過濾器,可以抑制圖片中的高頻部分,而讓低頻部分順利經過。那什麼是圖片的高頻部分呢?下圖給出了一個比較極端的例子。愛好攝影的朋友們都知道相機ISO適當時可以獲得右側圖片,畫質細膩;若是ISO過大,就會致使產生左側圖片,畫質差,噪點多。這些噪點就是圖片中的高頻部分,表示了像素值劇烈升高或下降。

介紹完了Gaussian Filter,如今能夠將其應用到咱們的灰度圖片上:

blur_ksize = 5 # Gaussian blur kernel size blur_gray = cv2.GaussianBlur(gray, (blur_ksize, blur_ksize), 0, 0) 


Canny Edge Detection

John F. Canny在1986年發明了Canny Edge Detection技術,其基本原理是對圖片中各個點求gradient,gradient較大的地方每每是edge。Canny Edge Detection精妙的地方在於它有兩個參數:low_threshold和high_threshold。算法先比較gradient與這兩個threshold的關係,若是gradient > high_threshold,就認可這是一個edge point;若是gradient < low_threshold,就判定這不是edge point;對於其餘的點,若是與edge point相鏈接,那麼這個點被認爲也是edge point,不然不是。

canny_lthreshold = 50 # Canny edge detection low threshold canny_hthreshold = 150 # Canny edge detection high threshold edges = cv2.Canny(blur_gray, low_threshold, high_threshold) 

ROI Based Edge Filtering

Woohoo! It's awesome! 通過了Canny Edge Detection,咱們發現物體的輪廓都被檢測到了!可是彷佛東西有點兒太多了… 不要緊,還有一個重要的條件沒有用:camera相對於車是固定的,而無人車相對於車道的左右位置也是基本固定的,因此車道在camera視頻中基本保持在一個固定區域內!據此咱們能夠畫出一個大概的Region of Interest (ROI),過濾掉ROI以外的edges。

def roi_mask(img, vertices): mask = np.zeros_like(img) mask_color = 255 cv2.fillPoly(mask, vertices, mask_color) masked_img = cv2.bitwise_and(img, mask) return masked_img roi_vtx = np.array([[(0, img.shape[0]), (460, 325), (520, 325), (img.shape[1], img.shape[0])]]) roi_edges = roi_mask(edges, roi_vtx) 

Hough Transformation

目前看起來咱們彷佛已經獲得了車道線了呢,然而…並無! 由於最終目標是獲得exactly兩條直線!而目前如今圖中不只有多條線,還有一些點狀和塊狀區域,Hough Transformation的目的就是找到圖中的線。

下圖中左側是image space,中間和右側是Hough space。先看左側和中間的圖(右側圖見本節備註),image space中的一個點對應Hough space的一條線;image space中的兩個點()對應Hough space的兩條相交線,且交點對應的線必通過image space的這兩個點。

那麼,若是Hough space中有多條線相交於一點,則在image space中對應的那些點應位於同一條線上,例如:

在實際操做中,咱們每每將Hough space劃分爲網格狀,若是通過一個格子的線的數目大於某threshold,咱們認爲這個通過這個格子的線在原image space對應的點應在同一條線上。具有了這些知識,咱們能夠用Hough Transformation來找線啦!

# Hough transform parameters rho = 1 theta = np.pi / 180 threshold = 15 min_line_length = 40 max_line_gap = 20 def draw_lines(img, lines, color=[255, 0, 0], thickness=2): for line in lines: for x1, y1, x2, y2 in line: cv2.line(img, (x1, y1), (x2, y2), color, thickness) def hough_lines(img, rho, theta, threshold, min_line_len, max_line_gap): lines = cv2.HoughLinesP(img, rho, theta, threshold, np.array([]), minLineLength=min_line_len, maxLineGap=max_line_gap) line_img = np.zeros((img.shape[0], img.shape[1], 3), dtype=np.uint8) draw_lines(line_img, lines) return line_img line_img = hough_lines(roi_edges, rho, theta, threshold, min_line_length, max_line_gap) 

備註:若是image space中兩個點,則其造成的直線斜率無限大,沒法用中間的圖表示,能夠採用右側的極座標表示方式。

Lane Extrapolation

Almost there! 如今咱們要根據獲得的線計算出左車道和右車道,一種能夠採用的步驟是:

  1. 根據斜率正負劃分某條線屬於左車道或右車道
  2. 分別對左右車道線移除outlier:迭代計算各條線的斜率與斜率均值的差,逐一移除差值過大的線
  3. 分別對左右車道線的頂點集合作linear regression,獲得最終車道。

由於這部分代碼有點兒多,就不貼在這裏了,請參見個人Github代碼。結果以下:

最最後,咱們將結果和原圖疊加:

cv2.addWeighted(img, 0.8, line_img, 1, 0) 

圖片任務完成!

回到視頻上

如今咱們將前面的代碼打個包放到叫process_an_image的函數中,而後

from moviepy.editor import VideoFileClip output = 'video_1_sol.mp4' clip = VideoFileClip("video_1.mp4") out_clip = clip.fl_image(process_an_image) out_clip.write_videofile(output, audio=False) 

將代碼應用到三個不一樣的video上,看看結果!

車道檢測基礎版 - 騰訊視頻

車道檢測基礎版2 - 騰訊視頻

車道檢測基礎版3 - 騰訊視頻

注意:對於不一樣的狀況,有些參數可能須要調節,第三個視頻的處理須要一些額外的操做,會在個人Github代碼中有具體描述。

參考資料

1. High ISO Noise Reduction

2. Gaussian Smoothing

相關文章
相關標籤/搜索