久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

OpenCV進(jìn)階之路:神經(jīng)網(wǎng)絡(luò)識(shí)別車牌字符 - 博客 - 伯樂在線

 mzsm 2015-02-22
原文出處: 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ì),,以下是算法步驟:

1
2
3
4
5
6
7
8
9
<1>將字符由RGB轉(zhuǎn)化為灰度,然后將圖像歸一化到16*8,。
<2>定義soble水平檢測(cè)算子:x_mask=[?1,0,1;?2,0,2;–1,0,1]和豎直方向梯度檢測(cè)算子y_mask=x_maskT,。
<3>對(duì)圖像分別用mask_x和mask_y進(jìn)行圖像濾波得到SobelX和SobelY,下圖分別代表原圖像,、SobelX和SobelY,。
<4>對(duì)濾波后的圖像,計(jì)算圖像總的像素和,,然后劃分4*2的網(wǎng)絡(luò),,計(jì)算每個(gè)網(wǎng)格內(nèi)的像素值的總和。
<5>將每個(gè)網(wǎng)絡(luò)內(nèi)總灰度值占整個(gè)圖像的百分比統(tǒng)計(jì)在一起寫入一個(gè)向量,,將兩個(gè)方向各自得到的向量并在一起,,組成特征向量。

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
void calcGradientFeat(const Mat& imgSrc, vector<float>& feat)
{
    float sumMatValue(const Mat& image); // 計(jì)算圖像中像素灰度值總和
    Mat image;
    cvtColor(imgSrc,image,CV_BGR2GRAY);
    resize(image,image,Size(8,16));
    // 計(jì)算x方向和y方向上的濾波
    float mask[3][3] = { { 1, 2, 1 }, { 0, 0, 0 }, { -1, -2, -1 } };
    Mat y_mask = Mat(3, 3, CV_32F, mask) / 8;
    Mat x_mask = y_mask.t(); // 轉(zhuǎn)置
    Mat sobelX, sobelY;
    filter2D(image, sobelX, CV_32F, x_mask);
    filter2D(image, sobelY, CV_32F, y_mask);
    sobelX = abs(sobelX);
    sobelY = abs(sobelY);
    float totleValueX = sumMatValue(sobelX);
    float totleValueY = sumMatValue(sobelY);
    // 將圖像劃分為4*2共8個(gè)格子,,計(jì)算每個(gè)格子里灰度值總和的百分比
    for (int i = 0; i < image.rows; i = i + 4)
    {
        for (int j = 0; j < image.cols; j = j + 4)
        {
            Mat subImageX = sobelX(Rect(j, i, 4, 4));
            feat.push_back(sumMatValue(subImageX) / totleValueX);
            Mat subImageY= sobelY(Rect(j, i, 4, 4));
            feat.push_back(sumMatValue(subImageY) / totleValueY);
        }
    }
}
float sumMatValue(const Mat& image)
{
    float sumValue = 0;
    int r = image.rows;
    int c = image.cols;
    if (image.isContinuous())
    {
        c = r*c;
        r = 1;   
    }
    for (int i = 0; i < r; i++)
    {
        const uchar* linePtr = image.ptr<uchar>(i);
        for (int j = 0; j < c; j++)
        {
            sumValue += linePtr[j];
        }
    }
    return sumValue;
}

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ù)。

1
2
CvANN_MLP::CvANN_MLP(const Mat& layerSizes, int activateFunc=CvANN_MLP::SIGMOID_SYM, double fparam1=0, double fparam2=0 );
void CvANN_MLP::create(const Mat& layerSizes, int activateFunc=CvANN_MLP::SIGMOID_SYM, double fparam1=0, double fparam2=0 );

上面是分別是構(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可以采用如下定義:

1
Mat layerSizes=(Mat_<int>(1,3)<<x1,x2,x3);

或者用一個(gè)數(shù)組來(lái)初始化:

1
2
int ar[]={x1,x2,x3};
Mat layerSizes(1,3,CV_32S,ar);

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è)。

1
2
3
4
5
6
7
8
CvANN_MLP_TrainParams::CvANN_MLP_TrainParams()
{
    term_crit = cvTermCriteria( CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 1000, 0.01 );
    train_method = RPROP;
    bp_dw_scale = bp_moment_scale = 0.1;
    rp_dw0 = 0.1; rp_dw_plus = 1.2; rp_dw_minus = 0.5;
    rp_dw_min = FLT_EPSILON; rp_dw_max = 50.;
}

它的參數(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次,。

1
2
CvANN_MLP_TRainParams param;
param.term_crit=cvTermCriteria(CV_TerMCrIT_ITER+CV_TERMCRIT_EPS,5000,0.01);

4.3. 神經(jīng)網(wǎng)絡(luò)的訓(xùn)練

我們先看訓(xùn)練函數(shù)的接口,然后按接口去準(zhǔn)備數(shù)據(jù),。

1
int CvANN_MLP::train(const Mat& inputs, const Mat& outputs, const Mat& sampleWeights, const Mat& sampleIdx=Mat(), CvANN_MLP_TrainParams params=CvANN_MLP_TrainParams(), int flags=0 );

inputs:輸入矩陣,。它存儲(chǔ)了所有訓(xùn)練樣本的特征。假設(shè)所有樣本總數(shù)為nSamples,,而我們提取的特征維數(shù)為ndims,,則inputs是一個(gè)nSamples?ndims的矩陣,我們可以這樣創(chuàng)建它,。

1
Mat inputs(nSamples,ndims,CV_32FC1); //CV_32FC1說(shuō)明它儲(chǔ)存的數(shù)據(jù)是float型的,。

我們需要將我們的訓(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í)際上就是做了一次向前傳播。

1
float CvANN_MLP::predict(const Mat& inputs, Mat& outputs) const

在進(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)。

1
2
3
4
5
6
7
8
9
10
11
12
int NNClassifier::classifier(const Mat& image)
{
    Mat nearest(1, nclass, CV_32FC1, Scalar(0));
    Mat charFeature;
    calcFeature(image, charFeature);
    neuralNetwork.predict(charFeature, nearest);
    Point maxLoc;
    minMaxLoc(nearest, NULL, NULL, NULL, &maxLoc);
    int result = maxLoc.x;
    return result;
}

這里我簡(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

 

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多