人工智能課第三次展示

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í)主人身體特征——音頻識別
  • 認(rèn)識主人后,啟動小車馬達(dá)——實時學(xué)習(xí)
  • 識別跑道白線,順著跑道線外延行走——圖像識別
  • 同時跟著主人速度走——實時學(xué)習(xí)

詳細(xì)算法介紹

雙目測距

雙目測距原理圖如下:
[圖片上傳失敗...(image-c1e316-1514170339592)]

雙目測距主要是利用了目標(biāo)點在左右兩幅視圖上成像的橫向坐標(biāo)直接存在的差異,也就是視差d,由相似三角形原理得知其與目標(biāo)點到成像平面的距離Z存在著反比例的關(guān)系 Z = fT/d。

相機標(biāo)定: 攝像頭由于光學(xué)透鏡的特性使得成像存在著徑向畸變,可由三個參數(shù)k1,k2,k3確定;由于裝配方面的誤差,傳感器與光學(xué)鏡頭之間并非完全平行,因此成像存在切向畸變,可由兩個參數(shù)p1,p2確定。單個攝像頭的定標(biāo)主要是計算出攝像頭的內(nèi)參(焦距f和成像原點cx,cy、五個畸變參數(shù)(一般只需要計算出k1,k2,p1,p2,對于魚眼鏡頭等徑向畸變特別大的才需要計算k3))以及外參(標(biāo)定物的世界坐標(biāo))。而雙目攝像頭定標(biāo)不僅要得出每個攝像頭的內(nèi)部參數(shù),還需要通過標(biāo)定來測量兩個攝像頭之間的相對位置(即右攝像頭相對于左攝像頭的旋轉(zhuǎn)矩陣R、平移向量t)。
[圖片上傳失敗...(image-5e36b5-1514170339592)])
[圖片上傳失敗...(image-cf4a4c-1514170339592)])
[圖片上傳失敗...(image-8b31b0-1514170339592)]\right])
[圖片上傳失敗...(image-8039ae-1514170339593)]+2p_2x\right])

雙目校正: 雙目校正是根據(jù)攝像頭定標(biāo)后獲得的單目內(nèi)參數(shù)據(jù)(焦距、成像原點、畸變系數(shù))和雙目相對位置關(guān)系(旋轉(zhuǎn)矩陣和平移向量),分別對左右視圖進(jìn)行消除畸變和行對準(zhǔn),使得左右視圖的成像原點坐標(biāo)一致、兩攝像頭光軸平行、左右成像平面共面、對極線行對齊。這樣一幅圖像上任意一點與其在另一幅圖像上的對應(yīng)點就必然具有相同的行號,只需在該行進(jìn)行一維搜索即可匹配到對應(yīng)點。

雙目匹配: 雙目匹配的作用是把同一場景在左右視圖上對應(yīng)的像點匹配起來,這樣做的目的是為了得到視差圖。雙目匹配被普遍認(rèn)為是立體視覺中最困難也是最關(guān)鍵的問題。得到視差數(shù)據(jù),通過上述原理中的公式就可以很容易的計算出深度信息。

實際注意事項

  • SIFT特征提取算法對左右圖像點提取特征
  • knnMatch取k=2找到左右圖片最佳匹配
  • 再過濾去除壞的匹配點
  • 對于剩下的點使用相似三角形計算公式得到圖片各點景深標(biāo)在圖上
  • 最終小車避障可根據(jù)其中少數(shù)點進(jìn)行判斷,或者取均值。

標(biāo)定結(jié)果如下:
以下圖片均為右轉(zhuǎn)90度的結(jié)果,因為小車拍攝到的視頻原狀是右偏的


墻角的實拍圖

拐角的實拍圖

信箱的實拍圖

信箱的實拍圖

由標(biāo)定結(jié)果可以看出,其測距效果還是比較接近真實值的。

圖像識別

CNN算法介紹

使用CNN神經(jīng)網(wǎng)絡(luò)對六百多張圖片進(jìn)行學(xué)習(xí),判斷小車應(yīng)當(dāng)直走、左轉(zhuǎn)、還是右轉(zhuǎn)。如左圖所示,白線斜率過大,小車距離白線過近,因此小車應(yīng)該左轉(zhuǎn),如中間圖片所示,小車應(yīng)該直走,如右圖所示,視野內(nèi)并沒有白線,此時默認(rèn)小車直走。

CNN神經(jīng)網(wǎng)絡(luò)的基本結(jié)構(gòu)

可以看出最左邊的圖像是輸入層,計算機理解為輸入若干個矩陣,接著是卷積層(Convolution Layer),在卷積層后面是池化層(Pooling layer),卷積層+池化層的組合可以在隱藏層出現(xiàn)很多次,在若干卷積層+池化層后面是全連接層(Fully Connected Layer, 簡稱FC),最后是輸出層。

  1. 卷積層
    卷積層是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的元素。
  1. 池化層
    池化層的作用是對輸入張量的各個子矩陣進(jìn)行壓縮。假如是2x2的池化,那么就將子矩陣的每2x2個元素變成一個元素,如果是3x3的池化,那么就將子矩陣的每3x3個元素變成一個元素,這樣輸入矩陣的維度就變小了。

要想將輸入子矩陣的每nxn個元素變成一個元素,那么需要一個池化標(biāo)準(zhǔn)。常見的池化標(biāo)準(zhǔn)有2個,MAX或者是Average。即取對應(yīng)區(qū)域的最大值或者平均值作為池化后的元素值。

下面這個例子采用取最大值的池化方法。同時采用的是2x2的池化。步幅為2。

首先對紅色2x2區(qū)域進(jìn)行池化,由于此2x2區(qū)域的最大值為6.那么對應(yīng)的池化輸出位置的值為6,由于步幅為2,此時移動到綠色的位置去進(jìn)行池化,輸出的最大值為8.同樣的方法,可以得到黃色區(qū)域和藍(lán)色區(qū)域的輸出值。最終,我們的輸入4x4的矩陣在池化后變成了2x2的矩陣。進(jìn)行了壓縮。

  1. 損失層
    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)

  1. CNN結(jié)構(gòu)圖
    使用keras搭建卷積神經(jīng)網(wǎng)絡(luò)
  1. CNN各層介紹
  • 卷積層2:33小核計算,降低復(fù)雜度同時不損失精度
  • 激活層:Relu,f(x)=max(0,x),收斂速度快
  • 池化層:區(qū)域壓縮為1/4,降低復(fù)雜度并減少特征損失
  • 全連接層*2:將分布式特征表示映射到樣本標(biāo)記空間
  • Dropout層:Dropout設(shè)為0.5,防止過擬合,減少神經(jīng)元之間相互依賴
  • 激活層:softmax,平衡多分類問題
  1. 效果分析

上圖是我們各個類別的準(zhǔn)確率和召回率??梢钥闯?,除了類別1,也就是左轉(zhuǎn)類的召回率較低以外,其他類的準(zhǔn)確率和召回率都較高。

宏平均(Macro-averaging),是先對每一個類統(tǒng)計指標(biāo)值,然后在對所有類求算術(shù)平均值。
微平均(Micro-averaging),是對數(shù)據(jù)集中的每一個實例不分類別進(jìn)行統(tǒng)計建立全局混淆矩陣,然后計算相應(yīng)指標(biāo)。

  1. 具體代碼實現(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值均達(dá)到了0.97,最差的AUC值也達(dá)到了0.84,效果還算不錯。


ROC曲線

實驗的分類報告如下:

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

音頻識別

音頻識別的目標(biāo)是識別出主人的口令“Hey AI”,識別出來口令中是否包含“Hey AI”,為一個二分類問題,使用的工具為RNN的一個變種LSTM。

LSTM介紹

Long Short Term 網(wǎng)絡(luò)—— 一般就叫做 LSTM ——是一種 RNN 特殊的類型,可以學(xué)習(xí)長期依賴信息。LSTM 由Hochreiter & Schmidhuber (1997)提出,并在近期被Alex Graves進(jìn)行了改良和推廣。在很多問題,LSTM 都取得相當(dāng)巨大的成功,并得到了廣泛的使用。

LSTM 通過刻意的設(shè)計來避免長期依賴問題。記住長期的信息在實踐中是 LSTM 的默認(rèn)行為,而非需要付出很大代價才能獲得的能力!

所有 RNN 都具有一種重復(fù)神經(jīng)網(wǎng)絡(luò)模塊的鏈?zhǔn)降男问?。在?biāo)準(zhǔn)的 RNN 中,這個重復(fù)的模塊只有一個非常簡單的結(jié)構(gòu),例如一個 tanh 層。


標(biāo)準(zhǔn) RNN 中的重復(fù)模塊包含單一的層

LSTM 同樣是這樣的結(jié)構(gòu),但是重復(fù)的模塊擁有一個不同的結(jié)構(gòu)。不同于 單一神經(jīng)網(wǎng)絡(luò)層,這里是有四個,以一種非常特殊的方式進(jìn)行交互。


LSTM 中的重復(fù)模塊包含四個交互的層

LSTM 的關(guān)鍵就是細(xì)胞狀態(tài),水平線在圖上方貫穿運行。

細(xì)胞狀態(tài)類似于傳送帶。直接在整個鏈上運行,只有一些少量的線性交互。信息在上面流傳保持不變會很容易。

LSTM 有通過精心設(shè)計的稱作為“門”的結(jié)構(gòu)來去除或者增加信息到細(xì)胞狀態(tài)的能力。門是一種讓信息選擇式通過的方法。他們包含一個 sigmoid 神經(jīng)網(wǎng)絡(luò)層和一個 pointwise 乘法操作。

Sigmoid 層輸出 0 到 1 之間的數(shù)值,描述每個部分有多少量可以通過。0 代表“不許任何量通過”,1 就指“允許任意量通過”!

LSTM 擁有三個門,來保護(hù)和控制細(xì)胞狀態(tài)。

LSTM具體實現(xiàn)

LSTM的框架圖如下


LSTM框架圖

首先使用了兩層雙向LSTM,接著利用Flatten實現(xiàn)到兩層全連接層的過渡。雖然單向LSTM已經(jīng)足夠進(jìn)行分類,但為了獲得更高的準(zhǔn)確度,是用了更強的雙向LSTM。

最后實驗結(jié)果在測試集上的各項指標(biāo)均接近于1,也就是全部分類正確,就不進(jìn)行圖表繪制。

實時學(xué)習(xí)

算法介紹

  1. 識別出運動的像素點

通過對比相鄰的兩幀圖像之間像素點的移動,標(biāo)注出移動的像素點。得到效果圖如下圖所示。

代碼如下所示:

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的運動點坐標(biāo),x2y2是new運動點的坐標(biāo)
    return old
  1. 畫出目標(biāo)區(qū)域
    kmeans 算法接受參數(shù) k ;然后將事先輸入的n個數(shù)據(jù)對象劃分為 k個聚類以便使得所獲得的聚類滿足:同一聚類中的對象相似度較高;而不同聚類中的對象相似度較小。聚類相似度是利用各中對象的均值所獲得一個“中心對象”(引力中心)來進(jìn)行計算的。

Kmeans算法是最為經(jīng)典的基于劃分的聚類方法,是十大經(jīng)典數(shù)據(jù)挖掘算法之一。Kmeans算法的基本思想是:以空間中k個點為中心進(jìn)行聚類,對最靠近他們的對象歸類。通過迭代的方法,逐次更新各聚類中心的值,直至得到最好的聚類結(jié)果。

我們使用Kmeans聚類分析的算法,將運動的像素點劃分為三個類別,分別用矩形框?qū)^(qū)域框出。

  1. 特征提取
    我們使用顏色作為人的主要特征,找出上步標(biāo)注出的三個矩形框中面積最大的一個,進(jìn)行主顏色的提取。
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
  1. 實時識別
    我們根據(jù)顏色特征來識別出實時圖像中人的位置。在RGB顏色空間中,以主顏色+-20作為判斷的顏色區(qū)域,找出符合的像素點。通過erode和dilate來平滑像素點,得到一個區(qū)域,然后通過opencv的輪廓尋找功能找到區(qū)域輪廓的像素點,用矩形框標(biāo)出這個區(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ù)標(biāo)注、
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容