1. 程式人生 > >無人駕駛之車道線檢測簡易版

無人駕駛之車道線檢測簡易版

這裡寫圖片描述

無人駕駛技術近些年發展迅速。無人車若想實現自動駕駛,從視覺的角度上講其要先學會觀察道路,具體來說,就是檢測車道線。包括識別車道線與車的位置關係,是實線還是虛線等。本文將簡單介紹車道線檢測的基本技術,包括Canny EdgesHough Transform等。

Pipe Line

本文進行車道線檢測的pipe line如下,主要使用了opencv庫:

  1. RGB to GRAY
  2. Gauss Blur
  3. Canny Edges
  4. Hough Transform
  5. Dram Lines

示例如下:

原始圖片:
這裡寫圖片描述

灰度圖片:
這裡寫圖片描述

高斯模糊圖片:
這裡寫圖片描述

Canny Edges:
這裡寫圖片描述

多邊形擷取後的圖片:
這裡寫圖片描述

生成左右兩條線:
這裡寫圖片描述

和原圖結合的最終圖片:
這裡寫圖片描述

Gray

通常的彩色圖片是三通道的,簡便起見,對其做單通道處理,轉化為灰色影象。

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import cv2


# Read in and grayscale the image
image = mpimg.imread('image.jpg')
gray = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)

轉化的經驗公式如下,該公式是根據人眼中三種不同的感光細胞的感光強度按比例分配的:

Y0.299R+0.587G+0.114B

同時需要注意一點,從RGB到灰度影象本質上是建立了一個對映函式。對於確立好的對映函式,我們總能找到RGB空間中不同的點對映之後得到的點卻基本相同。理由也很簡單,從3通道到1通道肯定伴隨著資訊的損失。解決辦法是不固定對映函式,根據圖片做動態的對映函式。

Gauss Blur

高斯模糊就是用高斯核對圖片做卷積操作,大小為5的高斯核如下:

這裡寫圖片描述

  • 原理:重新計算圖片中每個點的值,計算的時候取該點與周圍點的加權平均,權重符合高斯分佈。
  • 作用:降低圖片噪聲和減少細節(增強圖片在不同scale下的structure),並保留邊界。同時Gauss FIlter是一種低通濾波器,只允許低頻部分通過,限制高頻部分(例如畫素值劇烈升高或降低的早點)。
  • 效果:像通過半透明的玻璃看圖片一樣。
# Define a kernel size and apply Gaussian smoothing
kernel_size = 5
blur_gray = cv2.GaussianBlur(gray,(kernel_size, kernel_size),0)

Canny Edges

高斯模糊

首先,緊接上面的高斯模糊,邊緣檢測通常對噪聲很敏感,所以在邊緣檢測前要用高斯模糊降噪,這樣單獨的一個畫素噪聲在經過高斯平滑後的影象上變得幾乎沒有任何影響。

計算梯度

邊緣檢測的本質是計算圖片在每個點的梯度(畫素值的變化情況),變化值越大表明是邊緣的概率越高。 計算梯度的時候使用了卷積,相關計算如下(方向約成【0、45、90、135】之間):

這裡寫圖片描述

Non-maximum suppression

計算完梯度後,需要進行thin the edge。方法是將每個畫素點的梯度值與梯度方向上的兩個點進行比較,當且僅當這個點的梯度值最大才保留,否則捨棄。(例如梯度方向是0度,那麼將當前梯度值與左右兩邊的梯度值進行比較,當且僅當當前梯度值最大才保留)

Double threshold

進行Non-maximum suppression後,仍然可能有部分誤標記的edge,這些誤標記的edge可能來自噪音或者顏色的變化。解決的辦法是設定兩個閾值low_threshold、high_threshold,當前point的梯度gradient與閾值的關係如下:

  • gradient < low_threshold:丟棄
  • gradient > high_threshold:保留
  • low_threshold < gradient < high_threshold: 當且僅當其存在相連點的梯度大於high_threshold才保留
# Define our parameters for Canny and apply
low_threshold = 50
high_threshold = 150
edges = cv2.Canny(blur_gray, low_threshold, high_threshold)

ROI(Region of Interest) Based Edge Filtering

通過Canny進行邊緣檢測獲得邊緣後,會發現,獲得的邊緣不僅包括需要的車道線邊緣,同時包括不需要的其他車道以及周圍圍欄的邊緣。去掉這些邊緣的辦法是確定一個多邊形的可視域,只保留可視域部分的邊緣資訊。其依據是camera相對車是固定的,車相對於車道的相對位置也基本固定,所以車道在camera中基本保持在一個固定區域內。

# Next we'll create a masked edges image using cv2.fillPoly()
mask = np.zeros_like(edges)   
ignore_mask_color = 255   

# This time we are defining a four sided polygon to mask
imshape = image.shape
vertices = np.array([[(50,imshape[0]),(420, 280), (550, 280), (950,imshape[0])]], dtype=np.int32)
cv2.fillPoly(mask, vertices, ignore_mask_color)
masked_edges = cv2.bitwise_and(edges, mask)

Hough Transform

簡介

霍夫變換一種特徵提取技術,檢測具有特定形狀的物體,通常是直線、圓、橢圓。

其原理是將原空間隱射到引數空間,在引數空間進行投票獲得所需的圖形。

例子

下面以檢測圖片中的直線為例簡單介紹霍夫變換。

原空間中的直線可以對映到引數空間中的點。C。
這裡寫圖片描述

原空間中的點可以對映到引數空間中的直線。A。
這裡寫圖片描述

原空間中的點可以對映到引數空間中的直線,引數空間中直線的交點代表原空間中點的連線。C。
這裡寫圖片描述

原空間中的直線可以對映到引數空間中的點,引數空間中兩個點的連線代表原空間中兩個直線的交點。A。
這裡寫圖片描述

如果用y=kx+b中的k、b作為引數空間中的引數,會遇到豎直線k無窮大的問題,所以採用極座標表示如下。
這裡寫圖片描述

採用極座標後,原空間的點對應引數空間的二次曲線,原空間的直線對應引數引數空間上的點。C。
這裡寫圖片描述

車道線

無論採用xy座標還是極座標,原空間的點都對應引數空間的曲線,原空間的直線都對應著引數空間中曲線的交點。如下圖所示,可以根據在引數空間中每個grid相交點的出現次數尋找原空間中的直線。
這裡寫圖片描述
這裡寫圖片描述

Hough變換的程式碼如下,其引數的含義見註釋

rho = 2 # distance resolution in pixels of the Hough grid
theta = np.pi/180 # angular resolution in radians of the Hough grid
threshold = 15     # minimum number of votes (intersections in Hough grid cell)
min_line_length = 40 #minimum number of pixels making up a line
max_line_gap = 20    # maximum gap in pixels between connectable line segments
line_image = np.copy(image)*0 # creating a blank to draw lines on

# Run Hough on edge detected image
lines = cv2.HoughLinesP(edges, rho, theta, threshold, np.array([]), min_line_length, max_line_gap)

Lane Extrapolation

通過Hough變換後,得到了很多直線,例如下圖:
這裡寫圖片描述

為了獲得左右各一條直線,如下圖,還需要額外的工作。
這裡寫圖片描述

這裡介紹一種比較簡單的方法:

  1. 將所有直線按照斜率分成左右兩部分。
  2. 每部分求平均或者median得到加權的直線引數。
  3. 根據原圖片的位置描繪出新引數的直線。

參考