聲明 本文暫時(shí)禁止任何形式的轉(zhuǎn)載, 以下示例圖片為了不侵犯?jìng)€(gè)人行駛證隱私,全部做打碼處理。
前言
人工智能這個(gè)課題研究的主要目的就是實(shí)現(xiàn)“機(jī)器人” *模擬人的能力 人最強(qiáng)大的地方在于大腦,可以不斷的學(xué)習(xí)積累經(jīng)驗(yàn),繼而創(chuàng)新。機(jī)器識(shí)別圖像的過(guò)程,說(shuō)白了就是在模擬人類識(shí)別的過(guò)程。在上一章做到了機(jī)器讀入圖片(模擬人類通過(guò)眼睛看到從三維空間到視覺(jué)上二維成像)我們接下來(lái)讓機(jī)器模擬人類記憶->積累經(jīng)驗(yàn)-> 下次看到-> 識(shí)別出的一個(gè)過(guò)程
基礎(chǔ)
我們判斷一個(gè)物體是 太陽(yáng)?月亮? 是如何判別呢。是小時(shí)候我們還在上幼兒園時(shí),老師指著 ?? = 太陽(yáng) ?? = 月亮 也就是圖像+標(biāo)簽方式。機(jī)器就是小時(shí)候的我們,他不知道,他需要我們作為老師教授。SVM 支持向量機(jī)就是這個(gè)原理。我們把認(rèn)識(shí)的過(guò)程叫訓(xùn)練,人類會(huì)把這個(gè)訓(xùn)練記在腦海里形成記憶片段,而機(jī)器會(huì)生成的叫訓(xùn)練模型。
我們?cè)谏弦徽伦詈笊闪讼胍膱D片,如下

那根據(jù)紅框區(qū)域截取圖片,我們把想要特征的圖片叫Positive,不想要的特征圖片叫Negative,依次會(huì)有以下圖片
Negative






Positive

我們把Positive的圖片告訴機(jī)器去記住,有這個(gè)特征的就是行駛證。把Negative的圖片告訴機(jī)器去記住,有這些特征的就不是行駛證。這樣,當(dāng)這兩類數(shù)據(jù)足夠多時(shí),能包容更多場(chǎng)景時(shí),機(jī)器的識(shí)別率就會(huì)顯著提高。這里要實(shí)現(xiàn)機(jī)器識(shí)別一個(gè)很重要的方法就是SVM中文翻譯是支持向量機(jī)學(xué)習(xí)。 這名字聽(tīng)起來(lái)就高大上有沒(méi)有。
在我的工程目錄下創(chuàng)建一個(gè)SVM包,包的結(jié)構(gòu)如下

Model目錄 存在一個(gè)名稱為svm.xml的文件這就是訓(xùn)練之后得到的模型(
對(duì)比人類就是記憶片段),因?yàn)樵撃P偷淖饔檬桥袛鄨D片是行駛證因此我們?nèi)∶纸小靶旭傋C判斷模型”test目錄 與train目錄, 先說(shuō)train目錄就是字面意義“訓(xùn)練”,教給機(jī)器去告訴他去記住具有Positive特征的圖片就是行駛證,具有negative特征的不是行駛證,用計(jì)算機(jī)表示就是1和0. 因此代碼上就是這樣做的,看代碼:
void train() {
//初始化,參數(shù)調(diào)試很重要,會(huì)影響識(shí)別率
svm_ = cv::ml::SVM::create();
svm_->setType(cv::ml::SVM::C_SVC);
svm_->setKernel(cv::ml::SVM::RBF);
svm_->setDegree(0.1);
svm_->setGamma(0.1);
svm_->setCoef0(0.1);
svm_->setC(1);
svm_->setNu(0.1);
svm_->setP(0.1);
svm_->setTermCriteria(cvTermCriteria(CV_TERMCRIT_ITER, 20000, 0.0001));
//獲得訓(xùn)練數(shù)據(jù)
cv::Ptr<cv::ml::TrainData> train_data = tdata();
//訓(xùn)練
svm_->train(train_data);
//訓(xùn)練后的數(shù)據(jù)(記憶片段) 保存在指定文件里
string svm_xml_ = "/Users/xiu/Documents/Company/workspace/ocr/ocr/resource/model/svm.xml";
svm_->save(svm_xml_);
}
看代碼注釋部分應(yīng)該都會(huì)懂了。這就是一個(gè)訓(xùn)練的完整過(guò)程。具體再看下獲得訓(xùn)練數(shù)據(jù),這一個(gè)代碼片段也是非常重要,說(shuō)明一點(diǎn)c++工程我實(shí)現(xiàn)了SVM,但是官方封裝的Java接口,通過(guò)JNI方式去實(shí)現(xiàn) SVM 始終會(huì)報(bào)錯(cuò),我的底層opencv是3.2版本的,如果Java工程可以實(shí)現(xiàn)請(qǐng)聯(lián)系我,我哪天抽空調(diào)通了也會(huì)單獨(dú)發(fā)文。
獲得訓(xùn)練數(shù)據(jù)代碼片段:
cv::Ptr<cv::ml::TrainData> tdata() {
cv::Mat samples;
std::vector<int> responses;
//指定Negative和Positive數(shù)據(jù)所在目錄
string has_file_path_ = "/Users/xiu/Documents/Company/workspace/ocr/ocr/resource/src/train/positive";
string no_file_path_ = "/Users/xiu/Documents/Company/workspace/ocr/ocr/resource/src/train/negative";
std::vector<string> has_file_list_ = VLUtil::getFiles(has_file_path_, true);
std::vector<string> no_file_list_ = VLUtil::getFiles(no_file_path_, true);
for (string f : has_file_list_) {//是行駛證
auto image = cv::imread(f);
if (!image.data) {
continue;
}
cv::Mat feature;
VLUtil::getLBPFeatures(image, feature);//提取特征,經(jīng)過(guò)試驗(yàn)彩色圖片識(shí)別率并不好
feature = feature.reshape(1, 1);
samples.push_back(feature);
responses.push_back(int(1));// 是標(biāo)記為1
}
for (string f : no_file_list_) {//非行駛證
auto image = cv::imread(f);
if (!image.data) {
continue;
}
cv::Mat feature;
VLUtil::getLBPFeatures(image, feature);
feature = feature.reshape(1, 1);
samples.push_back(feature);
responses.push_back(int(0));//非,標(biāo)記為0
}
//生成TrainData
cv::Mat samples_, responses_;
samples.convertTo(samples_, CV_32FC1);
cv::Mat(responses).copyTo(responses_);
return cv::ml::TrainData::create(samples_, cv::ml::SampleTypes::ROW_SAMPLE,
responses_);
}
代碼意義還是看下注釋就OK了
肯定有人在問(wèn)了test目錄是什么。是這樣的,我們訓(xùn)練出了模型,如果判斷該模型是好是壞呢。當(dāng)然是拿測(cè)試數(shù)據(jù)來(lái)判斷了。原始數(shù)據(jù)為100的話,測(cè)試和訓(xùn)練數(shù)據(jù)最好占比是 30% 和70% ,理論上訓(xùn)練數(shù)據(jù)越多,識(shí)別率越高。沒(méi)有原始數(shù)據(jù)來(lái)源,幾乎沒(méi)法去做圖像識(shí)別,樣本數(shù)據(jù)是重中之重。有的人在開(kāi)始做時(shí),拿100%的原始數(shù)據(jù)去做訓(xùn)練,然后用原始數(shù)據(jù)去測(cè)試,這樣是不對(duì)的。舉個(gè)例子,老師平常教授的知識(shí),作為例子講解的題目。如果拿到考試當(dāng)中,就無(wú)法去真正辨別學(xué)生該知識(shí)的真實(shí)情況。SVM也是同樣道理。
我們接下里拿訓(xùn)練模型去判斷未知圖片是否為行駛證。代碼片段:
* 判斷這些矩形是否含有行駛證,其中有一個(gè)是,就是
*/
bool predict(const std::vector<string> &path) {
bool isVehicleLicenseOCR = false;
// svm_ = cv::ml::SVM::load(svm_xml_);
for (string f : path) {
auto image = cv::imread(f);
if (!image.data) {
std::cout << "error : file not exist" << f << std::endl;
continue;
}
cv::Mat feature;
VLUtil::getLBPFeatures(image, feature);
int predict = int(svm_->predict(feature));
std::cout << "file name :" << f << " predict: " << predict << std::endl;
if(predict>=1){
isVehicleLicenseOCR = true;
}
}
return isVehicleLicenseOCR;
}
該過(guò)程就是通過(guò)第一篇處理后的圖片,得到若干矩形,具有行駛證特征的圖片則返回1,只要有一個(gè)大于1的圖片就是行駛證。說(shuō)明其圖片就是行駛證。
結(jié)束語(yǔ)
通過(guò)SVM訓(xùn)練,目前我的樣本庫(kù)Positive有300張,Negative有500張,現(xiàn)在的行駛證識(shí)別率能達(dá)到95%以上,不過(guò)還需要更多訓(xùn)練更多種場(chǎng)景的樣本。后續(xù)第三章,我們回歸圖像處理,為第四章的ANN行駛證識(shí)別其中的文字來(lái)做鋪墊。 關(guān)于文字識(shí)別開(kāi)始我走了一段彎路,后來(lái)沒(méi)有做下去,我想單獨(dú)拿一張來(lái)分享。