用python实现的的手写数字识别器
概述
详细
前言
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/
如下:
项目结构图
整体的项目结构十分简单,一共两个脚本文件,一个是GUI界面脚本(digit_gui.py),
一个是分类器脚本(model.py)。
如下:
实现过程的部分代码展示
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 ) |
界面如下:
编写控件的回调函数:
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 |
运行效果
注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?