1. 程式人生 > >端到端的OCR:基於CNN的實現

端到端的OCR:基於CNN的實現

OCR是一個古老的問題。這裡我們考慮一類特殊的OCR問題,就是驗證碼的識別。傳統做驗證碼的識別,需要經過如下步驟:

1. 二值化
2. 字元分割
3. 字元識別

這裡最難的就是分割。如果字元之間有粘連,那分割起來就無比痛苦了。

最近研究深度學習,發現有人做端到端的OCR。於是準備嘗試一下。一般來說目前做基於深度學習的OCR大概有如下套路:

1. OCR的問題當做一個多標籤學習的問題。4個數字組成的驗證碼就相當於有4個標籤的圖片識別問題(這裡的標籤還是有序的),用CNN來解決。
2. OCR的問題當做一個語音識別的問題,語音識別是把連續的音訊轉化為文字,驗證碼識別就是把連續的圖片轉化為文字,用CNN+LSTM+CTC來解決。

目前第1種方法可以做到90%多的準確率(4個都猜對了才算對),第二種方法我目前的實驗還只能到20%多,還在研究中。所以這篇文章先介紹第一種方法。

下圖是一些這個驗證碼的例子:

python-captcha

可以看到這裡面有粘連,也有形變,噪音。所以我們可以看看用CNN識別這個驗證碼的效果。

首先,我們定義一個迭代器來輸入資料,這裡我們每次都直接呼叫python-captcha這個庫來根據隨機生成的label來生成相應的驗證碼圖片。這樣我們的訓練集相當於是無窮大的。

class OCRIter(mx.io.DataIter):
def __init__(self, count, batch_size, num_label, height, width):
    super(OCRIter, self).__init__()
    self.captcha = ImageCaptcha(fonts=['./data/OpenSans-Regular.ttf'])
    self.batch_size = batch_size
    self.count = count
    self.height = height
    self.width = width
    self.provide_data = [('data', (batch_size, 3, height, width))]
    self.provide_label = [('softmax_label', (self.batch_size, num_label))]

def __iter__(self):
    for k in range(self.count / self.batch_size):
        data = []
        label = []
        for i in range(self.batch_size):
            # 生成一個四位數字的隨機字串
            num = gen_rand() 
            # 生成隨機字串對應的驗證碼圖片
            img = self.captcha.generate(num)
            img = np.fromstring(img.getvalue(), dtype='uint8')
            img = cv2.imdecode(img, cv2.IMREAD_COLOR)
            img = cv2.resize(img, (self.width, self.height))
            cv2.imwrite("./tmp" + str(i % 10) + ".png", img)
            img = np.multiply(img, 1/255.0)
            img = img.transpose