效果展示
這不是OCR,有些人可能會覺得這東西會和OCR一樣,直接進行整個字的識別就行,然而並不是.
OCR是2維像素矩陣的像素數據.而手寫識別不一樣,手寫可以把用戶寫字的筆畫時間順序,抽象成一個維度.這樣識別的就是3維的數據了.識別起來簡單很多.
最近需要做一個中文手寫識別算法.搜索了網上的一些前人作品,發現都是只講了理論,不講實際開發.於是打算自己開發一個,並記錄開發過程.
由於代碼量比較多,這里不會全部貼上來講解,代碼已經放到了gitee,部分地方需對照代碼進行觀看,下面有URL.
思路
網上關於中文手寫識別的文章不多,不過數字OCR方案確有很多.
雖然中文手寫識別並不等於OCR,但總歸有點關聯性.
我發現數字的OCR大概是這么個套路:
神經網絡的輸出層每一個節點對應一個數字的相似度.而中文不能這么做.因為中文有上萬字.
不過這是手寫識別,我們有用戶寫字的時候每一筆的數據,可以先識別筆畫.然后再根據筆畫,去識別字.
資源獲取與數據模型設定
首先我們需要一個字典,用於提供所有中文漢字的筆畫順序,這玩意在百度搜索"字典 mdb"能得到很多(我會放到源碼里)
通過查看字典的"筆順"字段,我們可以看到,字典中的字,筆順分為了: 橫,豎,撇,捺,其它 這5個類型
橫豎撇捺好弄,不過這個"其它"有點特別,通過查詢.中文的筆畫有30多種.
我按照長相,將筆畫大體分成了這7種:
ID | 筆畫 | 名稱 |
---|---|---|
0 | ㇐ | 橫 |
1 | ㇑ | 豎 |
2 | ㇓ | 撇 |
3 | ㇏ | 捺 |
4 | ㇕㇖⺄ | 橫折 |
5 | ㇗㇙㇞㇟ㄣ㇂ ㇛㇜ | 豎折 |
6 | ㇡ ㇌ | 橫折折折 |
也就是說,我這里是分成7種來識別的,后續使用的時候,是再轉換為5種筆畫.
我們將用戶輸入的筆畫順序識別出來后,經過字符串相似度算法,識別出用戶輸入的筆畫,與字典中每個字的筆畫的相似度,然后進行排序.
關於字符串相似度,這里采用的是 levenshtein算法,相關代碼可在我的源碼中找到.
開發采集工具&采集一些數據
首先我需要采集一些筆畫數據,然后交給神經網絡,訓練神經網絡識別能力.
這里開發了一個采集工具,用來采集一些用於訓練的數據:
Gitee查看源碼>>
Github查看源碼>>
使用方法如下:
保存后會得到一個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類,這個類用於存放訓練或者識別用的數據並進行矩陣的輸出,可以在這里面找到生成矩陣的算法.
訓練完成后,使用訓練結果,對測試數據進行了測試.並生成了訓練結果文件:
訓練工具源碼:
Gitee查看源碼>>
Github查看源碼>>
實際使用
識別功能和采集工具做在一起了,將神經網絡訓練出來的結果"GData.json"文件放進采集工具工程里.運行工程即可.
在實際使用中效果沒有想象中的好,筆畫相似度高的字比較多,得把字寫得比較工整才能識別到,想要獲取更好的結果,還需要對方案進行更多的優化才行.
改進計划
目前我比較傾向於這兩個方案:
- 在測試中有個現象,筆畫識別錯誤率有點高,可能需要修改筆畫識別的方式,嘗試用別的方式去識別筆畫
- 我找到的字典有問題,字符雖然很全,但是筆畫分類才5種,只分為"橫,豎,撇,捺,其它",這個"其它"比較礙事,可以嘗試找筆畫分類更細的字典來解決這個問題.
如果對這個項目感興趣或者有更好優化的思路,可以給我留言