介紹
前面一篇文章介紹了我這個 FakeLPR 大體的框架,基本上可歸納爲三步
1.粗定位
2.角點檢測矯正
3.端到端識別字符
第一步粗定位不需要特別準,能大體定位到就可以了,因爲後面會把粗定位的結果按比例擴展,擴展出來的圖包含了車牌在裏面,要比粗定位結果大上幾圈,以便於檢測車牌角點。
本項目中沒有訓練車牌的粗定位模型,直接使用了 HyperLPR 的粗定位模型及相關代碼。https://github.com/zeusees/HyperLPR
粗定位模型可以自行替換,自己訓練個ssd,mobilenet-ssd,mtcnn都可以
本文主要介紹第二步,角點檢測,模型主要思路是將定位問題轉換爲分類問題,利用 caffe 實現多標籤分類來定位車牌角點
主要步驟
1.先生成車牌角點檢測的訓練數據和lmdb文件
# 從項目主目錄裏
cd train/datasets
# 生成角點檢測訓練數據
python creat_keypoint_data.py
# 生成角點檢測lmdb文件
python creat_keypoint_lmdb.py
注:要是某個包導不進去,先註釋掉試試,可能是我 import 多了,後同
2.啓動訓練
# 從項目主目錄裏
cd train
# 需要caffe環境
sh ./train_keypoint.sh
以上兩步就可以訓練出角點檢測模型,模型文件保存在 .../FakeLPR/train/keypoint_snapshot
下面詳細介紹一下
生成車牌數據
進入本項目文件夾,cd 到 train/datasets 文件夾,所有的生成數據都會在這個 datasets 文件夾下面進行
# 項目目錄裏
cd train/datasets
運行 creat_keypoint_data.py 生成角點檢測訓練數據
# 生成角點檢測訓練數據
python creat_keypoint_data.py
生成出來的文件夾有兩個 keypoint_train_data 和 keypoint_test_data ,分別是訓練和測試用,以 keypoint_train_data 爲例
keypoint_train_data/data 下保存的是生成的圖片,圖片生成出來的樣子是這樣的,尺寸爲 [748,280]
生成出來的數據保存在 keypoint_train_data/plate.db 當中,數據結構如下
表名都叫 train,要看的話就
select * from train;
filename是主鍵,其他4個點就是八個數,分別保存,LU就是left UP,以此類推
其他說明:
這個圖片生成腳本主要分三個部分
第一個 class 生成一張藍底的普通車牌的
第二個 class 對普通車牌進行隨機變換,變得更像真的,變換部分代碼參考了 Hyperlpr 的一個車牌變換程序
https://github.com/LCorleone/hyperlpr-train_e2e/blob/master/PlateCommon.py
最後一個就是隨機生成車牌字符。
你可以在 creat_keypoint_data.py 的 main 函數中修改你需要生成的數據數量,
後面的 e2e 檢測也是基於這裏的數據來的,你可以多弄一些,不過生成速度堪憂
# 根據自己的需求設置
def main():
############# 生成圖片數 ############
creat_train_num = 100000
creat_test_num = 1000
#####################################
對於中文顯示和保存的問題,取了個折中的辦法,用拼音,拼音和省份的轉換工具在腳本也有,在class Tool 中
province_change = [
[u"京",'jing'], [u"滬",'hu'], [u"津",'jin'], [u"渝",'yu'], [u"冀",'jii'], [u"晉",'jinn'],
[u"蒙",'meng'], [u"遼",'liao'], [u"吉",'ji'], [u"黑",'hei'], [u"蘇",'su'], [u"浙",'zhe'],
[u"皖",'wan'], [u"閩",'min'], [u"贛",'gann'], [u"魯",'lu'], [u"豫",'yuu'], [u"鄂",'e'],
[u"湘",'xiang'], [u"粵",'yue'], [u"桂",'gui'], [u"瓊",'qiong'], [u"川",'chuan'], [u"貴",'guii'],
[u"雲",'yun'], [u"藏",'zang'],[u"陝",'shan'], [u"甘",'gan'], [u"青",'qing'], [u"寧",'ning'],
[u"新",'xin'] ]
生出角點檢測 LMDB 文件
生成完數據,現在要生成用於 caffe 訓練的 LMDB 文件,這裏要先講一下這個模型思路
其實很簡單,將定位問題轉換爲一個分類問題,再用多標籤分類實現,我會將訓練圖像數據壓縮到 [90,30] ,以寬爲例,角點的y座標經過壓縮就在 [0,29] 之間,分類模型的輸出設爲30類,就能得到y座標了。一共有4個點8個座標,如此反覆8次就得到了4個角點的座標,實驗結果在生成數據集上效果很好,而且這還有一個優點,就算沒有準確分到那個類上,在準確值附近也是可以,類數越多定位越精確
本來這個思路需要8個模型,但是使用多標籤分類的辦法就可以一個模型搞定
另一個問題是 caffe 不支持多標籤分類,如果不換框架的話網上的辦法基本是改 caffe 源碼,做hdf5文件或者用兩個lmdb+Slice Laye的方法,因爲我是在服務器上運行,源碼改不了,hdf5又存在一個內存佔用大的問題,所以用了兩個lmdb+Slice Laye的方法來做 caffe 多標籤分類,後面的端到端識別模型也是如此
運行 creat_keypoint_lmdb.py 生成角點檢測訓練用的兩個lmdb文件
# 生成角點檢測lmdb文件
python creat_keypoint_lmdb.py
生成的 lmdb 文件存在 .../FakeLPR/train/datasets/lmdb 文件夾下,兩個 lmdb 分別對應着數據和標籤
其他說明:
多標籤的 LMDB 生成代碼參考自
https://blog.csdn.net/u013010889/article/details/53098346
這個腳本分兩步,第一步會先讀取 plate.db 文件,將需要的數據處理後,生成爲一個 keypoint_label.txt 保存數據,txt 裏面的格式爲
就是文件名和4個點的座標,順序是左上,右上,左下,右下
然後再讀取 txt 中的數據生成兩個 LMDB
爲什麼不連在一起,這樣做是因爲方便從其他形式來導入數據訓練,假如有小夥伴搞到了1w真實車牌的角點數據,就可以按照 txt 中的數據格式導,直接就能導成 LMDB文件了
# 生成lmdb文件的兩步
def get_lmdb(self,db_path,img_path,pause):
self.writeTXT_from_db(db_path,img_path) # db文件到txt文件
self.totwolmdb(img_path,pause) # 生成 LMDB 的
如果要自己弄數據,要注意的點座標的比例變換,圖片尺寸到類的比例要根據原圖和類的比例來,例如我的,生成時是 [748,280],目標是 [90,30],所以座標轉換代碼是
def resize_point(self,line):
# 你的源圖片寬高
# 可以讀取圖片來確定shape
src_w = 748
src_h = 280
dst_w = 90
dst_h = 30
scale_x = float(dst_w)/float(src_w)
scale_y = float(dst_h)/float(src_h)
out_line = []
for i in range(1,9,2):
out_line.append(float(line[i]) * scale_x)
out_line.append(float(line[i+1]) * scale_y)
return out_line
訓練
生成完就可以訓練了
啓動訓練
# 從項目主目錄裏
cd train
sh ./train_keypoint.sh
模型文件保存在 .../FakeLPR/train/keypoint_snapshot
模型調用
這沒什麼好說的,代碼在 .../FakeLPR/py2/keypoint.py 中
檢測是用 opencv 的 dnn 模塊直接調用
def opencv34_test(self,ex_plate):
ex_plate = cv2.cvtColor(ex_plate, cv2.COLOR_BGR2RGB)
inputBlob = cv2.dnn.blobFromImage(ex_plate,1,(90, 30),(104, 117, 123))
self.kp_net.setInput(inputBlob)
# 取出prob層結果
result_point = []
for i in range(1,9,2):
probx = self.kp_net.forward('prob_'+str(i))
proby = self.kp_net.forward('prob_'+str(i+1))
result_point.append([probx.argmax(),proby.argmax()])
return result_point
再根據結果來透視變換,得到矯正車牌
def warp(self,star_points,src_img):
# 目標尺寸
height = 35
width = 110
pts1 = np.float32([star_points[0],star_points[1],star_points[2],star_points[3]])
pts2 = np.float32([[0,0],[width,0],[0,height],[width,height]])
M = cv2.getPerspectiveTransform(pts1,pts2)
dst = cv2.warpPerspective(src_img,M,(width,height))
return dst
下一篇:FakeLPR車牌識別(3) ----- 車牌端到端識別