項目背景
本項目是筆者希望基於駕駛模擬類遊戲 歐洲卡車模擬2(ETS2) 實現駕駛輔助系統的設想的一個基礎項目 車道識別
關於《歐洲卡車模擬2》
《歐洲卡車模擬2》是一款模擬經營類遊戲,在遊戲中玩家要駕駛卡車完成貨物運輸任務,並可以購買更多的車庫、卡車、掛車,從司機介紹所僱傭司機來爲你工作,組建自己的物流公司。遊戲中玩家可以改裝自己的卡車、掛車的幾乎每一個部件,從駕駛室到底盤到各種配件和內飾。穿越歐洲大陸,組建自己的運輸帝國。
項目基本思路
對於車道線檢測,首先需要使程序能夠檢測出單張圖片中的車道線,以此爲依據進一步拓展至視頻中的車道線檢測,並最終推至實時畫面中的車道線檢測。
對於單張圖片的車道線識別,我的思路如下:
我們默認攝像機在車內位置是不變的,因此路面在畫面中的位置大致是不變的,爲了降低噪聲影響,我們可以人爲選取路面位置作爲興趣區域,並對興趣區域進行邊緣檢測與直線識別操作,並最終輸出處理結果。
原圖
項目步驟
- 圖像灰度處理
- 高斯模糊降噪
- ROI興趣區域掩膜
- canny邊緣檢測
- 霍夫直線檢測
- 車道線擬合
- 圖像結果輸出
圖像灰度處理
將原有的RGB三維色彩信息處理爲一維的灰度值
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
灰度處理結果
高斯濾波
降低圖片噪聲值,便於邊緣檢測
blur_ksize = 7
blur_gray = cv2.GaussianBlur(gray, (blur_ksize, blur_ksize), 1)
濾波後結果
canny邊緣檢測
對圖片進行邊緣檢測,便於下一步的霍夫直線檢測
canny_lthreshold = 50
canny_hthreshold = 80
edges = cv2.Canny(blur_gray, canny_lthreshold, canny_hthreshold)
canny邊緣檢測結果
ROI興趣區域掩膜處理
通過人爲處理去除掉大部分的噪聲值,便於直線檢測
def roi_mask(img, np.array([[(0, 660), (0, img.shape[1]),(img.shape[1], img.shape[0]), (img.shape[1], 660) ,(1000, 560) ,(900, 560)]])):
# 生成roi目標區域,排除大部分無關噪聲值
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處理結果
霍夫直線檢測、判斷車道位置
通過霍夫變換將邊緣圖中的直線進行匹配,並在記錄車道位置
rho = 1
theta = np.pi / 180
threshold = 15
min_line_length = 100
max_line_gap = 40
def draw_lines(img, lines, color=[255, 0, 0], thickness=16):
# 畫線函數
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
車道標記結果
圖像結果輸出
將車道位置與原圖拼合,輸出結果
img_res = cv2.add(img,line_img)
最終處理結果
全部代碼
import matplotlib.pyplot as plt
import matplotlib.image as mplimg
import numpy as np
from cv2 import cv2
blur_ksize = 5 # Gaussian blur kernel size
canny_lthreshold = 50 # Canny edge detection low threshold
canny_hthreshold = 80 # Canny edge detection high threshold
# Hough transform parameters
rho = 1 #rho的步長,即直線到圖像原點(0,0)點的距離
theta = np.pi / 180 #theta的範圍
threshold = 15 #累加器中的值高於它時才認爲是一條直線
min_line_length = 150 #線的最短長度,比這個短的都被忽略
max_line_gap = 40 #兩條直線之間的最大間隔,小於此值,認爲是一條直線
def roi_mask(img, vertices):
# 生成roi目標區域,排除大部分無關噪聲值
mask = np.zeros_like(img)
mask_color = 255
cv2.fillPoly(mask, vertices, mask_color)
masked_img = cv2.bitwise_and(img, mask)
return masked_img
def draw_lines(img, lines, color=[255, 0, 0], thickness=16):
# 畫線函數
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
def img_rogress(img):
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
blur_gray = cv2.GaussianBlur(gray, (blur_ksize, blur_ksize), 1)
edges = cv2.Canny(blur_gray, canny_lthreshold, canny_hthreshold)
return edges
if __name__ == "__main__":
img = mplimg.imread("datapic/test (26).jpg")
roi_vtx = np.array([[(0, 660), (0, img.shape[1]),(img.shape[1], img.shape[0]), (img.shape[1], 660) ,(1000, 560) ,(900, 560)]])
pre_res = img_rogress(img)
roi_edges = roi_mask(pre_res,roi_vtx)
line_img = hough_lines(roi_edges, rho, theta, threshold,
min_line_length, max_line_gap)
img_res = cv2.add(img,line_img)
plt.imshow( img_res)
plt.show()
後記
經過後面的一系列探索,本方法存在很大的侷限性,未來將會更新另一種新的車道檢測方法。