用python實現的的手寫數字識別器


概述

帶GUI界面的,基於python sklearn knn算法的手寫數字識別器,可用於識別手寫數字,訓練數據集為mnist。

詳細

前言

 

k-近鄰(kNN, k-NearestNeighbor)算法是一種基本分類與回歸方法,
通俗點來說,就是給定一個訓練數據集,對新的輸入實例,在訓練數據集中找到與該實例最鄰近的 k 個實例,這 k 個實例的多數屬於某個類,就把該輸入實例分為這個類。

python 第三方庫scikit-learn(sklearn)提供了knn的分類器。

MNIST手寫數字數據庫(Mixed National Institute of Standards and Technology database)包含
70000張手寫數字圖片。這些數字是通過美國國家統計局的員工和美國高校的學生收集的。每張圖片
都是28x28的灰度圖。

 

用mnist數據集訓練出一個knn分類器,對新輸入的手寫數字進行識別。

准備工作

1.安裝必要的第三方庫:

pip install scikit-learn 
pip install numpy
pip install wxPython 

 

安裝PIL,在以下地址下載PIL庫進行安裝:
http://effbot.org/media/downloads/PIL-1.1.7.win32-py2.7.exe
(或在http://effbot.org/downloads/ 中找到與你操作系統及python版本相對應
版本的PIL)

2.下載mnist數據集:
可以從以下地址下載mnist數據集。
http://yann.lecun.com/exdb/mnist/
如下:

數據集.jpg

項目結構圖

 

整體的項目結構十分簡單,一共兩個腳本文件,一個是GUI界面腳本(digit_gui.py),
一個是分類器腳本(model.py)。
如下:

文件結構.jpg

 

實現過程的部分代碼展示

 

1. 在model.py中導入相關的庫:

import numpy as np
import os
from PIL import Image
import random
from sklearn.neighbors import KNeighborsClassifier as knn
from sklearn.externals import joblib

 

2. 編寫model.py中的相關函數,

將圖片轉為向量:

def img2vec(fname):
    '''將jpg等格式的圖片轉為向量'''
    im = Image.open(fname).convert('L')
    im = im.resize((28,28))
    tmp = np.array(im)
    vec = tmp.ravel()
    return vec

 

隨機抽取1000張圖片作為訓練集:

def split_data(paths):
    '''隨機抽取1000張圖片作為訓練集'''
    fn_list = os.llistdir(paths)
    X = []
    y = []
    d0 = random.sample(fn_list,1000)
    for i,name in enumerate(d0):
        y.append(name[0])
        X.append(img2vec(name))
        dataset = np.array([X,y])
    return X,y

 

構建分類器:

def knn_clf(X_train,label):
    '''構建分類器'''
    clf = knn()
    clf.fit(X_train,label)
    return clf

 

保存模型:

def save_model(model,output_name):
    '''保存模型'''
    joblib.dump(model,ouotput_name)

 

3. 訓練模型:

X_train,y_label = split_data(file_path)
clf = knn_clf(X_train,y_label)
save_model(clf,'mnist_knn1000.m')

 

4. 在digit_gui.py中編寫用戶界面:
導入相關的庫:

import wx
from collections import namedtuple
from PIL import Image
import os
import model

 

編寫界面:

class MainWindow(wx.Frame):
    def __init__(self,parent,title):
        wx.Frame.__init__(self,parent,title=title,size=(600,-1))
        static_font = wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL)
        
        Size = namedtuple("Size",['x','y'])
        s = Size(100,50)
        sm = Size(100,25)

        self.fileName = None
        self.model = model
        
        b_labels = [u'open',u'run']

        TipString = [u'選擇圖片', u'識別數字']
        
        funcs = [self.choose_file,self.run]
        
        '''create input area'''
        self.in1 = wx.TextCtrl(self,-1,size = (2*s.x,3*s.y))
        self.out1 = wx.TextCtrl(self,-1,size = (s.x,3*s.y))

        '''create button'''
        self.sizer0 = wx.FlexGridSizer(rows=1, hgap=4, vgap=2)
        self.sizer0.Add(self.in1)
        
        buttons = []
        for i,label in enumerate(b_labels):
            b = wx.Button(self, id = i,label = label,size = (1.5*s.x,s.y))
            buttons.append(b)
            self.sizer0.Add(b)      

        self.sizer0.Add(self.out1)

        '''set the color and size of labels and buttons'''  
        for i,button in enumerate(buttons):
            button.SetForegroundColour('red')
            button.SetFont(static_font)
            button.SetToolTipString(TipString[i])
            button.Bind(wx.EVT_BUTTON,funcs[i])

        '''layout'''
        self.SetSizer(self.sizer0)
        self.SetAutoLayout(1)
        self.sizer0.Fit(self)
        
        self.CreateStatusBar()
        self.Show(True)

 

界面如下:

界面.jpg

 

編寫控件的回調函數:

    def run(self,evt):
        if self.fileName is None:
            self.raise_msg(u'請選擇一幅圖片')
            return None
        else:
            model_path = os.path.join(origin_path,'mnist_knn1000.m')
            clf = model.load_model(model_path)
            ans = model.tester(self.fileName,clf)
            self.out1.Clear()
            self.out1.write(str(ans))
        
    def choose_file(self,evt):
        '''choose img'''
        dlg = wx.FileDialog(
            self, message="Choose a file",
            defaultDir=os.getcwd(), 
            defaultFile="",
            wildcard=wildcard,
            style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR
            )
        if dlg.ShowModal() == wx.ID_OK:
            paths = dlg.GetPaths()
            dlg.Destroy()
            self.in1.Clear()
            self.in1.write(paths[0])
            self.fileName = paths[0]
            im = Image.open(self.fileName)
            im.show()
        else:
            return None

 

運行效果

運行效果.jpg

注:本文著作權歸作者,由demo大師發表,拒絕轉載,轉載需要作者授權

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM