官术网_书友最值得收藏!

3.4 基于傳統(tǒng)特征的傳統(tǒng)圖像分類方法

3.3節(jié)介紹了如何使用圖片的顏色以及形狀特征,在圖像中標(biāo)注足球的位置。這個標(biāo)注過程實際上還是基于人工規(guī)則進(jìn)行的,存在很多問題:

  • 只能識別藍(lán)黃相間的球。
  • 只能識別綠色草地上的球。
  • 攝像機(jī)距離拉遠(yuǎn)、拉近后球的像素大小改變,仍然無法識別。

由此可見,人工規(guī)則在實際應(yīng)用的場景中會遇到各種預(yù)想不到的結(jié)果,在這些情況下,人工規(guī)則的表現(xiàn)會大打折扣。為了解決這些問題,圖像處理技術(shù)引入了機(jī)器學(xué)習(xí)方法,希望通過機(jī)器規(guī)則來代替人工規(guī)則。這一思(tao)路(lu),總體如下:

(1)針對某一圖片,將幾百、上千像素圖片簡化為少數(shù)幾個區(qū)域,計算每個區(qū)域中輪廓特征的走向。

(2)將正負(fù)樣本所有圖片執(zhí)行第三步,將輪廓走向圖放入機(jī)器學(xué)習(xí)分類器進(jìn)行訓(xùn)練。

(3)將訓(xùn)練好的分類器應(yīng)用在新的圖片中。

我們審視這一思路,發(fā)現(xiàn)這個過程的核心思想其實是在簡化圖片——第一步中,原本圖片里各種不同的物體被減少到只剩下輪廓了,但這還不夠,最后計算的是一個區(qū)域內(nèi)的輪廓走向,此時一張1200×800×3大小的圖片,可能只剩下1000個點了,信息減少了上千倍。

這么做的原因首先是傳統(tǒng)的機(jī)器學(xué)習(xí)分類器,對輸入數(shù)據(jù)的大小有一個大致的上限,幾千張圖像數(shù)據(jù)如果不經(jīng)過簡化,直接送入模型,模型是無法訓(xùn)練輸入數(shù)據(jù)的;其次,圖像數(shù)據(jù)最有趣的一點是圖中一個像素點和周圍像素點周圍聯(lián)系非常緊密,數(shù)據(jù)的冗余度很大,這種冗余體現(xiàn)在很多時候,即使給圖片壓縮、涂黑、打馬賽克,我們也大致知道這張圖片的內(nèi)容;同理,對圖片進(jìn)行簡化,也是基于這一思想。

本節(jié)基于這個思路來介紹一下如何用python-opencv處理圖像,對圖片進(jìn)行簡化處理,然后用上一章的機(jī)器學(xué)習(xí)方法進(jìn)行圖像分類。我們使用優(yōu)達(dá)學(xué)城(Udacity)自動駕駛納米學(xué)位的一個開源項目一部分內(nèi)容作為講解材料,希望了解完整部分的讀者可以去優(yōu)達(dá)學(xué)城官網(wǎng)udacity.cn以及開源地址https://github.com/udacity/CarND-Vehicle-Detection查看完整內(nèi)容。

我們使用了優(yōu)達(dá)學(xué)城標(biāo)注的一個行車記錄儀數(shù)據(jù)集,這個數(shù)據(jù)集來自GTI以及KITTI數(shù)據(jù)集,標(biāo)注了車輛以及非車輛的情況,具體如下:

運(yùn)算結(jié)果:

其結(jié)果如圖3-18所示。

圖3-18 運(yùn)行結(jié)果

我們的任務(wù)是利用幾千張這樣的標(biāo)注圖片組成的數(shù)據(jù)集來訓(xùn)練一個分類器,以區(qū)別輸入圖片是否是車輛。

3.4.1 將圖片簡化為少數(shù)區(qū)域并計算每個區(qū)域輪廓特征的方向

這里其實是運(yùn)用方向梯度直方圖算法(Histogram of Oriented Gradients, HOG)來實現(xiàn)的。這一算法可以分為以下步驟(http://www.learnopencv.com/histogram-of-oriented-gradients/):

  • 圖像歸一化(可選)。
  • 計算圖像中x以及y方向的梯度。
  • 根據(jù)梯度,計算梯度柱狀圖。
  • 對塊狀區(qū)域進(jìn)行歸一化處理。
  • 展開結(jié)果,將一張圖片轉(zhuǎn)換成一個一維的特征向量。
  • 提取的特征,交給支持向量機(jī)或神經(jīng)網(wǎng)絡(luò)分類器進(jìn)行訓(xùn)練分類。

例如,可以將如圖3-19所示的左圖作為HOG算法的輸入文件,得到類似右圖的結(jié)果。首先,HOG算法的結(jié)果只表示輪廓線的變換,無關(guān)顏色(如白色的背景以及右下角黑色部分)都沒有輪廓線;其次,整張圖x、y方向有成百上千的像素點,這里被縮小到了32×32的網(wǎng)格區(qū)域,這一點類似前面提到的二維碼的讀取。當(dāng)然,這里與二維碼不同的是,除了分組求平均值以外,還考慮了輪廓線的方向性,即線條顏色深淺表示了輪廓線數(shù)目的多少,同時線條的方向也可以表示這塊區(qū)域內(nèi)輪廓線的總體走勢。

圖3-19 HOG算法實例(圖片來自skimage的官方文檔)

進(jìn)一步閱讀官方文檔,發(fā)現(xiàn)用法如下:

          fd, hog_image = hog(image, orientations=8, pixels_per_cell=(16, 16),
    cells_per_block=(1, 1), visualize=True)

這里有三個可以調(diào)的參數(shù),即orientations、pixels_per_cell以及cells_per_block。這三個參數(shù)的含義簡單說明如下:

  • pixels_per_cell是指多少個像素作為一個網(wǎng)格來計算,這個值越高,切出來的網(wǎng)格就越少,整個HOG的結(jié)果就越粗略。
  • orientation是指切出來每個網(wǎng)格中有幾種方向的走勢,如果是四種,就是上、下、左、右;如果是八種,就再增加上左、上右、下左、下右四種方向。
  • cells_per_block是指一個網(wǎng)格中使用幾個方向指針,如果是十字交叉的情況,則至少需要兩個方向指針進(jìn)行交叉,才可以表示出十字。

然后就是借助matplotlib可視化包查看一下不同參數(shù)的結(jié)果,如圖3-20所示。

圖3-20 使用不同的HOG參數(shù)分析輸入圖片得出不同的結(jié)果

這里決定用cell_per_block = 2,因為感覺結(jié)果中最多只出現(xiàn)了兩個方向的交叉。然后orientations = 9對拐角處的特征保留得更好,看起來像車的形狀。最后,pix_per_cell = 8看起來正好可以保持車的形狀,取6得到的網(wǎng)格過多,取10則得到的網(wǎng)格過少。

3.4.2 將HOG變換運(yùn)用在所有正負(fù)樣本中

這里將正負(fù)樣本抽樣相關(guān)的函數(shù)寫成一個class,然后在這里引用class進(jìn)行相應(yīng)的操作,得到正負(fù)樣本在各個圖片中的區(qū)域。然后從這些區(qū)域中提取圖像文件,resize到64×64,計算HOG值,進(jìn)而保存在矩陣中。

注意,下一步需要利用機(jī)器學(xué)習(xí)進(jìn)行相應(yīng)的判別,為了評價分類的準(zhǔn)確性,這里需要將正負(fù)樣本進(jìn)一步切割為訓(xùn)練集和測試集。

3.4.3 訓(xùn)練模型

完成前面的步驟后將開始模型的訓(xùn)練。訓(xùn)練的第一步是需要對數(shù)據(jù)進(jìn)行標(biāo)準(zhǔn)化處理:

    X_scalerM = StandardScaler()
    X_trainT = X_scalerM.fit_transform(X_train)
    X_testT  = X_scalerM.transform(X_test)
X_trainTs,y_trainTs = sklearn.utils.shuffle(X_trainT, y_train)

使用sklearn的支持向量機(jī)模塊進(jìn)行訓(xùn)練。訓(xùn)練后,看看驗證集的表現(xiàn):

    svc = SVC(random_state=0, C=1)
    t=time.time()
    svc.fit(X_trainTs, y_trainTs)
    t2 = time.time()
    print(round(t2-t, 2), 'Seconds to train SVC...')
    #51.54 Seconds to train SVC...

訓(xùn)練完成。接下來,用劃分出來的驗證集查看模型的表現(xiàn)。

3.4.4 將訓(xùn)練好的分類器運(yùn)用在新的圖片中

開始劃分?jǐn)?shù)據(jù)時就使用train_test_split(pd_SampClass, test_size=0.33, random_state=42),分別劃分了訓(xùn)練集以及驗證集。其中,66%的數(shù)據(jù)被劃分為訓(xùn)練集,用于上一步的模型訓(xùn)練。

這里,將用剩下的33%作為驗證集來檢驗?zāi)P偷谋憩F(xiàn)。首先看準(zhǔn)確率:

    print('Test Accuracy of SVC = ', round(svc.score(X_testT, y_test), 4))

運(yùn)行結(jié)果:

          # out:
          Test Accuracy of SVC =  0.9869

98%的分類準(zhǔn)確率還是不錯的。接下來選十個樣本看結(jié)果:

    n_predict = 10
    print('My SVC predicts: ', svc.predict(X_testT[0:n_predict]))

運(yùn)行結(jié)果:

          # out:
          My SVC predicts:  [1 1 1 0 0 0 0 1 1 1]
    print('For these',n_predict, 'labels: ', y_test[0:n_predict])

運(yùn)行結(jié)果:

          # out:
          For these 10 labels:  [1 1 1 0 0 0 0 1 1 1]

選的前十個測試樣本,結(jié)果都是預(yù)測正確。最后看AUC值:

    pred = svc.predict(X_testT)
    print("AUC for Merge dataset = %1.2f,\n" % (roc_auc_score(pred, y_test)))

運(yùn)行結(jié)果:

          # out:
          AUC for Merge dataset = 0.99,
    print(confusion_matrix(pred, y_test))

運(yùn)行結(jié)果:

          # out:
          [[2929   55]
           [  22 2855]]

發(fā)現(xiàn)大多數(shù)預(yù)測準(zhǔn)確,假陽性的數(shù)量是真陰性的2倍多,是一個基本可用的模型。至于這個模型的適用性如何,讀者可以在網(wǎng)上找圖片,resize到64×64,看看是否可以成功預(yù)測。

最后,總結(jié)本章所學(xué)的內(nèi)容。本章開始部分提到,要用機(jī)器學(xué)習(xí)方法分析傳統(tǒng)圖像數(shù)據(jù),可以有三種思路:

  • 手動提取重要的特征,用數(shù)字表示。如鳶尾花數(shù)據(jù)集,當(dāng)年就是用尺子量出來的長度、寬度,交給機(jī)器學(xué)習(xí)分類器。
  • 用簡單的圖像處理操作,將圖片轉(zhuǎn)換為少數(shù)幾個簡單的輪廓特征,交給機(jī)器學(xué)習(xí)分類器。
  • 用深度神經(jīng)網(wǎng)絡(luò),讓深度學(xué)習(xí)模型自動提取圖片的各種特征,再用模型自動提取的特征訓(xùn)練分類器。

本章介紹的是第二種方法,即提取簡單特征,交給機(jī)器學(xué)習(xí)分類器,如支持向量機(jī)。這種方法的問題想必讀者也有切身體會:

(1)“笨”——連足球都不認(rèn)識,需要手動提取顏色、輪廓,然后過濾噪聲,最后交給霍夫變換檢測器,計算機(jī)才認(rèn)識這是個圓形。

(2)“眼花”——我們拿到的是一個高像素的圖片,需要將圖片的信息不斷模糊、減少信息量,機(jī)器學(xué)習(xí)模型才能“認(rèn)識”這張圖片,才能用這種簡化后的圖片進(jìn)行模型訓(xùn)練。

我們再思考一下,為什么傳統(tǒng)計算機(jī)模型會顯得很“笨”,而且眼神不好?一個很重要的原因是,傳統(tǒng)的機(jī)器學(xué)習(xí)模型缺乏特征組合能力,尤其是對圖像輸入,計算機(jī)可以理解單獨(dú)的一個像素,但是把單一像素與周圍三五個點一起考慮,計算機(jī)模型在組合的時候,似乎不太能把握這一組點的關(guān)系,所以我們會用opencv skimage把人類在識別諸如球體、車輛這樣的物體的關(guān)鍵因素提取出來,然后將提取的信息交給機(jī)器學(xué)習(xí)模型。

接下來介紹的基于深度神經(jīng)網(wǎng)絡(luò)的方法,特征提取部分就并不完全由人手動完成,計算機(jī)模型可以幫助數(shù)據(jù)分析者提取諸如球形、車體框架這樣的特征。于是我們發(fā)現(xiàn),相比傳統(tǒng)的圖像處理技術(shù),計算機(jī)不“笨”了、不需要人提取特征了,眼神也變好了,可以直接識別原始圖片了。這也是深度學(xué)習(xí)技術(shù)總是和人工智能相提并論的一個很重要的原因。

主站蜘蛛池模板: 屏边| 灵寿县| 德化县| 襄汾县| 太康县| 陆河县| 泸州市| 石渠县| 中牟县| 玛纳斯县| 乳源| 景泰县| 安岳县| 巴林右旗| 武威市| 抚州市| 海兴县| 金堂县| 衡阳县| 白水县| 贺兰县| 化德县| 弥勒县| 曲阳县| 兴仁县| 卢湾区| 余庆县| 棋牌| 永泰县| 会泽县| 乌兰浩特市| 日喀则市| 阿荣旗| 三明市| 南平市| 湛江市| 普宁市| 乐山市| 陕西省| 增城市| 肇庆市|