OCR - 行駛證識(shí)別(SVM訓(xùn)練及判斷篇二)

聲明 本文暫時(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片,如下


image.png

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

Negative

image.png
image.png
image.png
image.png
image.png
image.png

Positive

image.png

我們把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)如下

image.png

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)分享。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容