1. 程式人生 > >車牌識別專案——當前技術(1)

車牌識別專案——當前技術(1)

不多說別的了,現在簡單總結一下幾個模組的技術問題和我的感想。

2. 目前使用的技術

車牌識別的模組雖然有時候不那麼清楚,但大體還是劃分為三個部分:定位,分割和識別。這中間涉及很多無法被包含在這三個模組中的重要功能,比如去噪、二值化、傾斜校正。當前是深度學習火爆的年代,我也從網路上看到過不分割直接識別的深度學習方法,與連筆手寫體的識別有些類似之處。

因為導師對新技術有些抵觸(主要因為它對硬體的需求),所以我還是採用比較傳統的技術來做,模組劃分也採用定位、分割、識別的傳統劃分。

2.1. 車牌定位

目前採用的是豎直邊緣加數學形態學的方法。在提取候選區域後,再使用先驗知識(車牌區域形狀,字元個數,位置等等)進行篩選。

2.1.1 豎直邊緣和數學形態學

這種方法網上有各種講解和實現,在開源的車牌識別庫EasyPROpenALPR中也都有比較不錯的實現,原理我這裡不再多說。事實上所有技術的原理我今天都不再多說了,因為都是各種基本的套路。

這種方法的好處是簡單和有效,在比較好的引數下,對大多數車牌都能定位到車牌區域。因此初期一直考慮在這種方法基礎上進行修改。

這種方法有幾個難以解決的缺陷,導致引數的調整十分繁瑣:

  1. 對使用場景必須具有很好的瞭解。比如車牌的大體位置,車牌在整個場景中所佔百分比等等。為了使車牌內容能夠完全融合,必須要知道字元豎直邊緣之間的最大距離。由於中國車牌在第二第三個字元之間有一個時隱時現的白點,而第二和第三個字元的差異可能也會導致它們之間的距離比較遠,因此形態學SE形狀的選擇十分棘手。
  2. 對異常光照敏感。夜間補光燈會打在車體上,不管什麼顏色的車,都會產生亮白的光斑,車牌周圍的區域極易與車牌融合在一起,可能會產生很大的區域。
  3. 永遠達不到精確,有時候會包含很多車牌周圍的背景。

在對這種方法的各種試驗,包括調整引數,根據先驗進行篩選,等等之後,因為魯棒性不好,環境情況複雜,我開始考慮其他的思路。

2.1.2 目標識別思路

在國外的開源車牌專案OpenALPR中,使用的是Cascade Classifier進行定位,整體思路是目標識別中常用的Haar-like或LBP特徵配合Cascade Adaboost分類器,在多尺度上識別場景中的目標物體。OpenALPR中使用的是LBP特徵,有關這種特徵網上也能查到很多介紹,跟HOG,Haar之類的差不多,都不復雜。使用LBP比Haar好的地方是訓練速度會快很多,因為全部是整數。

影象特徵提取三大法寶:HOG特徵,LBP特徵,Haar特徵
這種方法之所以去嘗試,是因為最近獲得了2000多張車牌照片,感覺在這些資料的支援下應該能去嘗試機器學習的方法。

這種方法我從上一週就開始嘗試,但是取得的效果不盡如人意。我想主要因為以下幾個方面的問題:

  • 正樣本是用EasyPR的定位方法獲取的,沒有完全獲取到所有的車牌,而且獲取到的車牌經過了傾斜校正。某些正樣本不包含完整的車牌區域,例如漢字缺失。
  • 負樣本中混有一些包含了正樣本的區域。因為太多而沒有仔細去篩選。
  • 對整個方法各種不瞭解,沒有好好去決定引數和選取樣本。

昨天一天我用imageclipper工具標定了這些資料,把所有的車牌區域都截取了出來。這個工具雖然簡單但是很好用,應該是專為標資料而生的,在windows下面編譯有問題,直接在這裡可以下到binary。這種近似苦力的工作雖然讓人難受,但是大量資料也是訓練分類器所必須的。對於負樣本,就在場景圖片中隨機擷取不包含車牌的背景就好。在網上看到的經驗中,對正負樣本的個數眾說紛紜,有說1比5,有說1比3,也有說2比1。這種事情還是自己去嘗試一下比較好。

在最新一輪的訓練中,我使用了正樣本2300張,負樣本6000張。

正樣本例子:
正樣本

負樣本例子:
負樣本

在有資料之後,使用opencv的createsamples和traincascade命令進行訓練。在opencv的官方文件中有詳細說明。 為了快速生成樣本描述檔案、生成不包含正樣本的負樣本區域、生成訓練引數,我寫了一些python指令碼來輔助進行訓練。這些指令碼都很簡單,很容易修改。

在opencv提供的訓練程式中, opencv_createsamples.exe這個程式可以指定一張圖片,生成多個包含該圖片的正樣本vec檔案;也可以根據正樣本描述檔案來生成vec檔案。如果是前者,那麼正樣本會被進行一定的變換之後,隨機放置在一些負樣本上,從而增加正樣本的個數。因此此時還需要指定負樣本描述檔案。根據opencv官方文件中的描述,這種方法通常適用於純剛性物體,例如opencv的徽標。如果是後者,那麼就不會對正樣本進行變形。

如果用第一種方法建立.vec檔案,那麼多個車牌將會生成多個.vec檔案。我的python指令碼中有一個merge_vec.py檔案,可以用來合併這些成為單獨的.vec檔案。

我嘗試了這種方法之後發現,由於會把正樣本放置在負樣本中,因此定位的結果中會帶有很多不包含車牌的區域。因此我認為這種方法並不適合我們的應用。

另外,在訓練過程中,還有以下幾個問題需要注意:

  • 負樣本描述檔案中的路徑。在opencv_createsample.exe中,你需要填寫由圖片目錄開始的相對路徑。例如,你把圖片存在neg/img中,描述檔案中的每行你需要填寫img/filename。而在opencv_traincascade.exe中,你需要填寫由當前目錄開始的相對路徑,例如neg/img/filename。這應當屬於opencv設計當中的問題。
  • 正負樣本個數的比例,這個前面已經提到過了,眾說紛紜。
  • opencv_traincascade.exe的numPos和numNeg引數,需要合理地填寫,如果填寫的引數大於實際的樣本個數,會在執行時或訓練中報錯。這些引數都要填地稍低於實際樣本個數。
  • 負樣本中一定不能包含車牌區域,甚至是一部分也不可以。我的python指令碼中的gen_neg.py可以根據imageclipper得到的結果,在生成負樣本時避開正樣本區域。

雖然我經歷過的分類或迴歸問題並不多,但是也總結了一個很重要的點,那就是最重要的不是用什麼模型(Adaboost, SVM, ANN),而是使用的資料,即特徵。至少在提到的這些傳統的方法裡面(我沒接觸過深度網路),最核心的還是提取的特徵,這些特徵是否能夠區分類別。

以下內容為8月19日編輯

經過這次重新訓練,整個定位器的精度已經好了很多。
雖然還是有如下圖這樣字元偏向一側的情況,但是考慮到這是純分類器的輸出,已經很不錯了,至少比一開始的數學形態學定位要好了很多。在後面的過程中還會根據情況進行一些調整。

8月19日定位測試結果
8月19日定位結果

這種定位方法最好的地方是,輸出的非車牌區域真的很少。也可能是負樣本個數比較多的原因?
另外,我指定的級聯分類器層數是17,但是訓練到12層就報錯了,不知道是什麼原因。今天我要把整個過程再來一遍。檢視一下中間是否有問題。

經過上述初步試驗,我認為haar-like+adaboost的方法可取。
之前逛知乎的時候搜opencv這個話題,發現很多人在真正做工程時是不用這個庫,而是很多東西要去自己實現的。這幾天讀opencv關於cascade classifier這方面的文件,發現使用的技術已經是10幾年前論文中的技術。從論文到工程,再到開源工程,這個路線是太漫長了。我們這樣缺乏技術能力的團隊,也很難具有快速的論文轉換為工程的能力。不去深挖整個技術,我認為是很難取得好的效果的。

Anyway,我要去閱讀一下關於Adaboost以及Cascade Classifier的這幾篇文章,主要看看能否去修改一下訓練器中使用的特徵。