[純C#實現]基於BP神經網路的中文手寫識別演算法
效果展示
這不是OCR,有些人可能會覺得這東西會和OCR一樣,直接進行整個字的識別就行,然而並不是.
OCR是2維畫素矩陣的畫素資料.而手寫識別不一樣,手寫可以把使用者寫字的筆畫時間順序,抽象成一個維度.這樣識別的就是3維的資料了.識別起來簡單很多.
最近需要做一箇中文手寫識別演算法.搜尋了網上的一些前人作品,發現都是隻講了理論,不講實際開發.於是打算自己開發一個,並記錄開發過程.
由於程式碼量比較多,這裡不會全部貼上來講解,程式碼已經放到了gitee,部分地方需對照程式碼進行觀看,下面有URL.
思路
網上關於中文手寫識別的文章不多,不過數字OCR方案確有很多.
雖然中文手寫識別並不等於OCR,但總歸有點關聯性.
我發現數字的OCR大概是這麼個套路:
神經網路的輸出層每一個節點對應一個數字的相似度.而中文不能這麼做.因為中文有上萬字.
不過這是手寫識別,我們有使用者寫字的時候每一筆的資料,可以先識別筆畫.然後再根據筆畫,去識別字.
資源獲取與資料模型設定
首先我們需要一個字典,用於提供所有中文漢字的筆畫順序,這玩意在百度搜索"字典 mdb"能得到很多(我會放到原始碼裡)
通過檢視字典的"筆順"欄位,我們可以看到,字典中的字,筆順分為了: 橫,豎,撇,捺,其它 這5個型別
橫豎撇捺好弄,不過這個"其它"有點特別,通過查詢.中文的筆畫有30多種.
我按照長相,將筆畫大體分成了這7種:
ID | 筆畫 | 名稱 |
---|---|---|
0 | ㇐ | 橫 |
1 | ㇑ | 豎 |
2 | ㇓ | 撇 |
3 | ㇏ | 捺 |
4 | ㇕㇖⺄ | 橫折 |
5 | ㇗㇙㇞㇟ㄣ㇂ ㇛㇜ | 豎折 |
6 | ㇡ ㇌ | 橫折折折 |
也就是說,我這裡是分成7種來識別的,後續使用的時候,是再轉換為5種筆畫.
我們將使用者輸入的筆畫順序識別出來後,經過字串相似度演算法,識別出使用者輸入的筆畫,與字典中每個字的筆畫的相似度,然後進行排序.
關於字串相似度,這裡採用的是
開發採集工具&採集一些資料
首先我需要採集一些筆畫資料,然後交給神經網路,訓練神經網路識別能力.
這裡開發了一個採集工具,用來採集一些用於訓練的資料:
原始碼>>
使用方法如下:
儲存後會得到一個json檔案,裡面是採集到的筆畫資料:
每個筆畫採集30次之後儲存,在儲存後,請將這個檔案改名,然後再重新開啟一次軟體,採集下一個筆畫
把上面表格中的7個筆畫每一個採集30次左右(次數不需要完全一樣)每個筆畫單獨採集到一個檔案
再額外採集一個用於測試的資料:
訓練過程
這裡選擇BP網路的原因是因為網路上有直接複製即可用的C#程式碼,畢竟我是用C#開發,基於C#的神經網路程式碼很少.大部分是基於C或者python的.
我對我找到的BP網路的部分程式碼進行了修改,訓練完後可以把訓練結果儲存為單個json檔案.也可以讀取json檔案接著訓練,或著運用裡面的訓練結果進行識別.
把上面採集的7個筆畫樣本放入神經網路訓練:
如你所見,我另外開發了一個訓練工具,讀取前面步驟採集到的筆畫資料生成矩陣,給BP網路,進行訓練.
矩陣的格式:
**注:我用來訓練的矩陣的大小是固定的16*16,以下只是為了說明而做的一個縮小版:**
\ | 第0列 | 第1列 | 第2列 | 第3列 | 第4列 | 第5列 | 更多列 |
---|---|---|---|---|---|---|---|
第0行 | 0.2 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | . |
第1行 | 0.0 | 0.4 | 0.0 | 0.0 | 0.0 | 0.0 | . |
第2行 | 0.0 | 0.0 | 0.6 | 0.0 | 0.0 | 0.0 | . |
第3行 | 0.0 | 0.0 | 0.0 | 0.8 | 0.0 | 0.0 | . |
第4行 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | . |
第5行 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | . |
更多行 | . | . | . | . | . | . | . |
注意:我在矩陣中使用0~1之間的浮點數標識出了哪個畫素是先畫出來的,哪個畫素是後畫出來的.
不過神經網路輸入的矩陣是1維的,所以在程式碼中可以看到,我寫了個GetDim1Matrix方法,將這裡面的資料,全部連線到了一起.
在程式碼中,有一個MatrixData類,這個類用於存放訓練或者識別用的資料並進行矩陣的輸出,可以在這裡面找到生成矩陣的演算法.
訓練完成後,使用訓練結果,對測試資料進行了測試.並生成了訓練結果檔案:
訓練工具原始碼:
原始碼>>
實際使用
識別功能和採集工具做在一起了,將神經網路訓練出來的結果"GData.json"檔案放進採集工具工程裡.執行工程即可.
在實際使用中效果沒有想象中的好,筆畫相似度高的字比較多,得把字寫得比較工整才能識別到,想要獲取更好的結果,還需要對方案進行更多的優化才行.
改進計劃
目前我比較傾向於這兩個方案:
- 在測試中有個現象,筆畫識別錯誤率有點高,可能需要修改筆畫識別的方式,嘗試用別的方式去識別筆畫
- 我找到的字典有問題,字元雖然很全,但是筆畫分類才5種,只分為"橫,豎,撇,捺,其它",這個"其它"比較礙事,可以嘗試找筆畫分類更細的字典來解決這個問題.
如果對這個專案感興趣或者有更好優化的思路,可以給我留言或者到Q群:801522252與我討論.