基于openCV的車道線識(shí)別

彭安旭

學(xué)號(hào)17020199032

轉(zhuǎn)載自https://zhuanlan.zhihu.com/p/52623916

【嵌牛導(dǎo)讀】自動(dòng)駕駛汽車依靠人工智能秸歧、視覺計(jì)算趾诗、雷達(dá)、監(jiān)控裝置和全球定位系統(tǒng)協(xié)同合作,讓電腦可以在沒有任何人類主動(dòng)的操作下矾削,自動(dòng)安全地操作機(jī)動(dòng)車輛郎逃。其中哥童,計(jì)算機(jī)視覺在整個(gè)自動(dòng)駕駛中占有很大的比重。而下面要探討的車道線識(shí)別褒翰,即為最基礎(chǔ)的智能識(shí)別贮懈。

【嵌牛鼻子】模式識(shí)別 計(jì)算機(jī)視覺

【嵌牛提問】如何初步實(shí)現(xiàn)自動(dòng)駕駛過程中的車道線識(shí)別?

【嵌牛正文】 

在介紹計(jì)算機(jī)視覺技術(shù)前优训,我想先討論一下這次分享的輸入和輸出朵你。

輸入

一張攝像機(jī)拍攝到的道路圖片,圖片中需要包含車道線揣非。如下圖所示抡医。

輸入圖像


圖片出處:https://github.com/udacity/CarND-LaneLines-P1/blob/master/test_images/whiteCarLaneSwitch.jpg

輸出

圖像坐標(biāo)系下的左右車道線的直線方程和有效距離。將左右車道線的方程繪制到原始圖像上早敬,應(yīng)如下圖所示忌傻。

輸出結(jié)果


在輸入和輸出都定義清楚后,我們就開始使用計(jì)算機(jī)視覺技術(shù)搞监,一步步完成對(duì)原始圖像的處理水孩。

原始圖像

認(rèn)識(shí)圖像前,我們需要先回顧一下在初中所學(xué)的物理知識(shí)——光的三原色琐驴,光的三原色分別是紅色(Red)俘种、綠色(Green)和藍(lán)色(Blue)。通過不同比例的三原色組合形成不同的可見光色绝淡。如下圖所示宙刘。

光的三原色

圖片出處:https://zhidao.baidu.com/question/197911511.html

圖像中的每個(gè)像素點(diǎn)都是由RGB(紅綠藍(lán))三個(gè)顏色通道組成。為了方便描述RGB顏色模型够委,在計(jì)算機(jī)中約束了每個(gè)通道由暗到亮的范圍是0~255荐类。

當(dāng)某個(gè)像素點(diǎn)的R通道數(shù)值為255,G和B通道數(shù)值為0時(shí)茁帽,實(shí)際表現(xiàn)出的顏色就是最亮的紅色玉罐;當(dāng)某個(gè)像素點(diǎn)的RGB三通道都為255時(shí),所表示的是最亮的白色潘拨;當(dāng)某個(gè)像素點(diǎn)的RGB三通道都為0時(shí)吊输,就會(huì)顯示最暗的黑色。在RGB顏色模型中铁追,不會(huì)有比[255,255,255]的組合更亮的顏色了季蚂。

根據(jù)以上理論基礎(chǔ),一幅彩色圖像,其實(shí)就是由三幅單通道的圖像疊加扭屁,如下圖所示算谈。

圖片發(fā)自簡書App

圖片出處:優(yōu)達(dá)學(xué)城(Udacity)無人駕駛工程師學(xué)位

以基于python的OpenCV為例,讀取名為test_img.jpg的圖片到計(jì)算機(jī)內(nèi)存中的代碼如下:

import cv2

img = cv2.imread('image_name.jpg')

讀取圖像后料滥,我們可以將圖像看做一個(gè)二維數(shù)組然眼,每個(gè)數(shù)組元素中存了三個(gè)值,分別是RGB三個(gè)通道所對(duì)應(yīng)的數(shù)值葵腹。

OpenCV定義了高每,圖像的原點(diǎn)(0,0)在圖片的左上角践宴,橫軸為X鲸匿,朝右,縱軸為Y阻肩,朝下带欢,如下圖所示。

原始圖像


需要注意的是烤惊,由于OpenCV的早期開發(fā)者習(xí)慣于使用BGR順序的顏色模型洪囤,因此使用OpenCV的imread()讀到的像素,每個(gè)像素的排列是按BGR撕氧,而不是常見的RGB,代碼編寫時(shí)需要注意喇完。

灰度處理

考慮到處理三個(gè)通道的數(shù)據(jù)比較復(fù)雜伦泥,我們先將圖像進(jìn)行灰度化處理,灰度化的過程就是將每個(gè)像素點(diǎn)的RGB值統(tǒng)一成同一個(gè)值锦溪〔桓灰度化后的圖像將由三通道變?yōu)閱瓮ǖ溃瑔瓮ǖ赖臄?shù)據(jù)處理起來就會(huì)簡單許多刻诊。

通常這個(gè)值是根據(jù)RGB三通道的數(shù)值進(jìn)行加權(quán)計(jì)算得到防楷。人眼對(duì)RGB顏色的敏感度不同,對(duì)綠色最敏感则涯,權(quán)值較高复局,對(duì)藍(lán)色最不敏感,權(quán)值較低粟判。坐標(biāo)為(x,y)的像素點(diǎn)進(jìn)行灰度化操作的具體計(jì)算公式如下:

圖片發(fā)自簡書App圖像灰度處理計(jì)算公式


調(diào)用OpenCV中提供的cvtColor()函數(shù)亿昏,能夠方便地對(duì)圖像進(jìn)行灰度處理

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 由于使用cv2.imread()讀到的img的數(shù)據(jù)排列為BGR,因此這里的參數(shù)為BGR2GRAY

灰度處理后的圖像如下圖所示:

灰度處理


邊緣提取

為了突出車道線档礁,我們對(duì)灰度化后的圖像做邊緣處理角钩。“邊緣”就是圖像中明暗交替較為明顯的區(qū)域。車道線通常為白色或黃色递礼,地面通常為灰色或黑色惨险,因此車道線的邊緣處會(huì)有很明顯的明暗交替。

常用的邊緣提取算法有Canny算法和Sobel算法脊髓,它們只是計(jì)算方式不同辫愉,但實(shí)現(xiàn)的功能類似」┝叮可以根據(jù)實(shí)際要處理的圖像一屋,選擇算法。哪種算法達(dá)到的效果更好袋哼,就選哪種冀墨。

以Canny算法為例,選取特定的閾值后涛贯,對(duì)灰度圖像進(jìn)行處理诽嘉,即可得到的邊緣提取的效果圖。

low_threshold = 40

high_threshold = 150

canny_image = cv2.Canny(gray, low_threshold, high_threshold)

Canny邊緣提取



感興趣區(qū)域選擇

邊緣提取完成后弟翘,需要檢測的車道線被凸顯出來了虫腋。為了實(shí)現(xiàn)自車所在車道的車道線檢測,我們需要將感興趣的區(qū)域(Region of Interest)提取出來稀余。提取感興趣區(qū)域最簡單的方式就是“截取”悦冀。

首先選定一個(gè)感興趣區(qū)域,比如下圖所示的藍(lán)色三角形區(qū)域睛琳。對(duì)每個(gè)像素點(diǎn)的坐標(biāo)值進(jìn)行遍歷盒蟆,如果發(fā)現(xiàn)當(dāng)前點(diǎn)的坐標(biāo)不在三角區(qū)域內(nèi),則將該點(diǎn)涂“黑”师骗,即將該點(diǎn)的像素值置為0历等。

感興趣區(qū)域選定


為了實(shí)現(xiàn)截取功能,可以封裝一下OpenCV的部分函數(shù)辟癌,定義一個(gè)region_of_interest函數(shù):

def region_of_interest(img, vertices):

? ? #定義一個(gè)和輸入圖像同樣大小的全黑圖像mask寒屯,這個(gè)mask也稱掩膜

? ? #掩膜的介紹,可參考:https://www.cnblogs.com/skyfsm/p/6894685.html

? ? mask = np.zeros_like(img)?

? ? #根據(jù)輸入圖像的通道數(shù)黍少,忽略的像素點(diǎn)是多通道的白色寡夹,還是單通道的白色

? ? if len(img.shape) > 2:

? ? ? ? channel_count = img.shape[2]? # i.e. 3 or 4 depending on your image

? ? ? ? ignore_mask_color = (255,) * channel_count

? ? else:

? ? ? ? ignore_mask_color = 255

? ? #[vertices]中的點(diǎn)組成了多邊形,將在多邊形內(nèi)的mask像素點(diǎn)保留仍侥,

? ? cv2.fillPoly(mask, [vertices], ignore_mask_color)

? ? #與mask做"與"操作要出,即僅留下多邊形部分的圖像

? ? masked_image = cv2.bitwise_and(img, mask)

? ? return masked_image

源碼出自:https://github.com/udacity/CarND-LaneLines-P1/blob/master/P1.ipynb

封裝完函數(shù)后,我們將感興趣的區(qū)域輸入农渊,實(shí)現(xiàn)邊緣提取后的圖像的截取患蹂。

#圖像像素行數(shù) rows = canny_image .shape[0]? 540行

#圖像像素列數(shù) cols = canny_image .shape[1]? 960列

left_bottom = [0, canny_image .shape[0]]

right_bottom = [canny_image .shape[1], canny_image .shape[0]]

apex = [canny_image .shape[1]/2, 310]

vertices = np.array([ left_bottom, right_bottom, apex ], np.int32)

roi_image = region_of_interest(canny_image, vertices)

截取后的圖像入下圖所示:

感興趣區(qū)域截取


霍夫變換

經(jīng)過灰度處理或颊、邊緣檢測、感興趣區(qū)域截取后传于,我們終于將左右車道線從復(fù)雜的圖像中提取出來了囱挑。接下來,我們使用霍夫變換來提取圖像中的直線(段)沼溜。

霍夫變換是一種特征檢測方法平挑,其原理和推導(dǎo)過程可以參看經(jīng)典霍夫變換(Hough Transform)。

在圖像中使用霍夫變換不僅能夠識(shí)別圖像中的直線系草,還能識(shí)別出圖像中的圓通熄、橢圓等特征。OpenCV為我們提供了霍夫變換檢測直線的函數(shù)找都,可以通過設(shè)置不同的參數(shù)唇辨,檢測不同長度的線段。由于車道線存在虛線的可能能耻,因此線段的檢測長度不能設(shè)置地太長赏枚,否則短線段會(huì)被忽略掉。

OpenCV的霍夫變換直線檢測函數(shù)使用方法如下:

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

# Hough Transform 檢測線段晓猛,線段兩個(gè)端點(diǎn)的坐標(biāo)存在lines中

lines = cv2.HoughLinesP(roi_image, rho, theta, threshold, np.array([]),

? ? ? ? ? ? ? ? ? ? ? ? ? ? min_line_length, max_line_gap)

封裝一個(gè)繪圖函數(shù)饿幅,實(shí)現(xiàn)把線段繪制在圖像上的功能,以實(shí)現(xiàn)線段的可視化

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) # 將線段繪制在img上

將得到線段繪制在原始圖像上

import numpy as np

line_image = np.copy(img) # 復(fù)制一份原圖戒职,將線段繪制在這幅圖上

draw_lines(line_image, lines, [255, 0, 0], 6)

結(jié)果如下圖:

霍夫變換直線檢測


可以看出栗恩,雖然右車道線的線段不連續(xù),但已經(jīng)很接近我們想要的輸出結(jié)果了洪燥。

數(shù)據(jù)后處理

霍夫變換得到的一系列線段結(jié)果跟我們的輸出結(jié)果還是有些差異摄凡。為了解決這些差異,需要對(duì)我們檢測到的數(shù)據(jù)做一定的后處理操作蚓曼。

實(shí)現(xiàn)以下兩步后處理,才能真正得到我們的輸出結(jié)果钦扭。

計(jì)算左右車道線的直線方程

根據(jù)每個(gè)線段在圖像坐標(biāo)系下的斜率纫版,判斷線段為左車道線還是右車道線,并存于不同的變量中客情。隨后對(duì)所有左車道線上的點(diǎn)其弊、所有右車道線上的點(diǎn)做一次最小二乘直線擬合,得到的即為最終的左膀斋、右車道線的直線方程梭伐。

計(jì)算左右車道線的上下邊界

考慮到現(xiàn)實(shí)世界中左右車道線一般都是平行的,所以可以認(rèn)為左右車道線上最上和最下的點(diǎn)對(duì)應(yīng)的y值仰担,就是左右車道線的邊界糊识。

基于以上兩步數(shù)據(jù)后處理的思路,我們重新定義draw_lines()函數(shù),將數(shù)據(jù)后處理過程寫入該函數(shù)中赂苗。

def draw_lines(img, lines, color=[255, 0, 0], thickness=2):

? ? left_lines_x = []

? ? left_lines_y = []

? ? right_lines_x = []

? ? right_lines_y = []

? ? line_y_max = 0

? ? line_y_min = 999

? ? for line in lines:

? ? ? ? for x1,y1,x2,y2 in line:

? ? ? ? ? ? if y1 > line_y_max:

? ? ? ? ? ? ? ? line_y_max = y1

? ? ? ? ? ? if y2 > line_y_max:

? ? ? ? ? ? ? ? line_y_max = y2

? ? ? ? ? ? if y1 < line_y_min:

? ? ? ? ? ? ? ? line_y_min = y1

? ? ? ? ? ? if y2 < line_y_min:

? ? ? ? ? ? ? ? line_y_min = y2

? ? ? ? ? ? k = (y2 - y1)/(x2 - x1)

? ? ? ? ? ? if k < -0.3:

? ? ? ? ? ? ? ? left_lines_x.append(x1)

? ? ? ? ? ? ? ? left_lines_y.append(y1)

? ? ? ? ? ? ? ? left_lines_x.append(x2)

? ? ? ? ? ? ? ? left_lines_y.append(y2)

? ? ? ? ? ? elif k > 0.3:

? ? ? ? ? ? ? ? right_lines_x.append(x1)

? ? ? ? ? ? ? ? right_lines_y.append(y1)

? ? ? ? ? ? ? ? right_lines_x.append(x2)

? ? ? ? ? ? ? ? right_lines_y.append(y2)

? ? #最小二乘直線擬合

? ? left_line_k, left_line_b = np.polyfit(left_lines_x, left_lines_y, 1)

? ? right_line_k, right_line_b = np.polyfit(right_lines_x, right_lines_y, 1)

? ? #根據(jù)直線方程和最大愉耙、最小的y值反算對(duì)應(yīng)的x

? ? cv2.line(img,

? ? ? ? ? ? (int((line_y_max - left_line_b)/left_line_k), line_y_max),

? ? ? ? ? ? (int((line_y_min - left_line_b)/left_line_k), line_y_min),

? ? ? ? ? ? color, thickness)

? ? cv2.line(img,

? ? ? ? ? ? (int((line_y_max - right_line_b)/right_line_k), line_y_max),

? ? ? ? ? ? (int((line_y_min - right_line_b)/right_line_k), line_y_min),

? ? ? ? ? ? color, thickness)

根據(jù)對(duì)線段的后處理,即可得到符合輸出要求的兩條直線方程的斜率拌滋、截距和有效長度朴沿。將后處理后的結(jié)果繪制在原圖上,如下圖所示:

數(shù)據(jù)后處理


處理視頻

視頻其實(shí)就是一幀幀連續(xù)不斷的圖像败砂,使用讀取視頻的庫赌渣,將視頻截取成一幀幀圖像,然后使用上面的灰度處理昌犹、邊緣提取坚芜、感興趣區(qū)域選擇、霍夫變換和數(shù)據(jù)后處理祭隔,得到車道線檢測結(jié)果货岭,再將圖片結(jié)果拼接成視頻,就完成了視頻中的車道線檢測疾渴。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末千贯,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子搞坝,更是在濱河造成了極大的恐慌搔谴,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桩撮,死亡現(xiàn)場離奇詭異敦第,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)店量,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門芜果,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人融师,你說我怎么就攤上這事右钾。” “怎么了旱爆?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵舀射,是天一觀的道長。 經(jīng)常有香客問我怀伦,道長脆烟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任房待,我火速辦了婚禮邢羔,結(jié)果婚禮上驼抹,老公的妹妹穿的比我還像新娘。我一直安慰自己张抄,他們只是感情好砂蔽,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著署惯,像睡著了一般左驾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上极谊,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天诡右,我揣著相機(jī)與錄音,去河邊找鬼轻猖。 笑死帆吻,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的咙边。 我是一名探鬼主播猜煮,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼败许!你這毒婦竟也來了王带?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤市殷,失蹤者是張志新(化名)和其女友劉穎愕撰,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體醋寝,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡搞挣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了音羞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片囱桨。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖嗅绰,靈堂內(nèi)的尸體忽然破棺而出蝇摸,到底是詐尸還是另有隱情,我是刑警寧澤办陷,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站律歼,受9級(jí)特大地震影響民镜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜险毁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一制圈、第九天 我趴在偏房一處隱蔽的房頂上張望们童。 院中可真熱鬧,春花似錦鲸鹦、人聲如沸慧库。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽齐板。三九已至,卻和暖如春葛菇,著一層夾襖步出監(jiān)牢的瞬間甘磨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國打工眯停, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留济舆,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓莺债,卻偏偏與公主長得像滋觉,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子齐邦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容