本文來自AI新媒體量子位(QbitAI)

找到馬路上的車道線,對于人類來說非常容易,但對計算機來說,一點陰影、反光、道路顔色的微小變化、或者車道線被部分遮擋,都會帶來很大的困難。
正在Udacity學習自動駕駛課程的Michael Virgo寫了兩篇部落格文章,介紹了如何建構檢測模型。
以下内容編譯自他的文章:
在Udacity無人車納米學位第一學期課程的五個項目中,有兩個是關于車道檢測的。
其中第一個項目介紹了一些基本的計算機視覺技術,如Canny邊緣檢測。
圖1:Canny邊緣檢測
第二個項目深入介紹了一種方法,稱為透視變換(perspective transformation),能将圖像中的某些點延伸到目标位置。根據透視原理,車輛視角拍攝的照片上,車道線會在遠方聚攏;而進行變換之後,我們會得到一張鳥瞰圖。
圖2:透視變換前後的圖像
在周遊圖像時,如暗色的道路變為亮色的車道線時,像素值會變化。在透視變換前,利用梯度和顔色門檻值得到一張二值圖像,當像素值高于門檻值時設定為1。在透視變換後,可在該圖像上運作滑動視窗,來計算特定車道線的多項式拟合曲線。
圖3:門檻值為S的二值圖像
圖4:原二值圖像和透視變換後的二值圖像
圖5:應用滑動視窗的二值圖像和輸出結果
這種技術效果看起來不錯,但實際存在很多限制。首先,透視變換操作會對相機有一些具體的要求,在變換前需要調正圖像,而且錄影機的安裝和道路本身的傾斜都會影響變換效果。其次,各種梯度和顔色門檻值隻在小部分情況下适用,故前面提到的計算機識别車道線的各種問題在這裡變得更加突出。最後,這種技術處理起來很慢:實作車道檢測功能的程式大約每秒能處理4.5幀(FPS),而汽車攝像頭的幀數可能會在30 FPS或以上。
圖6:車道檢測出錯的例子
我已經成功地應用深度學習技術完成了這兩個車道檢測項目,接下來我将對項目實作過程進行詳細介紹。
雖然目前有大量用于訓練自動駕駛技術的資料集産生,但大多數都沒有對圖像中的車道進行标注。我決定建立一個新的資料集,這是最關鍵的也是最耗時的一部分。為訓練深層神經網絡而針對性地建立新資料集,也是一個有趣且有意義的挑戰。
收集資料是很容易的。在我住處的周圍,有很多不同類型的道路可以開車去收集資料。根據我以往的項目經驗,一個各類資料平衡的資料集非常重要。我收集了高速公路、輔路、盤山路、夜晚和雨天的資料。在這個過程中,我利用手機拍攝了超過21,000幀視訊圖像。
在提取出所有圖檔幀後,我注意到了一個問題:在亮度高且開車速度較慢時視訊中的圖像品質較高,在高速公路夜間駕駛和雨中駕駛時視訊品質較為模糊,且這兩種情景下的圖像都存在很多問題。為了神經網絡能更好地學習相關資訊,我不得不檢查和篩選每張圖像。最終,訓練集的圖檔數量減少到14,000張,但仍然存在一些輕度模糊的圖像,希望不影響車道檢測的效果。
圖7:一張被删除掉的模糊圖像,但是車道檢測模型在該圖像上的實際效果很好。
為了标注資料集,我用了自己原來做過的一個計算機視覺算法,不是在輸出圖檔上标注預測的車道線位置,而是輸出六個多項式系數,以二次函數Ax2+Bx+C的形式來描述這兩條車道線。
但是,我希望深度神經網絡能具有更好的效果,是以我決定統一使用紅線來手動繪出真實的車道線,以便接下來可以使用紅色門檻值來更好地檢測車道線。我最初以為需要處理14000張圖像,但這将會花費太長時間,不切合實際;同時,如果在低速時多張相近的圖像同時存在,則預測模型的準确率可能會虛高。考慮到時間對資料集的影響,我決定從每10張圖像中抽取一張,進而建立了隻具有1400張訓練圖像的原始資料集。
圖8:由于最終的模型仍能在模糊的夜間圖像中檢測到車道線,看來這個方法提高了模型的魯棒性。
此後,我根據以往項目做法建立了一個程式,在道路圖像上使用了傳統的CV檢測模型,用拟合出的多項式,來重新繪制車道線。這種做法可以節省圖像處理的時間,但在我檢查實際效果時發現了一個明顯的問題:雖然我已經用大量彎曲道路的圖像來訓練這個傳統模型,但是仍然不能檢測到所有的車道線。在訓練集的1400張圖像中,大約有450張無法使用,出現問題的樣本主要是彎曲道路圖像。
然而,我意識到這是由于算法的滑動視窗機制,導緻這個模型本身存在問題。如果一條車道線在圖像邊緣停止了,原始的滑動視窗将沿着圖像邊緣垂直向上疊代,導緻該算法相信該線往該方向延伸。我們可以通過判斷滑動視窗是否觸及圖像邊緣來解決這一問題,如果滑動視窗觸及邊緣,且已在圖像裡疊代若幹步(這麼設定是防止模型開始時被誤判斷觸及邊緣),那麼滑動視窗就停止工作。
圖9:在彎曲道路圖像上建立一系列滑動視窗,前後處理效果對比
從圖裡看出,這個效果很好,故障率降低了一半,從原來的約450張減少到約225張。我想通過檢查标簽的實際分布情況來分析無法使用的剩下圖像。我通過直方圖來檢查六個系數的實際分布,結果顯示拟合曲線仍趨于直線。我還嘗試增大彎曲道路圖像的所占比例,但問題沒有解決:對于極其彎曲的道路,檢測出的車道仍然很筆直。
圖10:一個車道線系數的分布圖:明顯以直線為中心。
我借用了以前參加過的一個交通标志檢測項目的經驗。那個項目的資料集中,有些類别圖檔非常少,我對它們進行小幅度旋轉操作,增加了該類資料的比例,大大提高了準确率。
我再次使用這種方法,對于某一特定分布範圍之外的任何系數标簽,對圖像進行小幅度旋轉并同時保持相同的标簽。對于其中的三個系數,我大約各處理了400、100和30張圖像,部分圖檔可能進行了三次調整操作。
圖11:對部分圖像進行旋轉後,單個系數分布更為均勻。
在旋轉圖像後,每個系數的分布更為合理。當然,我還對資料集及标簽進行了一些快速預處理操作。訓練集的圖像從最初的720 x 1280以不同倍數縮小,并進行歸一化,有助于模型加快收斂。我也使了用sklearn庫中的StandardScaler函數來歸一化圖像标簽,歸一化時請確定儲存縮放資訊,因為在最後一步需要恢複操作。标簽歸一化後會降低訓練時的Loss值,但是繪制回到原始圖像後,最終的結果也提升不大。
你可能會想,接下來不采用透視變換方法了麼?是的,但是為了建立一個初始的模型結構,我想基于這個特定的資料集,将深度學習方法和傳統CV檢測模型的效果做對比。是以網絡輸入是做了透視變換後的道路圖像,在邏輯上,神經網絡可能更容易學習到相關參數。
在這裡,我使用了一個與行為克隆(Behavioral Cloning)項目中類似的模型結構,包括一個批歸一化(BN)層,接上多個卷積層、一個池化層、一個扁平層和多個全連接配接層。最終的全連接配接層的輸出大小為6,也就是要預測的車道線系數數量。我還使用Keras庫中ImageDataGenerator函數,主要通過旋轉、偏移高度和垂直翻轉來試圖增強模型的泛化能力,因為水準翻轉可能會誤導網絡去識别車道資訊。經過對模型結構、超參數和輸入圖像大小的微調後,該模型的效果不錯,但是對輸入輸出的透視變換操作極其依賴。總體來說,這個模型不能讓我滿意。
當我發現深度學習方法在這個模型上效果不錯時,我決定建立一個能在沒有進行透視變換的前提下檢測車道線的模型。我沿用了這個原來的結構,還添加了一個裁剪層,切除了輸入圖像的上三分之一。我認為,對于任何一張道路圖像,這部分會包含很少關于車道檢測的資訊。而且該模型經過訓練後輕松達到與透視變換模型相近的效果,是以我知道該模型的輸入圖像不必是經過透視變換後的資料集了。
在這一點上,我想将一些不同相機拍攝的額外資料輸入該模型,以解決相機的扭曲問題,是以我還使用了一些從Udacity其他項目中獲得的視訊資料集。然而,我們需要為新資料建立對應标簽,因為之前用于标記圖像的透視變換方法不适用于這些視訊。這也使我意識到了另一個大問題:圖像标簽本身就是鳥瞰圖中的多項式系數,就意味着在預測和繪制車道線後,仍然需要反向變換,恢複到原始圖像的視角。
這就導緻了該模型具有特殊性,僅能在我錄制的視訊中檢視車道檢測效果。我意識到該模型也許已經能正确地檢測車道,但是在後期預測中使用了透視變換,是以無法重制良好的視覺效果。我認為,該模型似乎在轉換視角上存在困難,是以可以通過檢視各層的激活情況,來判斷該模型是否已經學會檢測車道。
我很快找到了所需的keras-vis庫。keras-vis庫很好上手,隻需将訓練好的模型傳給對應函數,就可以傳回對應層的激活圖。這個函數一般在分類神經網絡中辨識各類特征,但在這裡我用來可視化多項式系數。
圖12:前幾個網絡層的激活圖(請注意裁剪層處于這些網絡層之前)
看到這些卷積神經網絡處理後的道路圖像,這是一件很有趣的事。雖然第一層的圖像效果看起來不錯,但是這種方法還存在一些問題。
首先,該模型在處理多張彎曲道路的圖像後,得到了車道的一條線。該模型已經學習到,兩條車道線之間存在聯系,因為在大多數情況下,車道線是互相平行的,是以如果識别出一條線,那就可以推理出另一條線的所在位置。可能是由于使用過生成器翻轉圖像,是以在處理天空部分時激活值大幅變化。該模型會把圖像中的天空誤定位為車道,是以如果想在原始視訊中标出車道,必須以某種方式删除這部分被錯誤激活的區域。
圖13:可視化深層網絡
第二個問題更加難解決。由于在彎曲道路的圖像中傾向于對單車道線和天空區域進行激活,在筆直道路的圖像中通常會激活圖檔底部的汽車本身,或者是汽車前方的區域,而不是标出車道的位置。我進一步增加了直道圖像的數量,檢測效果有時會變好。但是在彎道和直道之間,激活規律沒有任何一緻性,是以不能深入研究這種方法。
我還使用keras-vis庫嘗試了遷移學習(Transfer Learning)的方法。在之前的行為克隆項目中,我已經使一輛模拟車已經學會了根據訓練好的神經網絡呈現出的圖像來引導自動駕駛。這個我使用了超過20,000張圖像訓練得到的模型,會怎麼看待車道呢?
圖14:一張模拟車的輸入圖像
這個問題的答案是整條道路,因為Udacity模拟器裡沒有隔離出多條車道,但是我想知道我是否可以使用遷移學習來将模型的注意力集中在車道上。我希望利用這個項目20000張資料集的基礎上,添加一些用于車道檢測的新資料,并進行一些額外的訓練,希望能有更好的激活效果。在從該項目加載訓練模型之後,使用model.pop()函數移除了最終用于輸出轉向角的輸出層,并将其替換為輸出六個标簽系數。在訓練前,需要根據模型的輸入來調整輸入圖像的大小,否則不能正常運作。
經過一些額外的訓練與輸入自己的資料集,這個模型效果略有提升,從檢測整個道路,開始轉為識别車道線。但是,該模型仍然存在一緻性問題,如哪些圖像區域該被激活和對應的激活程度等等。
我感覺這些方法行不通,是以開始尋找一種新的方法。最近我看到一些小組在處理汽車拍攝的圖像時采取圖像分割的方法:将一個給定的圖像分成如道路、汽車、人行道和建築物等等多類對象。SegNet網絡是一種很有趣的圖像分割技術,在使用時可直接調用标準的模型結構。這種标準模型包含了帶有BN層和Relu激活層的卷積結構、上采樣層、池化層以及從中點到網絡輸出的反卷積層。這種方法沒有添加全連接配接層,就能直接建構出一個完全卷積神經網絡。
這似乎也是一個不錯的方法,但是車道線可能還會以錯誤的方式被繪制,為什麼不采用神經網絡來直接預測車道線本身?是以我調整一下,網絡的輸入仍是道路圖像,但輸出為經過繪制的車道線圖像。由于我是用綠線标出車道線的,我決定讓模型的輸出“過濾器”隻對RGB的“G”通道起作用。對于RB通道,使用了兩個空白過濾器,使相應圖像與原車道圖像結合。這種方法去除了水準翻轉圖像會對預測系數産生不良影響的擔憂,也加倍了資料集的樣本量。在使用這種方法預處理資料時,我可以同時翻轉道路圖像和車道圖像标簽。
圖15:作為新标簽的車道圖像
在這裡,我重新整理了資料集:
在原始資料集中有1,420張圖像(在10幀中取1幀操作後),并删除了227個不能合适标注的圖像;
在彎曲道路的視訊中,一共有1636張圖像,我從中挑選了568張圖像;
在Udacity正常項目裡給出的視訊中,又挑出了另外217張圖像;
上述總計1,978張圖像;
樣本量還太少,且各類分布不均勻,是以小幅度圖像旋轉後效果不好。在針對性調整後,得到了6,382張圖像;
再次通過水準翻轉,樣本量加倍,得到了12,764張圖檔。
隻要確定道路圖像、系數标簽和車道圖像标簽三者互相關聯,我仍然可以旋轉這些帶有這些新标簽的圖像,無需考慮各系數的分布情況。
由于我從沒使用過完全卷積神經網絡,是以我按照SegNet網絡結構來嚴格建構網絡。幸運的是,我可以用Keras庫快速建構,需要注意的是在添加反卷積層後,要確定網絡輸出圖像和輸入大小保持一緻。在池化層之後,我将輸入圖像的長寬比調整為80 x 160 x 3(原始寬高比為90 x 160 x 3),并完全鏡像前半部模型。因為所使用的池化層大小為2 x 2,如果輸入次元為90,很快就不能被2整除,導緻模型後半部分建構鏡像時出現問題。
圖16:SegNet網絡結構示意圖(從左到右)
在模型訓練時存在一些小問題,網絡過大導緻記憶體溢出,是以我為每個卷積層和反卷積層添加了BN層和Dropout層,這是減小網絡大小和防止過拟合的最有效方法。我在網絡的開頭設定了BN層,在網絡中添加了Dropout層。由于隻使用了“G”顔色通道,最終反卷積層的輸出大小為80 x 160,這樣更容易地與原始路面圖像比對。雖然我調小了輸入圖像,但是沒有大影響。我也将道路圖像标記除以255,進行歸一化,這能改善收斂時間和最終結果,但是意味着在預測後需要對輸出乘以255來恢複次元。
圖17:不同模型的效果對比
從視訊中可以看出,最終的預測效果不錯。但是該視訊已經被訓練過,是以實際效果可能會虛高。為了檢測實際效果,我們使用了車道檢測項目中的另一個測試視訊,發現該網絡對這個視訊的預測效果也很好。雖然在處理高速公路立交橋的陰影時存在小問題,但我們很高興用這個視訊證明了該模型的效果。此外,該模型比原有模型的處理速度更快,通常在GPU加速下每秒能處理25-29幀,實時可達到30 FPS。在沒有GPU加速時,其每秒5.5FPS的處理速度仍然比每秒為4.5 FPS的CV模型稍快一些。
圖18:傳統的CV模型與SegNet模型做對比,在這裡CV模型誤認為兩條車道線都在右邊。
這就是我利用深度學習實作車道檢測的全部過程。雖然不是很完美,但它比傳統的CV模型更強大。我們也嘗試在難度更大的測試視訊中識别車道線,從結果中發現了一些問題:在光線和陰影的過渡時或者當強光照到車窗時無法準确預測車道線。以下是我接下來改進模型的一些方向:
更多資料集。這是應用深度學習方法很重要的一點,通過擷取在不同條件下(如光線和陰影過渡時)和更多不同相機的資料,可以進一步提升該模型;
加入循環神經網絡(Recurrent Neural Network)。我認為如果結合RNN網絡強大的時間資訊預測能力,這将是一個非常棒的方法。接下來我将研究遞歸方法在定位方面的應用,希望能在這方面再建立一種新的車道檢測方法;
使用沒有或隻有一條車道線的道路資料集。因為在郊區或部分公路不會标記車道線,是以這種模型有更強的推廣性;
擴充模型,用來檢測更多的對象。類比于圖像分割,可以添加車輛和行人檢測的功能。上述模型隻使用了“G”通道,接下來我們可以使用但不限于“R”和“B”通道,這種方法可能會優于正常的圖像分割方法。
該項目的完整程式請檢視Github連結:
<a>https://github.com/mvirgo/MLND-Capstone</a>
【完】
本文作者:王小新
原文釋出時間:2017-05-15