用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中导入相关的库:

1
2
3
4
5
6
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中的相关函数,

将图片转为向量:

1
2
3
4
5
6
7
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张图片作为训练集:

1
2
3
4
5
6
7
8
9
10
11
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

 

构建分类器:

1
2
3
4
5
def knn_clf(X_train,label):
    '''构建分类器'''
    clf = knn()
    clf.fit(X_train,label)
    return clf

 

保存模型:

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

 

3. 训练模型:

1
2
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中编写用户界面:
导入相关的库:

1
2
3
4
5
import wx
from collections import namedtuple
from PIL import Image
import os
import model

 

编写界面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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

 

编写控件的回调函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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大师发表,拒绝转载,转载需要作者授权

 

posted on   demo例子集  阅读(41908)  评论(0编辑  收藏  举报

(评论功能已被禁用)
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示