AI Car 第三次展示報告
實現(xiàn)的功能
- 基于攝像頭的雙目測距
- 基于卷積神經(jīng)網(wǎng)絡(luò)的圖像識別
- 基于長短期記憶網(wǎng)絡(luò)的音頻識別
- 實時學(xué)習(xí)
- 聽從人命令
- 跟隨主人速度行走
- 為主人導(dǎo)航
功能介紹
室內(nèi)模式
- 啟動小車荒澡,人在小車側(cè)面晃動,小車學(xué)習(xí)主人身體特征——實時學(xué)習(xí)
- 小車識別出主人之后燎猛,帶領(lǐng)主人在室內(nèi)隨機游走
- 時刻緊跟主人腳步玛界,主人停下就停下,主人放慢腳步就減慢速度——實時學(xué)習(xí)
- 距離障礙物半米時向右拐彎——雙目測距
跑道模式
- 主人喊出口令“Hey AI”伤疙,小車識別出來之后學(xué)習(xí)主人身體特征——音頻識別
- 認識主人后银酗,啟動小車馬達——實時學(xué)習(xí)
- 識別跑道白線,順著跑道線外延行走——圖像識別
- 同時跟著主人速度走——實時學(xué)習(xí)
詳細算法介紹
雙目測距
雙目測距原理圖如下:
[圖片上傳失敗...(image-c1e316-1514170339592)]
雙目測距主要是利用了目標點在左右兩幅視圖上成像的橫向坐標直接存在的差異徒像,也就是視差d黍特,由相似三角形原理得知其與目標點到成像平面的距離Z存在著反比例的關(guān)系 Z = fT/d。
相機標定: 攝像頭由于光學(xué)透鏡的特性使得成像存在著徑向畸變锯蛀,可由三個參數(shù)k1,k2,k3確定灭衷;由于裝配方面的誤差,傳感器與光學(xué)鏡頭之間并非完全平行旁涤,因此成像存在切向畸變翔曲,可由兩個參數(shù)p1,p2確定。單個攝像頭的定標主要是計算出攝像頭的內(nèi)參(焦距f和成像原點cx,cy劈愚、五個畸變參數(shù)(一般只需要計算出k1,k2,p1,p2瞳遍,對于魚眼鏡頭等徑向畸變特別大的才需要計算k3))以及外參(標定物的世界坐標)。而雙目攝像頭定標不僅要得出每個攝像頭的內(nèi)部參數(shù)菌羽,還需要通過標定來測量兩個攝像頭之間的相對位置(即右攝像頭相對于左攝像頭的旋轉(zhuǎn)矩陣R掠械、平移向量t)。
[圖片上傳失敗...(image-5e36b5-1514170339592)])
[圖片上傳失敗...(image-cf4a4c-1514170339592)])
[圖片上傳失敗...(image-8b31b0-1514170339592)]\right])
[圖片上傳失敗...(image-8039ae-1514170339593)]+2p_2x\right])
雙目校正: 雙目校正是根據(jù)攝像頭定標后獲得的單目內(nèi)參數(shù)據(jù)(焦距注祖、成像原點猾蒂、畸變系數(shù))和雙目相對位置關(guān)系(旋轉(zhuǎn)矩陣和平移向量),分別對左右視圖進行消除畸變和行對準是晨,使得左右視圖的成像原點坐標一致婚夫、兩攝像頭光軸平行、左右成像平面共面署鸡、對極線行對齊案糙。這樣一幅圖像上任意一點與其在另一幅圖像上的對應(yīng)點就必然具有相同的行號限嫌,只需在該行進行一維搜索即可匹配到對應(yīng)點。
雙目匹配: 雙目匹配的作用是把同一場景在左右視圖上對應(yīng)的像點匹配起來时捌,這樣做的目的是為了得到視差圖怒医。雙目匹配被普遍認為是立體視覺中最困難也是最關(guān)鍵的問題。得到視差數(shù)據(jù)奢讨,通過上述原理中的公式就可以很容易的計算出深度信息稚叹。
實際注意事項:
- SIFT特征提取算法對左右圖像點提取特征
- knnMatch取k=2找到左右圖片最佳匹配
- 再過濾去除壞的匹配點
- 對于剩下的點使用相似三角形計算公式得到圖片各點景深標在圖上
- 最終小車避障可根據(jù)其中少數(shù)點進行判斷,或者取均值拿诸。
標定結(jié)果如下:
以下圖片均為右轉(zhuǎn)90度的結(jié)果扒袖,因為小車拍攝到的視頻原狀是右偏的
由標定結(jié)果可以看出,其測距效果還是比較接近真實值的亩码。
圖像識別
CNN算法介紹
使用CNN神經(jīng)網(wǎng)絡(luò)對六百多張圖片進行學(xué)習(xí)季率,判斷小車應(yīng)當直走、左轉(zhuǎn)描沟、還是右轉(zhuǎn)飒泻。如左圖所示,白線斜率過大吏廉,小車距離白線過近泞遗,因此小車應(yīng)該左轉(zhuǎn),如中間圖片所示席覆,小車應(yīng)該直走史辙,如右圖所示,視野內(nèi)并沒有白線佩伤,此時默認小車直走聊倔。
CNN神經(jīng)網(wǎng)絡(luò)的基本結(jié)構(gòu)
可以看出最左邊的圖像是輸入層,計算機理解為輸入若干個矩陣畦戒,接著是卷積層(Convolution Layer)方库,在卷積層后面是池化層(Pooling layer)结序,卷積層+池化層的組合可以在隱藏層出現(xiàn)很多次障斋,在若干卷積層+池化層后面是全連接層(Fully Connected Layer, 簡稱FC),最后是輸出層徐鹤。
- 卷積層
卷積層是CNN神經(jīng)網(wǎng)絡(luò)中最重要的一層垃环,我們通過如下的一個例子來理解它的原理。圖中的輸入是一個二維的3x4的矩陣返敬,而卷積核是一個2x2的矩陣遂庄。這里我們假設(shè)卷積是一次移動一個像素來卷積的,那么首先我們對輸入的左上角2x2局部和卷積核卷積劲赠,即各個位置的元素相乘再相加涛目,得到的輸出矩陣S的S00S00的元素秸谢,值為aw+bx+ey+fzaw+bx+ey+fz。接著我們將輸入的局部向右平移一個像素霹肝,現(xiàn)在是(b,c,f,g)四個元素構(gòu)成的矩陣和卷積核來卷積估蹄,這樣我們得到了輸出矩陣S的S01S01的元素,同樣的方法沫换,我們可以得到輸出矩陣S的S02臭蚁,S10,S11讯赏,S12S02垮兑,S10,S11漱挎,S12的元素系枪。
- 池化層
池化層的作用是對輸入張量的各個子矩陣進行壓縮。假如是2x2的池化识樱,那么就將子矩陣的每2x2個元素變成一個元素嗤无,如果是3x3的池化,那么就將子矩陣的每3x3個元素變成一個元素怜庸,這樣輸入矩陣的維度就變小了当犯。
要想將輸入子矩陣的每nxn個元素變成一個元素,那么需要一個池化標準割疾。常見的池化標準有2個嚎卫,MAX或者是Average。即取對應(yīng)區(qū)域的最大值或者平均值作為池化后的元素值宏榕。
下面這個例子采用取最大值的池化方法拓诸。同時采用的是2x2的池化。步幅為2麻昼。
首先對紅色2x2區(qū)域進行池化奠支,由于此2x2區(qū)域的最大值為6.那么對應(yīng)的池化輸出位置的值為6,由于步幅為2抚芦,此時移動到綠色的位置去進行池化倍谜,輸出的最大值為8.同樣的方法,可以得到黃色區(qū)域和藍色區(qū)域的輸出值叉抡。最終尔崔,我們的輸入4x4的矩陣在池化后變成了2x2的矩陣。進行了壓縮褥民。
- 損失層
dropout是指在深度學(xué)習(xí)網(wǎng)絡(luò)的訓(xùn)練過程中季春,對于神經(jīng)網(wǎng)絡(luò)單元,按照一定的概率將其暫時從網(wǎng)絡(luò)中丟棄消返。注意是暫時载弄,對于隨機梯度下降來說耘拇,由于是隨機丟棄,故而每一個mini-batch都在訓(xùn)練不同的網(wǎng)絡(luò)宇攻。
dropout最重要的功能就是防止數(shù)據(jù)出現(xiàn)過擬合驼鞭。
算法具體實現(xiàn)
- CNN結(jié)構(gòu)圖
使用keras搭建卷積神經(jīng)網(wǎng)絡(luò)
- CNN各層介紹
- 卷積層2:33小核計算,降低復(fù)雜度同時不損失精度
- 激活層:Relu尺碰,f(x)=max(0,x)挣棕,收斂速度快
- 池化層:區(qū)域壓縮為1/4,降低復(fù)雜度并減少特征損失
- 全連接層*2:將分布式特征表示映射到樣本標記空間
- Dropout層:Dropout設(shè)為0.5亲桥,防止過擬合洛心,減少神經(jīng)元之間相互依賴
- 激活層:softmax,平衡多分類問題
- 效果分析
上圖是我們各個類別的準確率和召回率题篷〈噬恚可以看出,除了類別1番枚,也就是左轉(zhuǎn)類的召回率較低以外,其他類的準確率和召回率都較高葫笼。
宏平均(Macro-averaging)深啤,是先對每一個類統(tǒng)計指標值,然后在對所有類求算術(shù)平均值路星。
微平均(Micro-averaging)溯街,是對數(shù)據(jù)集中的每一個實例不分類別進行統(tǒng)計建立全局混淆矩陣,然后計算相應(yīng)指標洋丐。
- 具體代碼實現(xiàn)
model = Sequential()
model.add(Convolution2D(nb_filters, (kernel_size[0], kernel_size[1]),
padding='same',
input_shape=(200,480,1))) # 卷積層
model.add(Activation('relu')) #激活層
model.add(Convolution2D(nb_filters, (kernel_size[0], kernel_size[1]))) #卷積層2
model.add(Activation('relu')) #激活層
model.add(MaxPooling2D(pool_size=pool_size)) #池化層
model.add(Dropout(0.25)) #神經(jīng)元隨機失活
model.add(Flatten()) #拉成一維數(shù)據(jù)
model.add(Dense(128)) #全連接層1
model.add(Activation('relu')) #激活層
model.add(Dropout(0.5)) #經(jīng)過交叉驗證
model.add(Dense(nb_classes)) #全連接層2
model.add(Activation('softmax')) #評分函數(shù)
#編譯模型
model.compile(loss='categorical_crossentropy',
optimizer='adadelta',
metrics=['accuracy'])
#訓(xùn)練模型
model.fit(train, y, batch_size=32, epochs=3,
verbose=1)
實驗結(jié)果
Class | Precision | Recall | F1-Score |
---|---|---|---|
0 | 0.73 | 1.00 | 0.85 |
1 | 1.00 | 0.18 | 0.31 |
2 | 0.89 | 0.94 | 0.91 |
Avg/Total | 0.81 | 0.80 | 0.75 |
下圖為本實驗的ROC曲線呈昔,由此可見,除了左轉(zhuǎn)之外友绝,剩下的曲線AUC值均達到了0.97堤尾,最差的AUC值也達到了0.84,效果還算不錯迁客。
實驗的分類報告如下:
Class | Precision | Recall | F1-Score |
---|---|---|---|
0 | 0.73 | 1.00 | 0.85 |
1 | 1.00 | 0.18 | 0.31 |
2 | 0.89 | 0.94 | 0.91 |
Avg/Total | 0.81 | 0.80 | 0.75 |
音頻識別
音頻識別的目標是識別出主人的口令“Hey AI”郭宝,識別出來口令中是否包含“Hey AI”,為一個二分類問題哲泊,使用的工具為RNN的一個變種LSTM剩蟀。
LSTM介紹
Long Short Term 網(wǎng)絡(luò)—— 一般就叫做 LSTM ——是一種 RNN 特殊的類型催蝗,可以學(xué)習(xí)長期依賴信息切威。LSTM 由Hochreiter & Schmidhuber (1997)提出,并在近期被Alex Graves進行了改良和推廣丙号。在很多問題先朦,LSTM 都取得相當巨大的成功缰冤,并得到了廣泛的使用。
LSTM 通過刻意的設(shè)計來避免長期依賴問題喳魏。記住長期的信息在實踐中是 LSTM 的默認行為棉浸,而非需要付出很大代價才能獲得的能力!
所有 RNN 都具有一種重復(fù)神經(jīng)網(wǎng)絡(luò)模塊的鏈式的形式刺彩。在標準的 RNN 中迷郑,這個重復(fù)的模塊只有一個非常簡單的結(jié)構(gòu),例如一個 tanh 層创倔。
LSTM 同樣是這樣的結(jié)構(gòu)嗡害,但是重復(fù)的模塊擁有一個不同的結(jié)構(gòu)。不同于 單一神經(jīng)網(wǎng)絡(luò)層畦攘,這里是有四個霸妹,以一種非常特殊的方式進行交互。
LSTM 的關(guān)鍵就是細胞狀態(tài)知押,水平線在圖上方貫穿運行叹螟。
細胞狀態(tài)類似于傳送帶。直接在整個鏈上運行台盯,只有一些少量的線性交互罢绽。信息在上面流傳保持不變會很容易。
LSTM 有通過精心設(shè)計的稱作為“門”的結(jié)構(gòu)來去除或者增加信息到細胞狀態(tài)的能力静盅。門是一種讓信息選擇式通過的方法有缆。他們包含一個 sigmoid 神經(jīng)網(wǎng)絡(luò)層和一個 pointwise 乘法操作。
Sigmoid 層輸出 0 到 1 之間的數(shù)值温亲,描述每個部分有多少量可以通過棚壁。0 代表“不許任何量通過”,1 就指“允許任意量通過”栈虚!
LSTM 擁有三個門袖外,來保護和控制細胞狀態(tài)。
LSTM具體實現(xiàn)
LSTM的框架圖如下
首先使用了兩層雙向LSTM魂务,接著利用Flatten實現(xiàn)到兩層全連接層的過渡曼验。雖然單向LSTM已經(jīng)足夠進行分類,但為了獲得更高的準確度粘姜,是用了更強的雙向LSTM鬓照。
最后實驗結(jié)果在測試集上的各項指標均接近于1,也就是全部分類正確孤紧,就不進行圖表繪制豺裆。
實時學(xué)習(xí)
算法介紹
- 識別出運動的像素點
通過對比相鄰的兩幀圖像之間像素點的移動,標注出移動的像素點。得到效果圖如下圖所示臭猜。
代碼如下所示:
def draw_flow(old, new, step=4):
flow = cv.calcOpticalFlowFarneback(
cv.cvtColor(old, cv.COLOR_BGR2GRAY),
cv.cvtColor(new, cv.COLOR_BGR2GRAY),
None, 0.5, 3, 15, 3, 5, 1.2, 0)
h, w = new.shape[:2]
y, x = np.mgrid[step/2:h:step, step/2:w:step].reshape(2, -1)
fx, fy = flow[np.int32(y), np.int32(x)].T
lines = np.int32(np.vstack([x, y, x+fx, y+fy]).T.reshape(-1, 2, 2))
for (x1, y1), (x2, y2) in lines:
if sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) < 15:
continue
cv.line(old, (x1, y1), (x2, y2), (0, 128, 0), 2)
cv.circle(old, (x1, y1), 3, (0, 255, 0), -1)
# x1 y1是old的運動點坐標躺酒,x2y2是new運動點的坐標
return old
- 畫出目標區(qū)域
kmeans 算法接受參數(shù) k ;然后將事先輸入的n個數(shù)據(jù)對象劃分為 k個聚類以便使得所獲得的聚類滿足:同一聚類中的對象相似度較高蔑歌;而不同聚類中的對象相似度較小羹应。聚類相似度是利用各中對象的均值所獲得一個“中心對象”(引力中心)來進行計算的。
Kmeans算法是最為經(jīng)典的基于劃分的聚類方法次屠,是十大經(jīng)典數(shù)據(jù)挖掘算法之一园匹。Kmeans算法的基本思想是:以空間中k個點為中心進行聚類,對最靠近他們的對象歸類劫灶。通過迭代的方法偎肃,逐次更新各聚類中心的值,直至得到最好的聚類結(jié)果浑此。
我們使用Kmeans聚類分析的算法累颂,將運動的像素點劃分為三個類別,分別用矩形框?qū)^(qū)域框出凛俱。
- 特征提取
我們使用顏色作為人的主要特征紊馏,找出上步標注出的三個矩形框中面積最大的一個,進行主顏色的提取蒲犬。
def get_dominant_color(image):
#顏色模式轉(zhuǎn)換朱监,以便輸出rgb顏色值
image = image.convert('RGBA')
#生成縮略圖,減少計算量原叮,減小cpu壓力
image.thumbnail((200, 200))
max_score = 0
dominant_color = 0
for count, (r, g, b, a) in image.getcolors(image.size[0] * image.size[1]):
# 跳過純黑色
if a == 0:
continue
saturation = colorsys.rgb_to_hsv(r / 255.0, g / 255.0, b / 255.0)[1]
y = min(abs(r * 2104 + g * 4130 + b * 802 + 4096 + 131072) >> 13, 235)
y = (y - 16.0) / (235 - 16)
# 忽略高亮色
if y > 0.9:
continue
score = (saturation + 0.1) * count
if score > max_score:
max_score = score
dominant_color = (r, g, b)
return dominant_color
- 實時識別
我們根據(jù)顏色特征來識別出實時圖像中人的位置赫编。在RGB顏色空間中,以主顏色+-20作為判斷的顏色區(qū)域奋隶,找出符合的像素點擂送。通過erode和dilate來平滑像素點,得到一個區(qū)域唯欣,然后通過opencv的輪廓尋找功能找到區(qū)域輪廓的像素點嘹吨,用矩形框標出這個區(qū)域。
mask = cv2.inRange(image, lower, upper)
mask = cv2.erode(mask, None, iterations=2)
mask = cv2.dilate(mask, None, iterations=2)
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
if len(cnts) > 0:
#找到面積最大的輪廓
c = max(cnts, key = cv2.contourArea)
x1,y1 = 1000,1000
x2,y2 = 0,0
for i in range(0,len(c)):
if c[i][0][0] < x1:
x1 = c[i][0][0]
if c[i][0][0] > x2:
x2 = c[i][0][0]
if c[i][0][1] < y1:
y1 = c[i][0][1]
if c[i][0][1] > y2:
y2 = c[i][0][1]
cv2.rectangle(image,(x1,y1),(x2,y2),(55,255,155),5)
小組分工
組員 | 參與工作 |
---|---|
楊昆霖 | 圖像識別境氢、音頻識別 |
劉玨 | 圖像識別蟀拷、實時學(xué)習(xí) |
施暢 | 雙目測距、數(shù)據(jù)采集 |
侯尚文 | 數(shù)據(jù)標注萍聊、 |