天天看點

手寫多位數字識别器實作 (轉載請注明出處!)

1、主要功能

①界面化的輸入方式,進行實時數字識别

②可以識别多位的數字,例如23,234

③CNN進行數字識别

2、運作環境

Windows10、python3.7+、tensorflow2.x

3、步驟介紹

神經網絡的模型可以自己訓練或調用./model下已經訓練好的模型,用tf2.x實作,對圖檔的預處理等是利用opencv和PIL實作的,界面使用PyQt5,該識别器可以實時識别從GUI中畫出的數字圖檔,利用截圖的方式存儲圖檔,并對圖檔進行預處理,進行字元分割成多個圖檔進行CNN識别,最終以一圖一數字的形式組合傳回至前端。

具體過程:

手寫多位數字識别器實作 (轉載請注明出處!)

4、細節

具體的界面代碼在下方的連結中,這裡稍微說一下圖檔字元分割部分:

# 按行切割,此時grayscaleimg為 50x100 矩陣,50 行,100列,每個元素不是0就是255
    row_nz = []
    # 将每行展成一個list,即有50個list
    for row in grayscaleimg.tolist():
        row_nz.append(len(row) - row.count(0))
    # row_nz裡存儲每行值和不為0的列數 eg.[0, 0, 0, 0, 0, 0, 7, 15, 16, 9, 10, 9, 9, 11, 14, 25, 32, 24, 20, 13, 7, 7,
    # 7, 9, 10, 10, 9, 9, 9, 14, 19, 14, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 50
    # 代表在第6行(0開始)有7列元素不為0

    # 找到上界(即第一個開始出現筆畫的行号) 記為第upper_y列
    upper_y = 0
    for i, x in enumerate(row_nz):
        if x >= 1:  # 若一行中出現大于兩個地方有筆畫(255)
            upper_y = i
            break

    # 找到下界(即最後一個出現筆畫的行号) 記為第lower_y列
    lower_y = 0
    for i, x in enumerate(row_nz[::-1]):
        if x >= 1:
            lower_y = len(row_nz) - i
            break

    # 按上下界進行切割,将沒有筆畫的上部分和下部分都丢棄,留下中間帶有筆畫的區域
    sliced_y_img = grayscaleimg[upper_y: lower_y, :]

    # 同理,按列切割,此時grayscaleimg為 (lower_y - upper_y)x100 矩陣
    col_nz = []
    # 将每行展成一個list,即有100個list
    for col in sliced_y_img.T.tolist():
        col_nz.append(len(col) - col.count(0))

    # 尋找每個字元的左邊界和右邊界,column_boundary_list存儲每個字元的起始列号
    column_boundary_list = []
    # record = False
    for i, x in enumerate(col_nz[:-1]):
        # 如果第i列無筆畫(和為0),第i+1列有筆畫,可以認為i列是某個字元的左邊界
        if col_nz[i] <= 1 and col_nz[i + 1] > 1:
            column_boundary_list.append(i)
        # 如果第i列有筆畫,第i+1列無筆畫,可以認為i列是某個字元的右邊界
        elif col_nz[i] >= 1 and col_nz[i + 1] < 1:
            column_boundary_list.append(i + 1)
    # 此時若書寫32, column_boundary_list裡存儲的類似于[20, 31, 56, 89],即20-31列代表'3', 56-89列代表'2'

    # 存儲分割後的圖檔
    img_list = []  # img_list存儲每幅圖的矩陣
    xl = [column_boundary_list[i:i + 2] for i in range(0, len(column_boundary_list), 2)]
    for x in xl:
        s = len(x)
        if len(x) == 2 and x[1] - x[0] > 5:
            s = fill(sliced_y_img[:, x[0]:x[1]])  # 從sliced_y_img截取每幅圖的列,進行背景填充
            img_list.append(s)                    # 将填充後的矩陣存入img_list


    img_list = [x for x in img_list if x.shape[1] > 5]
    print("數字位數為: ", len(img_list))  # 輸出總的字元數,即圖檔數
           

最後再對img_list裡的圖檔調用識别函數進行識别,傳回單一數字加入list中。

5、樣例

手寫多位數字識别器實作 (轉載請注明出處!)
手寫多位數字識别器實作 (轉載請注明出處!)
手寫多位數字識别器實作 (轉載請注明出處!)

完整代碼:https://github.com/GusionTan/HandwrittenDigitRecognitio

歡迎探讨,喜歡的話麻煩點個星,轉載請注明出處。