OCR - 行駛證識別(SVM訓練及判斷篇二)

聲明 本文暫時禁止任何形式的轉載, 以下示例圖片為了不侵犯個人行駛證隱私,全部做打碼處理。


前言

人工智能這個課題研究的主要目的就是實現“機器人” *模擬人的能力 人最強大的地方在于大腦,可以不斷的學習積累經驗,繼而創新。機器識別圖像的過程,說白了就是在模擬人類識別的過程。在上一章做到了機器讀入圖片(模擬人類通過眼睛看到從三維空間到視覺上二維成像)我們接下來讓機器模擬人類記憶->積累經驗-> 下次看到-> 識別出的一個過程

基礎

我們判斷一個物體是 太陽?月亮? 是如何判別呢。是小時候我們還在上幼兒園時,老師指著 ?? = 太陽 ?? = 月亮 也就是圖像+標簽方式。機器就是小時候的我們,他不知道,他需要我們作為老師教授。SVM 支持向量機就是這個原理。我們把認識的過程叫訓練,人類會把這個訓練記在腦海里形成記憶片段,而機器會生成的叫訓練模型。
我們在上一章最后生成了想要的圖片,如下


image.png

那根據紅框區域截取圖片,我們把想要特征的圖片叫Positive,不想要的特征圖片叫Negative,依次會有以下圖片

Negative

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

Positive

image.png

我們把Positive的圖片告訴機器去記住,有這個特征的就是行駛證。把Negative的圖片告訴機器去記住,有這些特征的就不是行駛證。這樣,當這兩類數據足夠多時,能包容更多場景時,機器的識別率就會顯著提高。這里要實現機器識別一個很重要的方法就是SVM中文翻譯是支持向量機學習。 這名字聽起來就高大上有沒有。
在我的工程目錄下創建一個SVM包,包的結構如下

image.png

Model目錄 存在一個名稱為svm.xml的文件這就是訓練之后得到的模型(對比人類就是記憶片段),因為該模型的作用是判斷圖片是行駛證因此我們取名字叫“行駛證判斷模型”
test目錄train目錄, 先說train目錄就是字面意義“訓練”,教給機器去告訴他去記住具有Positive特征的圖片就是行駛證,具有negative特征的不是行駛證,用計算機表示就是1和0. 因此代碼上就是這樣做的,看代碼:

   void train() {
        //初始化,參數調試很重要,會影響識別率
        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));

        //獲得訓練數據
        cv::Ptr<cv::ml::TrainData> train_data = tdata();

        //訓練
        svm_->train(train_data);

        //訓練后的數據(記憶片段) 保存在指定文件里
        string svm_xml_ = "/Users/xiu/Documents/Company/workspace/ocr/ocr/resource/model/svm.xml";
        svm_->save(svm_xml_);
    }

看代碼注釋部分應該都會懂了。這就是一個訓練的完整過程。具體再看下獲得訓練數據,這一個代碼片段也是非常重要,說明一點c++工程我實現了SVM,但是官方封裝的Java接口,通過JNI方式去實現 SVM 始終會報錯,我的底層opencv是3.2版本的,如果Java工程可以實現請聯系我,我哪天抽空調通了也會單獨發文。
獲得訓練數據代碼片段:

 cv::Ptr<cv::ml::TrainData> tdata() {
        cv::Mat samples;
        std::vector<int> responses;
        //指定Negative和Positive數據所在目錄
        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);//提取特征,經過試驗彩色圖片識別率并不好
            feature = feature.reshape(1, 1);
            samples.push_back(feature);
            responses.push_back(int(1));// 是標記為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));//非,標記為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了
肯定有人在問了test目錄是什么。是這樣的,我們訓練出了模型,如果判斷該模型是好是壞呢。當然是拿測試數據來判斷了。原始數據為100的話,測試和訓練數據最好占比是 30% 和70% ,理論上訓練數據越多,識別率越高。沒有原始數據來源,幾乎沒法去做圖像識別,樣本數據是重中之重。有的人在開始做時,拿100%的原始數據去做訓練,然后用原始數據去測試,這樣是不對的。舉個例子,老師平常教授的知識,作為例子講解的題目。如果拿到考試當中,就無法去真正辨別學生該知識的真實情況。SVM也是同樣道理。
我們接下里拿訓練模型去判斷未知圖片是否為行駛證。代碼片段:

     * 判斷這些矩形是否含有行駛證,其中有一個是,就是
     */
    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;
    }

該過程就是通過第一篇處理后的圖片,得到若干矩形,具有行駛證特征的圖片則返回1,只要有一個大于1的圖片就是行駛證。說明其圖片就是行駛證。

結束語

通過SVM訓練,目前我的樣本庫Positive有300張,Negative有500張,現在的行駛證識別率能達到95%以上,不過還需要更多訓練更多種場景的樣本。后續第三章,我們回歸圖像處理,為第四章的ANN行駛證識別其中的文字來做鋪墊。 關于文字識別開始我走了一段彎路,后來沒有做下去,我想單獨拿一張來分享。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容