怎樣用 MATLAB 識別圖片上的文字?
我想用 MATLAB 寫一個程序識別圖片上的文字,然後把這些文字轉換到 TXT 文本中。現在用因子分析,EM 演算法來寫,那麼怎麼把識別到的文字與資料庫進行連接識別呢?或者說怎麼把文字轉換成數字的呢?
去年自己做的一個小東西,現在看起來覺得沒那麼難,而且完成了這個小項目之後,又學深入學習了一陣子,等有空再繼續改改。
去年做的小項目大概是這樣的:因為學校的教務管理系統查分數比較麻煩,需要自己時不時登錄去「輪詢」,比較麻煩。那時會一點爬蟲,剛好學了一些機器學習的演算法。想著訓練出一個神經網路識別教務系統的驗證碼,然後讓代碼幫我隔5分鐘查一下成績,有新的成績出了就發郵件給我。於是我開始了。
1、 驗證碼預處理
我們學校的教務系統驗證碼長這個樣,4個字元(英文小寫字母加數字),左右傾斜,背景加了一些雜訊:
第一步想到的是濾波,驗證碼的雜訊不像椒鹽雜訊,更像高斯雜訊。我自己也寫了個均值濾波器,效果也很不錯,對付這種比較簡單的雜訊污染沒有太大問題。
在實際中,我直接調用了matlab的自帶濾波器,維納濾波。進行灰度處理後直接交給維納濾波:
濾除雜訊的效果不錯。
為了接下來的操作速度快一點,我直接進行了二值化操作,調整好閾值,二值化後得到:
2、Character Segmentation(Partition)
在實際的photo OCR當中,字元分割是很難的,在NG的machine learning中提到了一點,可以用sliding window的方法去實現,在這裡,我觀察了驗證碼的特點,其實驗證碼當中的字元都相對固定,所以我用最簡單的方法分割圖像,當然有時會偏差比較大。這也是可以改善的一點。我個人認為利用圖論演算法中的minimum cuts可以找到連接最弱的部分,然後進行切割,這也是可行的。
切割後的效果:
3、 神經網路
當時只能說是入門了神經網路,學的是NG的課。直接用了一個全連接的前饋神經網路,一共4層,input layer一共是260個神經元,兩層hidden layer都是200個神經元,output layer是36.
雖然方法很笨,一開始訓練樣本也不多,我抓了100張驗證碼,並手動標籤了,訓練了一個初步的模型。然後我就直接用這個模型去識別,把正確識別的驗證碼和對應的字元保存起來;把識別錯誤的保存到另外一個文件夾。針對識別錯誤的驗證碼,我手動標籤,然後訓練,重複這個過程。後面驗證碼已經接近1000張了。
雖然方法很笨,但是效果很不錯。經過我幾次改進之後,在線識別100張,正確識別率基本在90%以上(90%~93%左右)
其實,利用CNN效果會更好。先抓取大量為標籤的驗證碼,先進行預訓練,再進行監督訓練,效果也會好很多。
當時就是這樣,利用全連接網路+L2 weight penalty,利用full-batch method 加 conjugate gradient訓練了這個網路。
之後我學了Geoffrey E. Hinton的課程之後,進一步了解了神經網路,可以做的花樣就很多了。
總結
這就是訓練集的一部分:
標籤:
我租了騰訊雲的伺服器,學生優惠,1元1個月。
在考試月的時候完成了全部代碼,先在matlab完成了前期工作,然後用Python寫了一遍,加上了爬蟲的那一部分。 最後每次有成績都第一時間通知我:
附上github傳送門
[matlab版] mepeichun/Matlab_checkcode_verification
[java版] mepeichun/Java_checkcode_verification
[Python版] mepeichun/check_score_system
寫得很亂,因為那段時間參加了好幾個比賽。。有空再改
首先題主我不知道你是直接想要快速對文字進行識別呢,還是想自己寫一個東西來實現對文字的識別分類。對於前者,現有的工具其實已經很成熟了。一般來說用的都是OCR,也就是光學字元識別_百度百科,我之前用的是他的python介面——pytesser,想用的話直接百度即可。當然這個東西MATLAB裡面不知道有沒有。。。
==============================
當然,看到題主說是自己想用EM來進行分類。那我就當做你是想寫一個文字識別包了。最近正巧我也在做類似的工作。現在就來簡述一下工作步驟。
1、圖片獲取
由於我所做的是驗證碼識別,因此首先要獲得網站驗證碼。這個不管你用什麼方法,直接把圖片爬下來統一命名就好。比如說我就是用python爬取的本校教務系統的驗證碼,爬蟲原理什麼的在此就不贅述了,隨便一百度到處都是。然後把爬下來的圖片導入工作路徑,我們再進行進一步處理。
如圖是我爬下來的驗證碼,為了充實訓練集,建議還是多爬一些。
2、圖片處理
因為爬下來的驗證碼中包含很多噪點,首先我們要對其進行去噪工作,這個在MATLAB中就很好實現了,matlab的image processing toolbox有很多函數可以調用,經過試驗,我發現中值濾波可以起到很好的去噪效果。當然控制得好的話開閉運算跟高斯閾值分割估計能起到更好地去噪效果。如果你圖片中的文字足夠清晰且背景沒有噪點,那麼這一步可以省略。有一點需要強調的是,對於非灰度圖的圖片,建議上來還是先轉化成灰度圖以方便計算。這些在MATLAB中都有相應的函數,題主自己找一下吧(原諒我是用Python做的。。。MATLAB好久沒用函數名都忘得差不多了)
處理前的驗證碼
處理後的驗證碼
清晰了很多吧:)
3、圖片切割
對於連續的英文單詞,我們需要對其進行切割建立字模。由於我們之前已經將背景置白,因此我們可以創建一個counter變數來對每個字母邊界進行判斷。counter用於統計每一列黑色像素點的數量(經過觀察,我這裡的黑色定義為灰度值&<=110),如果counter == 0就算是遇到了邊界。這樣我們就能很輕鬆的切割出每個字模了。當然,在之後的切割中我發現,我們仍需要對採集到的字模進行進一步處理。原因有二,一方面是因為有的噪點因為沒有被完全去除導致我們可能切割出空白區域,另一方面可能有的字母之間會連在一起,因此出現了一個字模中有兩個字母的情況。對於這兩種情況,我們可以根據字模所包含的列數來進行篩選。在我這裡當字模的列數在2-24之間的時候基本上每個字模內都是單個字母。
切下來的字模
4、圖片二值化
這也許是所有步驟中最重要的一步,這一步之後意味著我們將可以直接對圖片進行分類了。記住我們未來對所有文字進行識別的時候,所有的步驟都是先切割,再二值化,最後進行分類。因此未來我們二值化的是字模而非屆時的整個圖片。(這不都是廢話嗎衰。。。)對於字模的二值化也很簡單,首先我們對每張圖片的每個像素進行遍歷,黑的置1白的置0,這個黑白的界定跟前面一樣,用灰度值大小進行判斷就好了。當然為了優化程序性能,我在之前的判斷的時候就已經將圖片二值化了。二值化後將數據寫好到txt文檔中就好了。值得強調的一點是,因為我們事後要先對所有數據進行人工分類,那個01010101的排布實在是像打了馬賽克。。。。所以還是用原來的圖片進行人工分類比較好。為了關聯好每個字模圖片和txt文件,我們可以建立一個fileid變數,對於相對應的圖片和txt文檔用相同的fileid當做文件名。這樣在後面人工識別後進行重命名的時候就很方便了。
好了下面進入打碼時間
z
v
k
說實話其實還是挺好認的。。
但是看多了就。。。。。
開始拿著這些給別人幫我認字他們說要吃了我。。。
好了言歸正傳
接下來就是人工認字來給這些鬼分個類了。
當然如果你的字夠正夠標準的話可以考慮直接用OCR分類。由於本校的驗證碼是歪的,餵給OCR後它實在是表示識別不能。。。。各種2認成z,s認成5,0O不分,最扯淡的還是特么還是好多x給我認成k。。。。。一怒之下我找了幾個童鞋十幾分鐘認完了1000+字模(對!就是這麼高效!)
接下來改文件名,那都是小case,颼颼幾秒搞定。
最後分好類的數據
5、分類
這個就不用我多說了吧,很多演算法都可以拿來嘗試。SVM,NN,EM,KNN.......隨你挑嘛。具體的怎麼數據歸一化用什麼數據結構我就不多說了,這些演算法MATLAB貌似都有好像?嘛,那就更好辦了嘛。最後上個結果
識別率大概在80%左右
還不錯吧:)
這是一個非常典型的問題。有很強大的學術意義也有很強大的工業界意義。相關產品其實也非常成熟:漢王公司有很強的手寫漢字識別系統。
實際上技術可以用,就是計算機視覺+機器學習/深度學習(使用哪一個機器學習或者深度學習的類庫會是一個頗有意思的問題)+TF-IDF演算法完全解決。當然可能還有其他演算法。
最近正好在寫這方面的代碼。不過我是用python。可以過一段和大家分享。原理和Matlab應該類似。其實個人認為這個問題用C/C++可以做的非常漂亮,而且C可以方便的做成一個嵌入式系統。
我會在合適的時候,把自己寫的一個用Python識別手寫數字的項目分享出來。原理應該類似。個人認為這種東西做工業級項目核心還是煉庫。拿大量數據去喂,靠玩機器學習演算法的花招是不行的。主要是對付漢語這種非字母語言。簡單的說,字模做成庫,然後匹配。
記得新版本的matlab就有ocr相關的功能
手寫體,還是印刷體。如果印刷體,各類OCR的軟體包可用。
推薦閱讀: