Opencv2.4.9源碼分析-CascadeClassification(三)剖析_第1頁
Opencv2.4.9源碼分析-CascadeClassification(三)剖析_第2頁
Opencv2.4.9源碼分析-CascadeClassification(三)剖析_第3頁
Opencv2.4.9源碼分析-CascadeClassification(三)剖析_第4頁
Opencv2.4.9源碼分析-CascadeClassification(三)剖析_第5頁
已閱讀5頁,還剩9頁未讀, 繼續(xù)免費閱讀

付費下載

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

Opencv2.4.9源碼分析——CascadeClassification(三)下面我們以車牌識別為例,具體講解 OpenCV 的級聯分類器的用法。在這里我們只對藍底白字的普通車牌進行識別判斷,對于其他車牌不在考慮范圍內。而且車牌是正面照,略微傾斜可以,傾斜程度太大也是不在識別范圍內的。我們通過不同渠道共收集了 1545幅符合要求的帶有車牌圖像的照片(很遺憾,我只能得到這么多車牌照片,如果能再多一些就更好了! ),通過 ACDSee軟件手工把車牌圖像從照片中剪切出來,并統(tǒng)一保存為 jpg格式。為便于后續(xù)處理,我們把文件名按照數字順序命名,如圖8所示。然后我們把這些車牌圖像保存到 pos文件夾內。圖

8

藍底白字車牌圖像需要注意的是,在這里我們沒有必要把車牌圖像縮放成統(tǒng)一的尺寸更沒有必要把它們轉換成灰度圖像, 這些工作完全可以由系統(tǒng)完成。

(即正樣本圖像的大?。?,我們只需要告訴系統(tǒng)車牌圖像文件、車牌的位置,以及車牌的尺寸大小即可。為了高效的完成上述工作,我們編寫了以下代碼:[cpp]viewplaincopy 在CODE上查看代碼片派生到我的代碼片#include"opencv2/core/core.hpp"#include"opencv2/highgui/highgui.hpp"#include"opencv2/imgproc/imgproc.hpp"#include<iostream>#include<fstream>#include<string>usingnamespacecv;usingnamespacestd;intmain(intargc,char**argv){ofstreampostxt("pos.txt",ios::out);

//創(chuàng)建

pox.txt

文件if(!postxt.is_open()){cout<<"cannotcreatpostxtfile!";returnfalse;}//N表示車牌圖像的總數,c表示最終可以利用的車牌樣本圖像的數量intN=1545,c=0;intwidth,height,i;Stringfilename;Matposimage;for(i=0;i<N;i++){

//遍歷所有車牌圖像filename=to_string(i)+".jpg"; //得到當前車牌圖像的文件名posimage=imread("pos\\"+filename);//打開當前車牌圖像if(posimage.empty()){cout<<"cannotopen"+filename+"file!"<<endl;continue;}width=posimage.size().width;height=posimage.size().height;//如果當前車牌圖像的寬小于

//當前車牌圖像的寬//當前車牌圖像的高60,或高小于 20,則剔除該車牌圖像if(width<60||height<20){cout<<filename+"toosmall!"<<endl;continue;}//把當前車牌圖像的信息寫入

pos.txt

文件內postxt<<"pos/"

+ filename

+ "

1

0 0 "

+

to_string(width)

+ "

"

+to_string(height)<<endl;c++;

//累計}cout<<c;

//終端輸出

c值postxt.close();

//關閉

pos.txt

文件return0;}執(zhí)行完該程序后,在終端輸出得到的c值為1390,這說明有由于尺寸過小而被剔除。另外,在當前目錄下我們還得到了

155(1545-1390)個車牌圖像pos.txt文件,該文件正是系統(tǒng)所需要的,它的文件內容如圖 9所示。圖9pos.txt文件在pos.txt文件中,每一行代表一個圖像文件。我們以第一行為例,它表示pos文件夾內的0.jpg文件,后面的“1”表示該文件只有一個樣本圖像(即車牌),再后面的“00”表示該樣本圖像的左上角坐標,由于我們已經對圖像進行了剪切,每個jpg文件就是一幅完成的車牌,所以所有行的這三個變量都是“100”。最后的“450140”表示0.jpg文件的寬和高。我們收集了 10589幅大小不同的不含車牌圖像的無水印、 無logo、無日期的照片。這些照片統(tǒng)一轉換為 jpg格式,并且也是按照數字的順序命名,如圖 10所示。然后我們把這些照片放入neg文件夾內。圖10不含車牌圖像的照片這些照片的尺寸沒有要求, 只要大于正樣本圖像的尺寸即可, 因為系統(tǒng)是對這些照片進行剪切,從而得到與正樣本圖像尺寸相同的負樣本圖像,所以一幅照片可以得到若干個負樣本圖像。這些照片盡量保證多樣性,并且每幅照片的內容盡可能的豐富,當然最重要的一點是不能含有車牌信息。我們還需要為系統(tǒng)提供一個保存有這些照片信息的文本文件。 同樣的,我們也寫了一段簡單的程序來完成這個工作:[cpp]viewplaincopy 在CODE上查看代碼片派生到我的代碼片#include"opencv2/core/core.hpp"#include"opencv2/highgui/highgui.hpp"#include"opencv2/imgproc/imgproc.hpp"#include<iostream>#include<fstream>#include<string>usingnamespacecv;usingnamespacestd;intmain(intargc,char**argv){ofstreamnegtxt("neg.txt",ios::out); //創(chuàng)建neg.txt文件if(!negtxt.is_open()){cout<<"cannotcreatnegtxtfile!";returnfalse;}//N表示照片的總數, c表示最終得到的照片的數量intN=10589,c=0;inti;Stringfilename;Matposimage;for(i=0;i<N;i++){filename=to_string(i)+".jpg"; //照片文件名posimage=imread("neg\\"+filename); //打開當前照片if(posimage.empty()){cout<<"cannotopen"+filename+"file!"<<endl;continue;}negtxt<<"neg/"+filename<<endl; //向neg.txt文件寫入照片文件名c++; //累加}cout<<c; //終端輸出 c值negtxt.close(); //關閉neg.txt文件return0;}執(zhí)行完該程序后,在當前目錄下得到了 neg.txt文件,它的文件內容如圖 11所示。以上內容準備好后,我們就可以利用

Opencv

提供的相關程序得到能夠識別車牌的級聯分類器了。首先在D盤下新建 plate文件夾,我們把前面提到的保存有大量照片圖像的 pos和neg這兩個文件夾、以及 pos.txt和neg.txt這兩個文本文件復制到 plate文件夾內,再在 plate文件夾內新建data文件夾(后面需要)。由于本人的電腦是 64位win7系統(tǒng),編譯器使用的是 MicrosoftVisual Studio 2012,因此需要從 opencv/build/x64/vc11/bin 文件夾內復制opencv_createsamples.exe和 opencv_traincascade.exe這兩個文件到 plate 文件夾內。opencv_createsamples.exe用于創(chuàng)建系統(tǒng)所需的正樣本 vec文件,opencv_traincascade.exe用于訓練級聯分類器。這兩個文件都需要在命令行下運行。opencv_createsamples.exe所需的參數較多,這里我們只把要用到的參數進行講解:-info:用于表示含有車牌照片的文本文件,即 pos.txt-bg:用于表示不含車牌照片的文本文件,即 neg.txt-vec:輸出的正樣本 vec文件名,我們把這個文件命名為 pos.vec-num:車牌照片圖像的數量,即

1390-w:正樣本圖像的寬(像素)-h:正樣本圖像的高(像素)后兩個參數需要我們根據實際情況填寫, 由于我們只對藍底白字的車牌進行識別, 這類車牌的實際尺寸為 440mm×140mm,我們必須要保持正樣本圖像的寬和高也是這個比例,而且寬和高不能過大,更不能過小。綜合考慮,我們選擇: -w為58,-h為18。在前面我們準備車牌照片時,并沒有把車牌縮放成 58×18這個尺寸,這是因為opencv_createsamples.exe會根據-w和-h這兩個參數對圖像進行統(tǒng)一縮放處理的,所以前面就沒有處理。最終的opencv_createsamples.exe命令為:opencv_createsamples.exe-infopos.txt-bgneg.txt-vecpos.vec-num1390-w58-h18為方便起見,我們把這個命令保存到 createsamples.bat批處理文件中,這樣只要執(zhí)行該文件即可。執(zhí)行的結果如圖 12所示,并且在 plate文件夾內會生成 pos.vec文件。圖12opencv_createsamples.exe執(zhí)行結果下面就要執(zhí)行opencv_traincascade.exe來訓練級聯分類器,該命令所需要的參數也較多,但都很重要,它們的含義如下:-data:文件夾名,用于保存訓練生成的各種 xml文件,該文件夾一定要事先創(chuàng)建好,否則系統(tǒng)會報錯,在這里,我們定義該文件夾名為 data,它已在前面創(chuàng)建好-vec:由opencv_createsamples.exe程序生成的正樣本 vec文件,即 pos.vec-bg:用于表示不含車牌照片的文本文件,即 neg.txt-numPos:訓練級聯分類器的每一級分類器(即強分類器)時所用的正樣本數目-numNeg:訓練級聯分類器的每一級分類器(即強分類器)時所用的負樣本數目-numStages:最終得到的級聯分類器的級數,我們設置為 12-precalcValBufSize:用于存儲預先計算特征值的內存空間大小,單位為 MB-precalcIdxBufSize:用于存儲預先計算特征索引的內存空間大小,單位為 MB-stageType:強分類器的類型, 目前只實現了 AdaBoost,因此唯一的值(缺省值)為BOOST-featureType:特征類型,HAAR(缺省值),LBP或HOG-w:正樣本圖像的寬,必須與 opencv_createsamples.exe命令的參數一致,即 58-h:正樣本圖像的高,必須與 opencv_createsamples.exe命令的參數一致,即 18-bt:AdaBoost的類型,DAB,RAB,LB或GAB(缺省值)-minHitRate:原理部分提到的每級分類器的最小識別率-maxFalseAlarmRate:原理部分提到的每級分類器的最大錯誤率-weightTrimRate:用于決策樹的剪枝,缺省值為 0.95-maxDepth:決策樹的最大深度,缺省值為 1,即該決策樹為二叉樹(樹墩形)-maxWeakCount:強分類器所包含的最大決策樹的數量,該值也與最大錯誤率有關,我們定義該值為150-mode:如果特征為HAAR,則該參數決定了使用哪種HAAR狀特征(見圖1),BASIC(缺省值)、CORE或ALL下面我們就重點介紹幾個重要參數的選取。 由于本人的計算機的內存為 16G,為了最大化的利用該內存,我們把 -precalcValBufSize和-precalcIdxBufSize 這兩個參數值都定義為 5000,即5G。最小識別率和最大錯誤率決定了訓練時間的長短和識別的質量,我們定義這兩個值分別為0.999和0.25。-numPos指的是訓練強分類器時所用的正樣本數量,它并不是全體正樣本的數量,原則上該值越大,分類器的質量越好,但還要考慮識別率,如果識別率設置得不高,會有一些正樣本被識別為負樣本,因此要有一定的冗余,當然系統(tǒng)也考慮到了這點,即如果正樣本都用完了,并且還沒有達到numPos所指定的數量,則系統(tǒng)會調整該值為實際的數量(詳細內容見前面的源碼分析部分)。我們設置該值為1300。-numNeg設置為多大似乎還沒有定論,但通過閱讀Viola&Jones算法的原文發(fā)現,他們使用9832個正樣本(4916個人臉圖像,再加上它們的垂直鏡像圖像)和10000個負樣本,正、負樣本的數量接近于1:1,因此我們設置 numNeg為1350。最終的opencv_traincascade.exe命令為:opencv_traincascade.exe -data data-vec pos.vec -bg neg.txt-numPos 1300 -numNeg1350 -numStages 12 -precalcValBufSize 5000 -precalcIdxBufSize 5000 -w58 -h18 -maxWeakCount 150 -modeALL -minHitRate 0.999 -maxFalseAlarmRate0.25同理,我們也把這個命令保存到批處理文件 train.bat中。這里還需要注意一點的是:參數的大小寫一定要分區(qū),否則系統(tǒng)出錯。圖14opencv_traincascade.exe執(zhí)行過程中輸出的第 3級強分類器的信息在執(zhí)行該命令時,終端首先輸出一些參數信息,如圖 13所示。然后是輸出級聯分類器的每級強分類器的訓練信息,因為我們設置了numStages為12,所以一共有12個強分類器:0-stage至11-stage。圖14所示為第3級強分類器的信息。下面我們逐條分析這些信息的含義:=====TRAINING3-stage=====<BEGIN表示開始訓練第3級強分類器。POScount:consumed1300:1302在訓練本級強分類器時,能夠使用1300個正樣本圖像,而這1300個正樣本圖像是從1302個正樣本圖像集中選取出來的,也就是說此時有兩個正樣本沒有被識別出來。前面的1300正是opencv_traincascade.exe命令中參數numPos所指定的數量,有時這個值會小于numPos,說明numPos設置過大,并且最小識別率設置的較小,從而導致正樣本圖像數量不足。后面的1302可以用來表示當前級聯分類器的識別率,即由 0-stage、1-stage、2-stage組成的級聯分類器的識別率。此時的識別率為 99.846%,因為1300÷1302=0.99846。NEGcount:acceptanceRatio1350:0.00620359在訓練本級強分類器時,能夠使用1350個負樣本圖像,這個數正是opencv_traincascade.exe命令中參數numNeg所指定的數量,當然這個數也有可能小于numNeg,這是因為前面信息中POScount的數值不等于numPos所致,具體數值的大小見源碼分析。后面的0.00620359表示負樣本的接受率,也就是當前強分類器之前的所有強分類器(0-stage、1-stage、2-stage)構成的級聯分類器的錯誤率,即經過當前級聯分類器預測后,這些被預測為正樣本而實際為負樣本的1350幅圖像是從多少個負樣本圖像中得到的。級聯分類器的特點是后一級的強分類器只接收那些前面分類器認為是正樣本的數據,把負樣本預測為正樣本,這種情況會隨著訓練級數的增加,困難程度也在增加,當然這種困難程度還與opencv_traincascade.exe命令中所設置的最大錯誤率maxFalseAlarmRate有關,錯誤率設置的越低,困難程度會越大。以本級為例,這1350個負樣本是從二十多萬個負樣本中選擇出來的,計算公式為:1350÷0.00620359≈217615。在本例的最后一級強分類器的訓練中,這個數值甚至會高達十億。所以訓練過程中的時間消耗主要就在這里。 在沒有顯示該行信息之前, 終端輸出的是下列信息:NEGcurrentsamples:XXXX。XXXX代表著當前時刻得到的負樣本數量,這個數值會逐漸增加,當增加到1350時,則會正常顯示上面的信息。當此時得到的級聯分類器的錯誤率小于我們所設置的錯誤率時 (以此時為例,當前已得到了 3個強分類器:0-stage、1-stage、2-stage,現在要訓練第4個強分類器3-stage,當這個強分類器訓練好后,這4個強分類器構成的級聯分類器應該滿足的最大錯誤率為:0.25×0.25×0.25×0.25=0.00390625),則系統(tǒng)會停止訓練,因為當前得到的級聯分類器已經滿足了要求,無需再訓練下去了。Precalculationtime: 52.337表示預先計算特征值所消耗的時間,即在沒有構建強分類器之前,我們就把一部分特征值計算好了,該值與opencv_traincascade.exe命令中的參數precalcValBufSize和precalcIdxBufSize有關,也就是我們事先為此開辟的內存越大,所保存的特征值就越多,因此計算這些特征值所花費的時間就越長。由于在構建強分類器之前,要用到的特征值都已計算好,所以構建強分類器的時間就大大縮短了。+------+-------------+-------------+|N|HR|FA|+------+-------------+-------------+|1|1|1|+------+-------------+-------------+|2|1|1|+------+-------------+-------------++------+-------------+-------------+|10|0.999231|0.336296|+------+-------------+-------------+|11|0.999231|0.228148|+------+-------------+-------------+N表示當前強分類器的弱分類器(即決策樹)的訓練得到的數量,HR表示當前強分類器的識別率,FA表示當前強分類器的錯誤率。我們從倒數第2行開始,此時訓練得到了10棵決策樹,識別率為99.9231%,錯誤率為33.6296%,識別率滿足了要求,即大于最小識別率99.9%,但錯誤率不滿足要求,即它大于最大錯誤率25%,所以還需要繼續(xù)訓練,當又得到了一棵決策樹時(即此時有11棵決策樹),識別率和錯誤率都滿足了要求(99.9231%>99.9%,22.8148%<25%)。END>表示此時該級的強分類器已經得到,因為識別率和錯誤率都滿足了要求,所以此級強分類器的訓練結束。Traininguntilnowhastaken0days0hours27minutes2seconds.表示到目前為止,訓練級聯分類器共用時 27分2秒。圖15顯示了整個級聯分類器訓練完成后的界面,可以看出一共訓練了算機的CPU是IntelCorei5-4690K。如果我們把識別率和錯誤率分別改為需要一天多的時間,如果再把級數調整為13級,則需要6天。

10多個小時。我的計0.9995和0.2,則當訓練結束后,在data文件夾內會得到據,我們利用它就可以識別出車牌。

cascade.xml文件,這正是我們需要的級聯分類器數下面的程序是一個簡單的應用:[cpp]viewplaincopy 在CODE上查看代碼片派生到我的代碼片#include"opencv2/core/core.hpp"#include"opencv2/highgui/highgui.hpp"#include"opencv2/imgproc/imgproc.hpp"#include"opencv2/objdetect/objdetect.hpp"#include<iostream>#include<fstream>#include<string>usingnamespacecv;usingnamespacestd;intmain(intargc,char**argv){CascadeClassifierssifier("cascade.xml");Matimg=imread("car.jpg"); //讀取照片vector<Rect>plates; //代表車牌區(qū)域

//實例化級聯分類器//車牌識別,默認識別的最小車牌為正樣本的面積(這里就是片的面積,即只能識別面積為58×18以上的車牌

58×18),最大為整幅照classifier.detectMultiScale(img,plates);for(intI=0;i<plates.size();i++) //畫出車牌區(qū)域rectangle(img,plates[i],Scalar(255,0,255),2);imshow("plates",img);waitKey(0);return0;}圖16識別結果圖16為運行的效果。由于手上的車牌照片不多,無法對識別效果做全面的衡量,但從不多的實驗結果來看,雖然有錯檢的情況,檢測到的車牌也有不完整的現象,但基本上能夠滿足要求。我通過一些實驗發(fā)現,單純的提高識別率或降低錯誤率、以及增加級數似乎都不能改善上述問題,我認為只有增大正樣本的數量才是提高識別質量的有效方法。下面是對視頻文件進行車牌識別:[cpp]viewplaincopy 在CODE上查看代碼片派生到我的代碼片#include"opencv2/core/core.hpp"#include"opencv2/highgui/highgui.hpp"#include"opencv2/imgproc/imgproc.hpp"#include"opencv2/objdetect/objdetect.hpp"#include<iostream>#include<fstream>#include<string>usin

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論