一次完整的OCR實踐記錄
一、任務介紹
這次的任務是對兩百餘張圖片裡面特定的編號進行識別,涉及保密的原因,這裡就不能粘貼出具體的圖片了,下面粘貼出一張類似需要識別的圖片。
假如說我的資料來源如上圖所示,那麼我需要做的工作就是將上面圖片裡面標紅的數字給識別出來。
我採用的演算法是https://github.com/YCG09/chinese_ocr,這是基於Tensorflow和keras框架採用ctpn+densenet+CTC演算法來完成對圖片指定內容的字元識別。
二、 影象標註
既然要進行OCR識別,那麼一定要對已有的資料來源進行影象標註工作,這裡採用的工具是labelImg,相信大家如果有搞深度學習這塊的話一定對這個工具不會陌生。
對影象具體的標註流程,我這裡就不做說明了,網上有很多資料可以查詢。這裡需要作特別說明的是,對於ctpn的訓練,label的名字為text,對於densenet的訓練來說的話,就需要把標註框裡面的內容當作label。
然後就是資料增強這塊,這裡需要記錄的有兩點,一就是原始的資料來源比較少就必須做資料增強,不然做出來的效果肯定不太行,二就是怎麼做資料增強,由於這裡的資料比較簡單,需要識別的內容也是有規律可行的,那這裡就用不著採用比較複雜的資料增強,所以我做的資料增強就是對影象隨機進行裁剪和傾斜,當然這裡裁剪的尺寸和傾斜的角度一定要控制好,不然就會影響圖片的質量。
import cv2 import numpy as np import random import os from PIL import Image # 資料增強的程式碼 img_path = r"*****************" save_path = r"****************" # 隨機傾斜圖片 def rotate_ima(img_path,save_path): for file in os.listdir(img_path): img = cv2.imread(os.path.join(img_path,file),0) rows,cols = img.shape # cols-1 and rows-1 are the coordinate limits. # 每張圖片傾斜4張 for i in range(4): a = random.randint(2,6) print(a) # 指定左右傾斜 for j in range(2): a = -a M = cv2.getRotationMatrix2D(((cols-1)/2.0,(rows-1)/2.0),a,1) dst = cv2.warpAffine(img,M,(cols,rows)) #cv2.imshow('img',img) #cv2.imshow('dst',dst) cv2.imwrite(os.path.join(save_path,'rot_'+str(i)+'_'+str(j)+file),dst) #cv2.waitKey(0) cv2.destroyAllWindows() # 隨機裁剪圖片 def cut_img(img_path,save_path): all_file=[] for file in os.listdir(img_path): all_file.append(file) file1=random.sample(all_file,2) for x in file1: im=Image.open(os.path.join(img_path,x)) crop_all=[] for c in range(5): # 對每張圖片隨機生成5張 for i in range(4): a=random.randint(100,400) crop_all.append(a) region=im.crop((crop_all[0],crop_all[1],im.size[0]-crop_all[2],im.size[1]-crop_all[3])) region.save(os.path.join(save_path,'cut_'+str(c)+'_'+x)) #rotate_ima(img_path,save_path) cut_img(img_path,save_path)
然後我大概生成了3000張左右的圖片就開始進行資料標註了,標註了大概六七個小時才把這些資料標註給完成。
有了這些標註資料過後,就可以正式開始訓練了。
三、CTPN訓練
關於CTPN訓練流程在https://github.com/YCG09/chinese_ocr/tree/master/ctpn的readme已經說的很清楚了。但是我這裡就列出我所踩的坑吧。
最開始我直接把標註的資料製作成VOC2007資料集的格式丟進去訓練,然後訓練出來的效果並不好,後面我才在周圍同事的提醒下有一個關鍵的步驟忘了做。
因為CTPN是進行文字檢測並不同於普通的目標檢測,它的檢測原理是對單個的字元進行檢測然後拼接在一起。
因為我們在進行資料標註的時候是對一整行文字進行拉框標註,但是如果要進行CTPN訓練的話就需要對這個框劃分成很多個矩形小框,劃分的方法就是上面的split_label.py程式。
但是要進行上面一步的前提就是需要更改標註檔案,使用labelImg標註出來的檔案是一個影象對應一個xml檔案,但是這裡需要更改成一個影象對應一個txt檔案,txt裡面存放的是標註框的四個座標,共計八個點(注意座標點的順序)。如下所示
410,1554,1723,1554,1723,1736,410,1736
然後在執行split_label.py,接著ToVoc.py,這裡面的程式碼細節需要自行更改,這裡就不做說明了。
然後就可以正式開始訓練了,截圖如下:
這裡粘貼出一個錯誤需要注意:
解決方案就是刪除cache資料夾
四、DenseNet+CTC訓練
DenseNet+CTC訓練主要分為兩個步驟,一是影象處理,二是txt檔案處理。
影象處理的話,在我們拿到標註好的資料之後需要對原始影象進行裁剪工作,就是根據標註的座標裁剪出具體的影象,就拿上面的影象來說,我們需要的影象如下所示。
然後再對裁剪後的影象進行resize工作,resize成(280,32),這樣的話影象處理這一部分就算完成了。
txt處理的話,這裡我們需要對xml檔案進行一系列處理來達到下面的效果。
前面card_900.jpg代表影象名稱,後面這一串字元代表需要識別的字元在下面這個檔案裡面的位置索引。
注意這裡txt裡面存放的是所有影象裡面待識別字符的編號,不是一個影象對應一個txt。
做到這一步過後,在把生成的txt劃分成訓練集和測試集,就算成功製作出來訓練DenseNet的資料集了。
然後就可以開始訓練了,截圖如下:
五、總結
這次這個小的OCR專案歷時大概十天左右,從資料標註再到訓練模型,裡面踩了很多坑,也做了很多次嘗試,也查閱了很多資料,也向周圍同事請教了很多次,總算功夫不負有心人,總算完成了這次專案。
這個記錄只是記錄了大概的流程,很多程式碼細節並不方便透露,更多詳情參閱上面給出的GitHub地址。記錄下這個更多是方便自己以後查閱。
&n