原文出處: Ronny 的博客(@RonnyYoung) 歡迎分享原創(chuàng)到伯樂頭條 1. 關(guān)于OpenCV進(jìn)階之路前段時(shí)間寫過(guò)一些關(guān)于OpenCV基礎(chǔ)知識(shí)方面的系列文章,,主要內(nèi)容是面向OpenCV初學(xué)者,介紹OpenCV中一些常用的函數(shù)的接口和調(diào)用方法,,相關(guān)的內(nèi)容在OpenCV的手冊(cè)里都有更詳細(xì)的解釋,,當(dāng)時(shí)自己也是邊學(xué)邊寫,權(quán)當(dāng)為一種筆記的形式,,所以難免有淺嘗輒止的感覺,,現(xiàn)在回頭看來(lái),很多地方描述上都存在不足,以后有時(shí)間,,我會(huì)重新考慮每一篇文章,,讓成長(zhǎng)系列對(duì)基礎(chǔ)操作的介紹更加詳細(xì)一些。 OpenCV進(jìn)階之路相比于成長(zhǎng)系列,,不會(huì)有太多的基礎(chǔ)函數(shù)的介紹,,相對(duì)來(lái)說(shuō)會(huì)更偏向于工程實(shí)踐,通過(guò)解決實(shí)際問(wèn)題來(lái)說(shuō)明某些較高級(jí)函數(shù)的用法和注意事項(xiàng),,主要內(nèi)容會(huì)集中在特征提取,、機(jī)器學(xué)習(xí)和目標(biāo)跟蹤幾個(gè)方向。所以這個(gè)系列文章知識(shí)點(diǎn)沒有先后順序之分,,根據(jù)個(gè)人平時(shí)工作學(xué)習(xí)中遇到的問(wèn)題而定,。 這篇文章主要介紹OpenCV中神經(jīng)網(wǎng)絡(luò)的用法,并通過(guò)車牌字符的識(shí)別來(lái)說(shuō)明一些參數(shù)設(shè)置,,函數(shù)調(diào)用順序等,,而關(guān)于神經(jīng)網(wǎng)絡(luò)的原理在博客機(jī)器學(xué)習(xí)分類里已經(jīng)詳細(xì)的講解與實(shí)現(xiàn)了,所以本文中就不多加說(shuō)明,。 2. 車牌字符識(shí)別車牌識(shí)別是計(jì)算機(jī)視覺在實(shí)際工程中一個(gè)非常成功的應(yīng)用,雖然現(xiàn)在技術(shù)相對(duì)來(lái)說(shuō)已經(jīng)成熟,,但是圍繞著車牌定位,、車牌二值化、車牌字符識(shí)別等方向,,還是不時(shí)的有新的算法出現(xiàn),。通過(guò)學(xué)習(xí)車牌識(shí)別來(lái)提升自己在圖像識(shí)別方面的工程經(jīng)驗(yàn)是非常好的,因?yàn)樗浅:玫恼f(shuō)明了計(jì)算機(jī)視覺的一般過(guò)程: 圖像→預(yù)處理→圖像分析→目標(biāo)提取→目標(biāo)識(shí)別 而整個(gè)車牌識(shí)別過(guò)程實(shí)際上相當(dāng)于包含了兩個(gè)上述過(guò)程:1,,是車牌的識(shí)別,;2,車牌字符的識(shí)別,。 這篇文章其實(shí)主要是想介紹OpenCV中神經(jīng)網(wǎng)絡(luò)的用法,,而不是介紹車牌識(shí)別技術(shù)。所以我們主要討論的內(nèi)容集中在車牌字符的識(shí)別上,,關(guān)于定位,、分割等不多加敘述敘述。 3. 字符特征提取在深度學(xué)習(xí)(將特征提取作為訓(xùn)練的一部分)這個(gè)概念引入之前,,一般在準(zhǔn)備分類器進(jìn)行識(shí)別之前都需要進(jìn)行特征提取,。因?yàn)橐环鶊D像包含的內(nèi)容太多,有些信息能區(qū)分差異性,,而有些信息卻代表了共性,。所以我們要進(jìn)行適當(dāng)?shù)奶卣魈崛“阉鼈冎g的差異性特征提取出來(lái)。 這里面我們計(jì)算二種簡(jiǎn)單的字符特征:梯度分布特征、灰度統(tǒng)計(jì)特征,。這兩個(gè)特征只是配合本篇文章來(lái)說(shuō)明神經(jīng)網(wǎng)絡(luò)的普遍用法,,實(shí)際中進(jìn)行字符識(shí)別需要考慮的字符特征遠(yuǎn)遠(yuǎn)要比這復(fù)雜,還包括相似字特征的選取等,,也由于工作上的原因,,這一部分并不深入的介紹。 1,,首先是梯度分布特征,,該特征計(jì)算圖像水平方向和豎直方向的梯度圖像,然后通過(guò)給梯度圖像分劃不同的區(qū)域,,進(jìn)行梯度圖像每個(gè)區(qū)域亮度值的統(tǒng)計(jì),,以下是算法步驟:
2,,第二個(gè)特征非常簡(jiǎn)單,只需要將圖像歸一化到特定的大小,,然后將圖像每個(gè)點(diǎn)的灰度值作為特征即可,。 <1>將圖像由RGB圖像轉(zhuǎn)換為灰度圖像; <2>將圖像歸一化大小為8×4,,并將圖像展開為一行,,組成特征向量。 4. OpenCV中的神經(jīng)網(wǎng)絡(luò)關(guān)于神經(jīng)網(wǎng)絡(luò)的原理我的博客里已經(jīng)寫了兩篇文章,,并且給出了C++的實(shí)現(xiàn),,所以這里我就不提了,下面主要說(shuō)明在OpenCV中怎么使用它提供的庫(kù)函數(shù),。 CvANN_MLP是OpenCV中提供的一個(gè)神經(jīng)網(wǎng)絡(luò)的類,,正如它的名字一樣(multi-layer perceptrons),它是一個(gè)多層感知網(wǎng)絡(luò),它有一個(gè)輸入層,一個(gè)輸出層以及1或多個(gè)隱藏層,。 4.1. 首先我們來(lái)創(chuàng)建一個(gè)網(wǎng)絡(luò),,我們可以利用CvANN_MLP的構(gòu)造函數(shù)或者create函數(shù)。
上面是分別是構(gòu)造函數(shù)和cteate成員函數(shù)的接口,,我們來(lái)分析各個(gè)形參的意思,。 layerSizes:一個(gè)整型的數(shù)組,這里面用Mat存儲(chǔ),。它是一個(gè)1*N的Mat,,N代表神經(jīng)網(wǎng)絡(luò)的層數(shù),第i列的值表示第i層的結(jié)點(diǎn)數(shù),。這里需要注意的是,,在創(chuàng)建這個(gè)Mat時(shí),一定要是整型的,,uchar和float型都會(huì)報(bào)錯(cuò),。 比如我們要?jiǎng)?chuàng)建一個(gè)3層的神經(jīng)網(wǎng)絡(luò),其中第一層結(jié)點(diǎn)數(shù)為x1,第二層結(jié)點(diǎn)數(shù)為x2,,第三層結(jié)點(diǎn)數(shù)為x3,,則layerSizes可以采用如下定義:
或者用一個(gè)數(shù)組來(lái)初始化:
activateFunc:這個(gè)參數(shù)用于指定激活函數(shù),不熟悉的可以去看我博客里的這篇文章《神經(jīng)網(wǎng)絡(luò):感知器與梯度下降》,一般情況下我們用SIGMOID函數(shù)就可以了,,當(dāng)然你也可以選擇正切函數(shù)或高斯函數(shù)作為激活函數(shù),。OpenCV里提供了三種激活函數(shù),線性函數(shù)(CvANN_MLP::IDENTITY),、sigmoid函數(shù)(CvANN_MLP::SIGMOID_SYM)和高斯激活函數(shù)(CvANN_MLP::GAUSSIAN)。 后面兩個(gè)參數(shù)則是SIGMOID激活函數(shù)中的兩個(gè)參數(shù)α和β,,默認(rèn)情況下會(huì)都被設(shè)置為1,。 4.2. 設(shè)置神經(jīng)網(wǎng)絡(luò)訓(xùn)練參數(shù)神經(jīng)網(wǎng)絡(luò)訓(xùn)練參數(shù)的類型存放在CvANN_MLP_TrainParams這個(gè)類里,它提供了一個(gè)默認(rèn)的構(gòu)造函數(shù),,我們可以直接調(diào)用,,也可以一項(xiàng)一項(xiàng)去設(shè)。
它的參數(shù)大概包括以下幾項(xiàng),。 term_crit:終止條件,,它包括了兩項(xiàng),迭代次數(shù)(CV_TERMCRIT_ITER)和誤差最小值(CV_TERMCRIT_EPS),,一旦有一個(gè)達(dá)到條件就終止訓(xùn)練,。 train_method:訓(xùn)練方法,OpenCV里提供了兩個(gè)方法一個(gè)是很經(jīng)典的反向傳播算法BACKPROP,另一個(gè)是彈性反饋算法RPROP,,對(duì)第二種訓(xùn)練方法,,沒有仔細(xì)去研究過(guò),這里我們運(yùn)用第一種方法。 剩下就是關(guān)于每種訓(xùn)練方法的相關(guān)參數(shù),,針對(duì)于反向傳播法,,主要是兩個(gè)參數(shù),一個(gè)是權(quán)值更新率bp_dw_scale和權(quán)值更新沖量bp_moment_scale,。這兩個(gè)量一般情況設(shè)置為0.1就行了,;太小了網(wǎng)絡(luò)收斂速度會(huì)很慢,太大了可能會(huì)讓網(wǎng)絡(luò)越過(guò)最小值點(diǎn),。 我們一般先運(yùn)用它的默認(rèn)構(gòu)造函數(shù),,然后根據(jù)需要再修改相應(yīng)的參數(shù)就可以了。如下面代碼所示,,我們將迭代次數(shù)改為了5000次,。
4.3. 神經(jīng)網(wǎng)絡(luò)的訓(xùn)練我們先看訓(xùn)練函數(shù)的接口,然后按接口去準(zhǔn)備數(shù)據(jù),。
inputs:輸入矩陣,。它存儲(chǔ)了所有訓(xùn)練樣本的特征。假設(shè)所有樣本總數(shù)為nSamples,,而我們提取的特征維數(shù)為ndims,,則inputs是一個(gè)nSamples?ndims的矩陣,我們可以這樣創(chuàng)建它,。
我們需要將我們的訓(xùn)練集,經(jīng)過(guò)特征提取把得到的特征向量存儲(chǔ)在inputs中,,每個(gè)樣本的特征占一行,。 outputs:輸出矩陣。我們實(shí)際在訓(xùn)練中,,我們知道每個(gè)樣本所屬的種類,,假設(shè)一共有nClass類。那么我們將outputs設(shè)置為一個(gè)nSample行nClass列的矩陣,,每一行表示一個(gè)樣本的預(yù)期輸出結(jié)果,,該樣本所屬的那類對(duì)應(yīng)的列設(shè)置為1,其他都為0,。比如我們需要識(shí)別0-9這10個(gè)數(shù)字,,則總的類數(shù)為10類,那么樣本數(shù)字“3”的預(yù)期輸出為[0,0,1,0,0,0,0,0,0,0]; sampleWeights:一個(gè)在使用RPROP方法訓(xùn)練時(shí)才需要的數(shù)據(jù),,所以這里我們不設(shè)置,,直接設(shè)置為Mat()即可。 sampleIdx:相當(dāng)于一個(gè)遮罩,,它指定哪些行的數(shù)據(jù)參與訓(xùn)練,。如果設(shè)置為Mat(),,則所有行都參與。 params:這個(gè)在剛才已經(jīng)說(shuō)過(guò)了,,是訓(xùn)練相關(guān)的參數(shù),。 flag:它提供了3個(gè)可選項(xiàng)參數(shù),用來(lái)指定數(shù)據(jù)處理的方式,,我們可以用邏輯符號(hào)去組合它們,。UPDATE_WEIGHTS指定用一定的算法去初始化權(quán)值矩陣而不是用隨機(jī)的方法。NO_INPUT_SCALE和NO_OUTPUT_SCALE分別用于禁止輸入與輸出矩陣的歸一化,。 一切都準(zhǔn)備好后,,直接開始訓(xùn)練吧! 4.4. 識(shí)別識(shí)別是通過(guò)Cv_ANN_MLP類提供的predict來(lái)實(shí)現(xiàn)的,,知道原理的會(huì)明白,,它實(shí)際上就是做了一次向前傳播。
在進(jìn)行識(shí)別的時(shí)候,,我們對(duì)圖像進(jìn)行特征提取,,把它保存在inputs里,通過(guò)調(diào)用predict函數(shù),,我們得到一個(gè)輸出向量,,它是一個(gè)1*nClass的行向量,其中每一列說(shuō)明它與該類的相似程度(0-1之間),,也可以說(shuō)是置信度,。我們只用對(duì)output求一個(gè)最大值,就可得到結(jié)果,。這個(gè)函數(shù)的返回值是一個(gè)無(wú)用的float值,,可以忽略。 5. 車牌字符識(shí)別測(cè)試1,,我們需要讀取所有的訓(xùn)練樣本,,將它們的路徑在保存在vector<string>中。 這里面我的車牌字符,,因?yàn)?和I、0和O是一樣的,,所以數(shù)字加字母一共34類,,其中每類有200個(gè)樣本圖像,共34*200個(gè)訓(xùn)練樣本,。 2,,計(jì)算特征。我們按順序讀入圖像,,調(diào)用特征計(jì)算函數(shù),,把得到的結(jié)合保存在input對(duì)應(yīng)的行中,,同時(shí)把圖像對(duì)應(yīng)的預(yù)期輸出保存在output中。 3,,創(chuàng)建神經(jīng)網(wǎng)絡(luò),,這里我們計(jì)算得到的特征維數(shù)為48維,所以我們簡(jiǎn)單的設(shè)計(jì)一個(gè)3層的神經(jīng)網(wǎng)絡(luò),,輸入層有48個(gè)結(jié)點(diǎn),,隱藏層也為48個(gè)結(jié)點(diǎn),輸出層為34個(gè)結(jié)點(diǎn),。然后神經(jīng)網(wǎng)絡(luò)的訓(xùn)練方法選用BACKPROP,,迭代次數(shù)設(shè)置為5000次。 4,,調(diào)用訓(xùn)練函數(shù)進(jìn)行訓(xùn)練,,并保存訓(xùn)練得到的權(quán)值矩陣,直接調(diào)用save成員函數(shù)即可,。 nnetwork.save(“mlp.xml”); 5,,識(shí)別測(cè)試,我們可以用單張圖像進(jìn)行測(cè)試,,也可以選定一個(gè)測(cè)試集去進(jìn)行測(cè)試,,比如可以用一半的圖像作為訓(xùn)練集,一半的圖像作為測(cè)試集,。這里我們可以加載已經(jīng)訓(xùn)練好的權(quán)值矩陣,,而不用重新訓(xùn)練,只要開始有保存了xml文件,。但是記得你還是要?jiǎng)?chuàng)建一個(gè)網(wǎng)絡(luò)后,,才能加載進(jìn)來(lái)。
這里我簡(jiǎn)單的做了一下測(cè)試,,在這兩個(gè)特征下,,網(wǎng)絡(luò)設(shè)置為3層[48,48,34],一半圖像為測(cè)試集,,得到的識(shí)別率為98%,,我相信通過(guò)嘗試調(diào)整網(wǎng)絡(luò)的層數(shù)以及選用更好的特征,一定會(huì)得到更滿意的識(shí)別率,。PS(工作中用的是SVM識(shí)別器,,正常采集到的車牌,字符識(shí)別率在99.8%以上),。但是神經(jīng)網(wǎng)絡(luò)識(shí)別器有個(gè)很大的優(yōu)點(diǎn)就是,,一旦網(wǎng)絡(luò)訓(xùn)練好,識(shí)別需要的數(shù)據(jù)文件非常小,,而且速度很快,。 6. 字符樣本的下載看到文章下的評(píng)論多是需求字符樣本的,,希望拿到字符樣本的同學(xué)不要將其用于商業(yè)用途或者創(chuàng)建分享下載的鏈接。博文里用的樣本是每類200張圖像的測(cè)試樣本,,下面給出一份每類50個(gè)圖像的樣本子集,,我以為用來(lái)做學(xué)術(shù)測(cè)試已經(jīng)夠了,出于公司利益考慮,,請(qǐng)勿再向我索要完整樣本,。 百度網(wǎng)盤:http://pan.baidu.com/s/1mgLUWBm
|
|