OCR - 行駛證識別(行駛證判斷篇一)

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


感想

做了近一個月的圖形圖像識別,從互聯網,書籍上了解了最基礎的圖形圖像知識以及處理知識。對圖形圖像可以說做了基本入門。基礎算法是最重要的!這個為以后調整參數和自己分析圖片幫助都很大。業務需求不一樣,也許用同樣的處理流程,調整不同的參數和邏輯就可以達到目的。目前有個現象,機器學習的人不多,機器學習還被分為例如語音識別,自然語言處理,圖像識別等等,圖像識別又有做各種業務的,所以能碰上業務要求一樣的少之又少。所以互聯網資料甚少,開源能商業用的產品基本不要想,3、4百人的群可能一天都超不多20句技術溝通,作者問問題幾乎得不到回答。底層庫是C/C++所寫,沒有這方面經驗的人看代碼,寫代碼會非常辛苦。這也是該技術門檻高,回報大的所在。因此學習機器學習人首先要有毅力,獨立學習,獨立解決問題,獨立探索,開放性思維,與大家共勉之!

思路分析

一、我們常常會有各種證件來證明自己,比如出生證,護照。那么“行駛證如何證明自己是一張行駛證呢?” 這句話非常繞口,但實際就是這么一回事。隨便一張照片如何判斷是不是行駛證,在實際用戶上傳的照片中,用戶最有可能上傳的就是行駛證照片,本人照片,小貓小狗車照片等三大類。 我們發現行駛證最明顯的特征是,在其最上方明確的寫著“中華人民共和國機動車行駛證”字樣,那么好, 如果照片上有這個字樣,不就說明是一張行駛證了么!
二、因為一張用戶上傳的圖可能會很大,比如1080x720的,再加上是彩色圖,可能都有幾百K,這個識別對人類眼睛來講不會造成很大負擔,你可能0.幾秒就可以判斷出到底是不是行駛證,但對于機器(電腦)來說,他只懂得0和1,如何判斷?我們可以通過對圖片做一系列處理挖掘其特征,分割我們感興趣矩形區域,這樣機器處理起來就相對容易很多了,下面會講。
三、我們判斷一個物體是 太陽?月亮? 是如何判別呢。是小時候我們還在上幼兒園時,老師指著 ?? = 太陽   ?? = 月亮    也就是圖像+標簽方式。機器就是小時候的我們,他不知道,他需要我們作為老師教授。SVM 支持向量機就是這個原理。我們把認識的過程叫訓練,人類會把這個訓練記在腦海里形成記憶片段,而機器會生成的叫訓練模型,我們取個名字叫《 行駛證判斷模型》 有了這個模型,機器下次看到圖片是 會告訴我們,這到底是不是行駛證。

行駛證特征提取大概流程

1.原圖
2.圖像統一寬度,防止圖片過小,影響現有參數,所以取相同寬度等比縮放
3.圖像濾波(高斯低濾波 也叫高斯模糊)
4.灰度化處理   
5.二值化(局部處理算法)
6.形態學操作 (閉操作)
7.取輪廓
8.去掉邏輯上不符合要求的矩形,做過濾
9.截取感興趣區域并輸出

接下來一步步解釋采用這種方式處理圖片的作用以及效果

原圖展示

image.png

原圖統一寬度

image.png

我設置的是寬度1000px 高度根據圖片的比例自適應,這樣的好處是避免一些圖片極端過大或者過小,影響以后的參數,按理論上講圖片大小不會影響識別率,但是統一尺寸可以讓參數更好調整。舉個例子形態學閉操作的核大小參數如果適應寬度1000px的圖像,如果放在寬度300px的圖像上,那結果完全不是自己想要的。但是如果圖像統一了寬度(或者高度)按比例縮放了,那么參數就容易調整的多。

高斯模糊

image.png

高斯模糊主要是為了去掉圖片上的噪點。噪點是什么呢? 可以想一下你在馬路上打電話,這個時候周圍環境的車的喇叭聲,周圍人說聲音,小鳥嘰嘰喳喳的叫聲對你聽筒聲音有了干擾,就是噪聲。在相機成像過程中也會出現類似的噪點。
去掉噪點的好處是,忽略了圖片上無用信息,減少了數據量。你可以認為去掉了圖片中你不關心的像素。
具體講解高斯濾波請看阮一峰講的高斯濾波
話說阮大俠講的也不是很清楚,其實濾波分為高低之分,高斯模糊叫高斯低通道濾波才準確的哈。詳細了解濾波知識
代碼

   //! 圖像濾波,處理噪點
    cv::Mat image_filter;
    int k_width = 7;
    int k_height = 7 ;
//    boxFilter(image, image_filter, -1,cv::Size(3,3));//方塊濾波
//    blur(image, image_filter, cv::Size(3, 3));//均值濾波
    GaussianBlur(image, image_filter, cv::Size( k_width, k_height), 0, 0 );//高斯濾波
    if( !image_filter.data ){
        std::cout << "image is not exist" << std::endl;
        return -1 ;
    }
    cv::imwrite(filter_name,image_filter);
    cv::namedWindow("image", CV_WINDOW_AUTOSIZE);
    cv::imshow("image_filter", image_filter);
    cv::waitKey();

k_widthk_height分別是高斯內核的寬和高,兩個值可以不相等,但必須是正值,奇數。亦可為0

灰度化處理

image.png

圖像的灰度化即是將彩色圖像轉化成為灰度圖像的過程成為圖像的灰度化處理。彩色圖像中的每個像素的顏色有R、G、B三個分量決定,而每個分量有255中值可取,這樣一個像素點可以有1600多萬(255255255)的顏色的變化范圍。而灰度圖像是R、G、B三個分量相同的一種特殊的彩色圖像,其一個像素點的變化范圍為255種,所以在數字圖像處理種一般先將各種格式的圖像轉變成灰度圖像以使后續的圖像的計算量變得少一些。
OpenCV中代碼實現

 //! 轉成灰度圖并展示
    cv::Mat grey;
    cvtColor(image, grey, CV_BGR2GRAY);
    if( !grey.data ){
        std::cout << "image_gary is not exist" << std::endl;
        return -1 ;
    }
    cv::imwrite(grey_name,grey);
    cv::namedWindow("image", CV_WINDOW_AUTOSIZE);
    cv::imshow("image_grey", grey);
    cv::waitKey();

圖片的灰度化的最有利的是顏色變少,數據量變少,提高計算效率。
但黑白圖片的識別率會相應降低。舉個例子,貓有很多品種,如果是彩色圖片你可容易記住它的特征。但是如果是黑白圖片,你下次再見到相同品種的貓時,恐怕你就不太容易辨認了。機器學習一樣的道理。要時刻記住機器學習就是模擬人類的記憶,總結,判斷,推測。

直方圖均衡化 ?

直方圖如果有攝影的朋友肯定會知道,照片的對比度,曝光度,直方圖就是展示了這一關系。直方圖越均衡,像素分布及起伏越均勻則照片的顏色對比和反差越小。
處理后的圖片

image.png

我們來看下代碼

  //! 直方圖均衡化  用這個效果似乎不太好 暫時舍掉
    cv::Mat image_hist;
    equalizeHist(grey,image_hist);
    if( !grey.data ){
        std::cout << "image_hist is not exist" << std::endl;
        return -1 ;
    }
    cv::imwrite(hist_name,image_hist);
    cv::namedWindow("image", CV_WINDOW_AUTOSIZE);
    cv::imshow("image_grey", image_hist);
    cv::waitKey();

經過大量圖片對比,我肉眼發現,很多圖片不用直方圖均衡化處理會更加的好。因為很多人在拍攝照片時,底部背景是黑色車座椅,或者方向盤之類的,總之會導致本來清晰的圖片,整個都變的灰色了。這樣二值化反而不太好。
!!!直方圖均衡化暫時舍掉!!!

二值化

二值化是選定一個像素等級的閾值 0~255之間,圖片只存在0或者255 也就是生產黑白圖,這樣去把圖像的里的物體輪廓展示出來。那么這個閾值到底選擇哪個好呢,有一個現成的算法叫OTSU,它會根據圖像中具體的灰度值選擇一個合理值,處理結果看圖

image.png

但是如果圖片的有光照不均勻如圖

image.png

再經過OSTU算法進行二值化處理會是什么樣子呢?如圖

圖片.png

哇塞,怎么變成這樣了。我的文字區域呢?我一番思考知道原因了,原來二值化做的是全局處理,但是這張圖片正好有光照從圖片上明顯看出分隔,這樣一個閾值就有些不合理了,似乎應該分塊處理,是了,opencv想到這個情況了,提供了局部處理函數,我們來看下整個代碼,包括全局處理的代碼。

 //! 二值化
    int blockSize = 25;
    int constValue = 10;
    cv::Mat image_threshold;
//    cv::threshold(image_hist , image_threshold ,0,255,CV_THRESH_OTSU); //整體二值化
    cv::adaptiveThreshold(grey, image_threshold, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY_INV, blockSize, constValue);//局部二值化
    cv::imwrite(threshold_name,image_threshold);
    cv::imshow("image_threshold", image_threshold);
    cv::waitKey();

換成局部二值化處理,效果好多了,問題解決。如圖

圖片.png

形態學操作

形態學有諸如 開/閉/頂帽/黑帽/腐蝕/膨脹操作 ,形態學操作的目的是為了使得原本白色區域連成一片的效果,如下:

圖片.png

請忽略我黃色圓圈,這是我后來通過作圖軟件添加上去的,是為了更好說明,經過形態學閉操作處理后的圖片,并不會產生黃圈
我們看到,白色區域就是我們之前想要的文字區域啊,真的是太好了! 已經找到有價值的區域位置了,這樣我們在原圖上截取有價值圖片,然后計算機處理的數據進一步減少!速度更快!準確性更高!
當然,這種方式肯定會有一些區域不是我們想要的。比如左下角的區域,原圖是紅色水印位置。其實這個信息對于咱們來講是無用信息,如果能把它去掉,不用說 對于咱們的識別速度+準確度又會提高了不少。
圖片的水印是紅色的,另外駕駛證背景注意看會有淺紅色,如果使用HSV調整參數是可以找到紅章部分的,但是每張圖情況不一樣這個參數調整必須是動態的,就要有另外限制條件,比如二值化后的圖像是個矩形才去掉,等等。還有一種思路,紅章肯定都是在標準化行駛證圖像的左下角,在左下角做生長算法,找到合適種子點就可以完整的取到紅章矩形,這倆種思路都可以繼續往深入研究,如果其他朋友有思路,可以聊聊。

取輪廓

代碼

vector<vector<Point> > contours;
        findContours(morphology, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);

我們做了取輪廓操作,同時為了直觀看到效果,我加入了代碼在原圖上畫輪廓,看下效果

image.png

我在原圖上畫出了我們得到的所有矩形,我們想要的頭部帶有“中華人民共和國機動車行駛證”字樣的矩形,那么其他矩形對我們來說就屬于Negative類型圖樣。盡量的在合理邏輯下過濾,這個過濾條件有個度的把握,比如如果就針對這一張圖片,通過Positive圖片面積就能把其他矩形做到完全過濾,但是不同圖片這個矩形幾乎不能一樣,所以這樣你的這個流程意義就不大了。我們的目的是盡可能過濾掉明顯不是Positive的矩形。所以有了下面的過濾參數設置。

 if ( !(1.0 * rect.y > 100 || 1.0 * rect.width * rect.height < 510.0f || rect.x == 0 || rect.y == 0) ) {
                outRects.push_back(rect);
                cv::Mat tempImg;
                zoom(rect).copyTo(tempImg);
                string filename = folder_out + "/"+VLUtil::getFileName(file_path_,false)+"_"+VLUtil::int2str(i) + ".jpg";
                files.push_back(filename);
                imwrite(filename, tempImg);
            }

這段代碼的過濾條件是

  1. 矩形的y軸 >100的去掉,我參考了很多張圖片,得出的數據
    2.矩形的寬*高 = 面積 小于510 去掉,去掉了過小的矩形
  2. 矩形的開始坐標x,y是0的去掉
    然后就得了相對少的矩形,如圖所示


    image.png

我們會發現剩下的矩形不多了,其中包含我們想要的特征 - 帶有中華人民共和國機動車行駛證字樣的矩形。OK!非常棒!

這些矩形就是SVM的訓練樣本,請繼續關注下一篇文章,如果做SVM訓練,完成行駛證的識別工作。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,595評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,560評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,814評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,224評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,444評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,988評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,804評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,998評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,237評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,706評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,993評論 2 374

推薦閱讀更多精彩內容