1. 程式人生 > >Python徒手實現識別手寫數字—大綱

Python徒手實現識別手寫數字—大綱

寫在前面

其實我之前寫過一個簡單的識別手寫數字的程式,但是因為邏輯比較簡單,而且要求比較嚴苛,是在50x50大小畫素的白底圖上手寫黑色數字,並且給的訓練材料也不夠多,導致準確率只能五五開。所以這一次準備寫一個加強升級版的,藉此來提升我對Python處理檔案與圖片的能力。

這次準備加強難度:

  1. 被識別圖片可以是任意大小;
  2. 不一定是白底圖,只要數字顏色是黑色,周圍環境是淺色就行;
  3. 加強識別手寫數字的邏輯,提升準確率。

    因為我還沒開始正式寫,並且最近專業課程學習也比較緊迫,所以可能更新的比較慢。不過放心,程式碼質量肯定是不會下降的,我會盡我所能寫的邏輯明確、通俗易懂點。

    所以這次面向的人群是擁有一定Python基礎,對數學算髮有一點了解(識別影象的演算法嘛)的人。

但畢竟我不是專業的,也沒有看那麼多論文,所以我這裡運用的演算法僅僅是我一個粗淺的想法,只是為了練手而已。如果和實際應用脫節,還望莫怪。

當然,如果諸位有什麼比較好的想法,可以在下方評論或者私信我,我們可以探討一下,相互進步。

整體思路

大綱

對圖片的預處理

在最開始的時候,我們假設只擁有一個訓練庫,裡面是從0到9的手寫數字圖案若干組。

所以我們首先應該將這些圖案讀入程式中,然後運用某種方式儲存好,用來後面識別圖片。

這裡的圖案我們假設是大小不一的,裡面手寫的數字也是有大有小。所以我們可以將包住手寫數字圖案的最小矩形給裁剪出來,然後將裁剪出來的圖案統一給拉伸成相同大小的圖案。

以上操作得出一個矩陣,這個矩陣的值是圖案的灰度值。對於訓練用的圖片和被檢測的圖片我們都是這樣處理。

影象識別的演算法處理

我這裡想用兩個方法來讓數字識別準確點:

  1. 識別所寫數字的“洞數”;
  2. 將圖片轉為1xn的向量,然後根據根據訓練圖片分出的類對被識別圖片圖片進行分類。

洞數就是某個數字是否有閉合的曲線,比如說7沒有洞,6有一個洞,8有兩個洞。所以我們根據洞數可以分成以下三類

  • 0洞:1, 2, 3, 4, 5, 7
  • 1洞:6, 9, 0
  • 2洞:8

但是因為各種手寫差異,比如說6, 9, 8之類的沒有閉合,4上面閉合,所以會導致下面這種可能情況

  • 0洞:1, 2, 3, 4, 5, 6, 7, 9
  • 1洞:6, 8, 9, 0
  • 2洞:8

雖然說這樣分類0洞佔大多數,但是聊勝於無。

對於將圖片轉為向量的意思就是將圖片原本的二維矩陣展開稱為一維向量。這個用numpy的函式可以可以很簡單的實現。

對於這個分類,下面我就簡單的講一下原理。

假設我們在二維平面上有兩個點A=(1,1)B=(5,5),我現在再放一個點C=(2,2),那麼請問,C點離哪一個更近?

學過初中數學的都會知道肯定是離A點更近。所以我們換一種說法,我們現在有兩個類A和B,A類中包括了點(1,1),B類中包括了點(5,5),所以對於點(2,2),它可能屬於哪一類?

因為這個點離A類的點更近一點,所以它可能屬於A類。這就是結論。那麼對於3維空間,A類是點(1,1,1)和B類是(5,5,5),那麼對於點(2,2,2)肯定也是屬於A類。

可以看出,我們這裡是將兩個點的距離來作為判斷屬於哪一類的標準。那麼對於我們將圖片拉成的1xn維向量,他實際上投影到n維空間上就是一個點,所以我們將訓練向量分成10類,分別代表十個數字,那麼被識別數字靠近哪一個類,那說明它有可能屬於這一個類。

那麼我們這裡可以假設對於被識別向量,列出距離他最近的前十個向量分別屬於哪一類別,然後根據名次加上一個權重,並計算出一個值。該值代表了可能是屬於哪一個類,因此這就是我們得出的最終的一個結果——被識別手寫數字圖片的值。

難點

儲存已訓練圖片的向量。這一條我想就直接儲存在csv檔案中,每一次運算時先判斷是否有新的訓練圖片加入,如果有,則把新的圖片向量也存入csv檔案中。若沒有,則直接讀取所有向量儲存在一個大矩陣中用於計算。

將手寫數字從背景中分離。因為我這裡令手寫數字為黑色(灰度值為0),其他背景色儘量為,所以就令灰度值大於某個界限(如50)的點全部為255(白色),其餘不變。這樣子只要非255,那就是手寫數字的點。

識別手寫數字的洞。這個有演算法,搞過程式設計競賽的應該會了解。具體我就不細講了,大概就是利用遞迴之類的去尋找。

求向量距離。這個更簡單了,求解每一個訓練向量與識別向量的距離就行,只不過當訓練向量比較大的時候可能比較慢。

總結

以上就是全部思路,如果諸位有更好的想法,歡迎評論/私信我,讓我們一起相互學習進步,謝謝。

如果你喜歡的話,請點個喜歡哦~