摘要

手写数字识别是模式识别中一个非常重要和活跃的研究领域,数字识别也不是一项孤立的技术,他涉及的问题是模式识别的其他领域都无法回避的;应用上,作为一种信息处理手段,字符识别有广阔的应用背景和巨大的市场需求。因此,对数字识别的研究具有理论和应用的双重意义。

人工神经网络识别方法是近年该研究领域的一种新方法,该方法具有一些传统技术所没有的优点:良好的容错能力、分类能力强、并行处理和自学习能力,并且是离线训练和在线识别的。这些优点使它在手写体字符的识别中能对大量数据进行快速实时处理,并达到良好的识别效果。

由于手写数字识别难于建立精确的数学模型,所以本文使用Python基于TensorFlow 卷积神经网络设计手写数字识别算法,并编程实现GUI 界面,构建手写数字识别系统。本系统界面设计友好,功能完善。通过测试,本识别系统对于较规范的手写体数字的识别达到了很好的识别效果。

下载mnist数据集

http://yann.lecun.com/exdb/mnist/

安装必要的库

pip install PyQt5
pip install PyQt5 -sip
pip install PyQt5 -tools
pip install numpy
pip install tensorflow

训练模型

keras训练模型,并保存模型,该模型识别正确率99%

# -*- coding: utf-8 -*-
"""
Created on Thu Dec  5 10:39:19 2019@author: dell
"""import tensorflow as tf
try:import tensorflow.python.keras as keras
except:import tensorflow.keras as keras
from tensorflow.python.keras import layersfrom tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPool2D
from tensorflow.keras.utils import to_categoricalmnist = keras.datasets.mnist
(x_train,y_train),(x_test,y_test) = mnist.load_data()
#x_train, x_test = x_train/255.0, x_test/255.0  # 除以 255 是为了归一化。X_train4D = x_train.reshape(x_train.shape[0], 28, 28, 1).astype('float32')
X_test4D = x_test.reshape(x_test.shape[0], 28, 28, 1).astype('float32')X_train4D_Normalize = X_train4D / 255 # 归一化
X_test4D_Normalize = X_test4D / 255y_trainOnehot = to_categorical(y_train)
y_testOnehot = to_categorical(y_test)
# Sequential 用于建立序列模型
# Flatten 层用于展开张量,input_shape 定义输入形状为 28x28 的图像,展开后为 28*28 的张量。
# Dense 层为全连接层,输出有 128 个神经元,激活函数使用 relu。
# Dropout 层使用 0.2 的失活率。
# 再接一个全连接层,激活函数使用 softmax,得到对各个类别预测的概率。
#model = keras.Sequential()
#model.add(layers.Flatten(input_shape=(28,28)))
#model.add(layers.Dense(128,activation="relu"))
#model.add(layers.Dropout(0.2))
#model.add(layers.Dense(10,activation="softmax"))model = Sequential()# 一层卷积
model.add(Conv2D(filters=16,kernel_size=(5, 5),padding='same',  # 保证卷积核大小,不够补零input_shape=(28, 28, 1),activation='relu'))
# 池化层1
model.add(MaxPool2D(pool_size=(2, 2)))
model.add(Dropout(0.25))# 二层卷积
model.add(Conv2D(filters=32, kernel_size=(5, 5), padding='same', activation='relu'))
# 池化层2
model.add(MaxPool2D(pool_size=(2, 2)))
model.add(Dropout(0.25))model.add(Conv2D(filters=64, kernel_size=(5, 5), padding='same', activation='relu'))
model.add(Conv2D(filters=128, kernel_size=(5, 5), padding='same', activation='relu'))
model.add(MaxPool2D(pool_size=(2, 2)))
model.add(Dropout(0.25))model.add(Flatten())  # 平坦层
model.add(Dense(128, activation='relu'))  # 全连接层
model.add(Dropout(0.25))
model.add(Dense(10, activation='softmax')) # 激活函数# 优化器选择 Adam 优化器。
# 损失函数使用 sparse_categorical_crossentropy,
# 还有一个损失函数是 categorical_crossentropy,两者的区别在于输入的真实标签的形式,
# sparse_categorical 输入的是整形的标签,例如 [1, 2, 3, 4],categorical 输入的是 one-hot 编码的标签。
#model.compile(optimizer="adam",#             loss="sparse_categorical_crossentropy",#            metrics=['accuracy'])# 训练模型
model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])
train_history = model.fit(x=X_train4D_Normalize,y=y_trainOnehot,validation_split=0.2,batch_size=300,epochs=10,verbose=2)# fit 用于训练模型,对训练数据遍历一次为一个 epoch,这里遍历 5 次。
# evaluate 用于评估模型,返回的数值分别是损失和指标。
#model.fit(x_train,y_train,epochs=10)
# 将整个模型保存为HDF5文件
model.save('F:\wu\my_model.h5')
model.evaluate(X_test4D_Normalize,y_testOnehot)

训练模型后续将直接上传此博客,直接供大家使用!

手写数字识别

from PyQt5.Qt import QWidget, QColor, QPixmap, QIcon, QSize, QCheckBox
from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout, QPushButton, QSplitter,\QComboBox, QLabel, QSpinBox, QFileDialog
from PaintBoard import PaintBoardimport tensorflow as tf
import numpy as np
try:import tensorflow.python.keras as keras
except:import tensorflow.keras as kerasclass MainWidget(QWidget):def __init__(self, Parent=None):'''Constructor'''super().__init__(Parent)self.__InitData() #先初始化数据,再初始化界面self.__InitView()def __InitData(self):'''初始化成员变量'''self.__paintBoard = PaintBoard(self)#获取颜色列表(字符串类型)self.__colorList = QColor.colorNames() def __InitView(self):'''初始化界面'''self.setFixedSize(640,480)self.setWindowTitle("手写数字识别")self.label_name = QLabel('XXXX大学', self)self.label_name.setGeometry(500,5,120,35)self.label_name = QLabel('电信院', self)self.label_name.setGeometry(500,35,100,35)self.label_name = QLabel('班级', self)self.label_name.setGeometry(500,65,100,35)self.label_name = QLabel('姓名', self)self.label_name.setGeometry(500,95,100,35)#新建一个水平布局作为本窗体的主布局main_layout = QHBoxLayout(self) #设置主布局内边距以及控件间距为10pxmain_layout.setSpacing(10) #在主界面左侧放置画板main_layout.addWidget(self.__paintBoard) #新建垂直子布局用于放置按键sub_layout = QVBoxLayout() #设置此子布局和内部控件的间距为5pxsub_layout.setContentsMargins(5, 5, 5, 5)splitter = QSplitter(self) #占位符sub_layout.addWidget(splitter)self.__btn_Recognize=QPushButton("开始识别")self.__btn_Recognize.setParent(self)self.__btn_Recognize.clicked.connect(self.on_btn_Recognize_Clicked)sub_layout.addWidget(self.__btn_Recognize)self.__btn_Clear = QPushButton("清空画板")self.__btn_Clear.setParent(self) #设置父对象为本界面#将按键按下信号与画板清空函数相关联self.__btn_Clear.clicked.connect(self.__paintBoard.Clear) sub_layout.addWidget(self.__btn_Clear)self.__btn_Quit = QPushButton("退出")self.__btn_Quit.setParent(self) #设置父对象为本界面self.__btn_Quit.clicked.connect(self.Quit)sub_layout.addWidget(self.__btn_Quit)self.__btn_Save = QPushButton("保存作品")self.__btn_Save.setParent(self)self.__btn_Save.clicked.connect(self.on_btn_Save_Clicked)sub_layout.addWidget(self.__btn_Save)self.__cbtn_Eraser = QCheckBox("  使用橡皮擦")self.__cbtn_Eraser.setParent(self)self.__cbtn_Eraser.clicked.connect(self.on_cbtn_Eraser_clicked)sub_layout.addWidget(self.__cbtn_Eraser)self.__label_penThickness = QLabel(self)self.__label_penThickness.setText("画笔粗细")self.__label_penThickness.setFixedHeight(20)sub_layout.addWidget(self.__label_penThickness)self.__spinBox_penThickness = QSpinBox(self)self.__spinBox_penThickness.setMaximum(20)self.__spinBox_penThickness.setMinimum(2)self.__spinBox_penThickness.setValue(10) #默认粗细为10self.__spinBox_penThickness.setSingleStep(2) #最小变化值为2self.__spinBox_penThickness.valueChanged.connect(self.on_PenThicknessChange)#关联spinBox值变化信号和函数on_PenThicknessChangesub_layout.addWidget(self.__spinBox_penThickness)self.__label_penColor = QLabel(self)self.__label_penColor.setText("画笔颜色")self.__label_penColor.setFixedHeight(20)sub_layout.addWidget(self.__label_penColor)self.__comboBox_penColor = QComboBox(self)self.__fillColorList(self.__comboBox_penColor) #用各种颜色填充下拉列表self.__comboBox_penColor.currentIndexChanged.connect(self.on_PenColorChange) #关联下拉列表的当前索引变更信号与函数on_PenColorChangesub_layout.addWidget(self.__comboBox_penColor)main_layout.addLayout(sub_layout) #将子布局加入主布局def __fillColorList(self, comboBox):index_black = 0index = 0for color in self.__colorList: if color == "black":index_black = indexindex += 1pix = QPixmap(70,20)pix.fill(QColor(color))comboBox.addItem(QIcon(pix),None)comboBox.setIconSize(QSize(70,20))comboBox.setSizeAdjustPolicy(QComboBox.AdjustToContents)comboBox.setCurrentIndex(index_black)def on_PenColorChange(self):color_index = self.__comboBox_penColor.currentIndex()color_str = self.__colorList[color_index]self.__paintBoard.ChangePenColor(color_str)def on_PenThicknessChange(self):penThickness = self.__spinBox_penThickness.value()self.__paintBoard.ChangePenThickness(penThickness)def on_btn_Save_Clicked(self):savePath = QFileDialog.getSaveFileName(self, 'Save Your Paint', '.\\', '*.png')print(savePath)if savePath[0] == "":print("Save cancel")returnimage = self.__paintBoard.GetContentAsQImage()image.save(savePath[0])print(savePath[0])def on_cbtn_Eraser_clicked(self):if self.__cbtn_Eraser.isChecked():self.__paintBoard.EraserMode = True #进入橡皮擦模式else:self.__paintBoard.EraserMode = False #退出橡皮擦模式def on_btn_Recognize_Clicked(self):savePath = "E:/wu/text.png"image = self.__paintBoard.GetContentAsQImage()image.save(savePath)print(savePath)# 加载图像img = keras.preprocessing.image.load_img(savePath, target_size=(28, 28))img = img.convert('L')x = keras.preprocessing.image.img_to_array(img)x = abs(255-x)#x = x.reshape(28,28)x = np.expand_dims(x, axis=0)  x=x/255.0new_model = keras.models.load_model('E:/wu/my_model.h5')prediction = new_model.predict(x)output = np.argmax(prediction, axis=1)print("手写数字识别为:" + str(output[0]))   def Quit(self):self.close()

主函数

from MainWidget import MainWidget
from PyQt5.QtWidgets import QApplicationimport sysdef main():app = QApplication(sys.argv) mainWidget = MainWidget() #新建一个主界面mainWidget.show()    #显示主界面exit(app.exec_()) #进入消息循环if __name__ == '__main__':main()

运行界面

改变画笔颜色

保存手写数字图片


手写板程序参考 https://blog.csdn.net/creatorgg/article/details/81542837
感谢前辈的分享

后续将继续剖析程序细节,分章节讲解程序。

源程序也将上传至此博客

完整工程文件link

大家对程序有什么疑问或建议均可留言,感谢大家支持!!!

Python手写数字识别+GUI界面+手写板设计相关推荐

  1. MATLAB实现基于BP神经网络的手写数字识别+GUI界面+mnist数据集测试

    文章目录 MATLAB实现基于BP神经网络的手写数字识别+GUI界面+mnist数据集测试 一.题目要求 二.完整的目录结构说明 三.Mnist数据集及数据格式转换 四.BP神经网络相关知识 4.1 ...

  2. python 手写数字识别 封装GUI,手写板获取鼠标写字轨迹信息

    python 手写数字识别知识不用多说,本文用深度学习Python库Keras实现深度学习入门教程mnist手写数字识别.mnist手写数字识别是机器学习和深度学习领域的"hello wor ...

  3. 实验四 手写数字识别的神经网络算法设计与实现

    实验四 手写数字识别的神经网络算法设计与实现 一.实验目的 通过学习BP神经网络技术,对手写数字进行识别,基于结构的识别法及模板匹配法来提高识别率. 二.实验器材 PC机 matlab软件 三.实验内 ...

  4. 模式识别 实验四 手写数字识别的神经网络算法设计与实现

    实验四 手写数字识别的神经网络算法设计与实现 一.实验目的 通过学习BP神经网络技术,对手写数字进行识别,基于结构的识别法及模板匹配法来提高识别率. 二.实验器材 PC机 matlab软件 三.实验内 ...

  5. python手写数字识别实验报告_Python代码实现简单的MNIST手写数字识别(适合初学者看)...

    补充:由于很多同学找我要原数据集和代码,所以我上传到了资源里,https://download..net/download/zugexiaodui/10913834 初学机器学习,第一步是做一个简单的 ...

  6. python手写数字识别实验报告_python神经网络编程实现手写数字识别

    本文实例为大家分享了python实现手写数字识别的具体代码,供大家参考,具体内容如下 import numpy import scipy.special #import matplotlib.pypl ...

  7. python手写数字识别教学_python实现基于SVM手写数字识别功能

    本文实例为大家分享了SVM手写数字识别功能的具体代码,供大家参考,具体内容如下 1.SVM手写数字识别 识别步骤: (1)样本图像的准备. (2)图像尺寸标准化:将图像大小都标准化为8*8大小. (3 ...

  8. python手写数字识别实验报告_机器学习python实战之手写数字识别

    看了上一篇内容之后,相信对K近邻算法有了一个清晰的认识,今天的内容--手写数字识别是对上一篇内容的延续,这里也是为了自己能更熟练的掌握k-NN算法. 我们有大约2000个训练样本和1000个左右测试样 ...

  9. Python 手写数字识别 MNIST数据集下载失败

    目录 一.MNIST数据集下载失败 1 失败的解决办法(经验教训): 2 亲测有效的解决方法: 一.MNIST数据集下载失败 场景复现:想要pytorch+MINIST数据集来实现手写数字识别,首先就 ...

最新文章

  1. ERROR: epmd error for host 192: badarg (unknown POSIX error)
  2. 0.2 秒居然复制了一个 100G 文件?怎么做到的?
  3. OpenCV官方文档
  4. 如何利用云原生技术构建现代化应用
  5. eclipse tomcat jsp乱码
  6. Hybris服务器启动日志分析
  7. jmeter 加密解密_犯罪大师入门篇密文答案 谜之解密入门篇密文解题详解_游戏资讯...
  8. 基于asp.net的音乐分享网站的设计与实现(含源文件)
  9. NOIP 2011 聪明的质检员-二分答案
  10. 可以参考《SpringMVC接口测试异常:Can not deserialize instance
  11. 从零开始学习python编程-如何从零开始学python?
  12. Mac上最好用的HTML文本编辑器BBEdit下载安装教程
  13. 工业互联网发展驶入快车道
  14. CSS - 样式以及样式权重
  15. MFQ(海盗派探索性测试)学习记录
  16. Python笔记 之 dict模块
  17. 三星S5P6818工控底板 (ARM Cortex-A53架构)
  18. 听说,Java程序员都是吃青春饭的?
  19. 今晚7:30 | 连界、将门、百度、碧桂园创投四位大佬眼中的AI世界,是继续高深还是回归商业本质?...
  20. 玩吧斗兽棋的一些攻略 同级子谁胜负问题

热门文章

  1. 常见应用层协议都是基于什么运输层协议的
  2. SpringBoot 系列教程(六十):SpringBoot整合Swagger-Bootstrap-Ui
  3. Infortrend横向扩展NAS又添新功能!DNS 负载均衡让CS飞起来
  4. JS 下载文件两种方式总结
  5. IPTV是什么 IPTV有什么功能
  6. 如何查看小米手机的IP地址和MAC地址
  7. wsdl互联网短信接口_中国移动推出短信小程序,逆袭机会在哪里?
  8. JavaScript Basics
  9. 01.Nodejs1教程
  10. 如何将word单词表中的汉字/英文删掉