✅ 毕业设计:Python+Keras手写数字识别系统 PyQt5界面+CNN+OpenCV 卷积神经网络 深度学习(建议收藏)✅
博主介绍:✌全网粉丝10W+,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业项目实战6年之久,选择我们就是选择放心、选择安心毕业✌
> 🍅想要获取完整文章或者源码,或者代做,拉到文章底部即可与我联系了。🍅🍅感兴趣的可以先收藏起来,点赞、关注不迷路,大家在毕设选题,项目以及论文编写等相关问题都可以给我留言咨询,希望帮助同学们顺利毕业 。🍅
1、毕业设计:2026年计算机专业毕业设计选题汇总(建议收藏)✅
2、大数据毕业设计:2026年选题大全 深度学习 python语言 JAVA语言 hadoop和spark(建议收藏)✅
1、项目介绍
技术栈:python语言、Keras模型、CNN算法、PyQt5图形界面、OpenCV
研究背景:
手写数字识别是计算机视觉入门经典任务,传统人工录入易出错,亟需一套可交互、可上传、实时识别的桌面端工具辅助教学与票据录入。
研究意义:
本系统基于Keras+CNN训练MNIST模型,集成PyQt5图形界面,支持画板手写、图片上传、橡皮擦修正,可为毕业设计提供“模型-界面-OpenCV处理”完整闭环,预计识别准确率>98%,显著提升课堂演示与票据处理效率。
2、项目界面
(1)手写数字识别检测
(2)橡皮擦功能
(3)上传图片检测识别
(4)手写数字识别检测
(5)界面效果
3、项目说明
程序基于Keras框架构建CNN卷积神经网络,使用MNIST手写数字数据集(60 000张训练图像、10 000张测试图像)进行训练。首先通过mnist.load_data加载数据,并利用matplotlib展示样本;随后将28×28图像reshape为(28,28,1)并归一化至0-1区间,标签转one-hot编码。网络结构包含3个卷积层+2个全连接层,激活函数采用ReLU,优化器为RMSProp,损失函数为交叉熵。训练5轮、batch_size=64、验证集比例10%,最终在测试集获得>98%准确率,模型保存为my_mnist_model.h5。
图形界面使用PyQt5开发,主程序CallWindows.py启动PaintBoard.py画板:支持鼠标手写、橡皮擦修正、颜色对比度增强、OpenCV轮廓分割;点击“识别”即时返回预测数字与置信度。同时支持图片上传批量检测,结果可保存为CSV。系统界面简洁,操作步骤:绘制→识别→清除→保存,为教学演示与票据录入提供轻量级、可落地的手写数字识别解决方案。
关键词:手写数字识别;CNN;Keras;PyQt5;MNIST
4、核心代码
from PyQt5.QtWidgets import QWidget
from PyQt5.Qt import QPixmap, QPainter, QPoint, QPaintEvent, QMouseEvent, QPen, \
QColor, QSize
from PyQt5.QtCore import Qt
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from keras.datasets import mnist
import matplotlib.pyplot as plt
from keras import models
from keras import layers
from keras.utils.np_utils import to_categorical
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
# 定义模型
def model_conv():
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))
model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['acc'])
return model
# 导入MNIST数据集
(train_data, train_labels), (test_data, test_labels) = mnist.load_data()
print('train_shape {} {}'.format(train_data.shape, train_labels.shape))
print('test_shape {} {}'.format(test_data.shape, test_labels.shape))
plt.imshow(train_data[0])
plt.title('number {}'.format(train_labels[0]))
plt.show()
# 数据预处理
x_train = train_data.reshape((60000, 28, 28, 1))
x_train = x_train.astype('float32') / 255
x_test = test_data.reshape((10000, 28, 28, 1))
x_test = x_test.astype('float32') / 255
y_train = to_categorical(train_labels)
y_test = to_categorical(test_labels)
print(x_train.shape, y_train.shape)
# 定义模型
model = model_conv()
print(model.summary())
# 开始训练
his = model.fit(x_train, y_train, epochs=5, batch_size=64, validation_split=0.1)
# 计算准确度
loss, acc = model.evaluate(x_test, y_test)
print('loss {}, acc {}'.format(loss, acc))
# 保存模型
model.save("my_mnist_model.h5")
class Sketchpad(QWidget):
def __init__(self, Parent=None):
super().__init__(Parent)
self.__InitData() # 先初始化数据,再初始化界面
self.__InitView()
def __InitData(self):
# 私有变量size,画板初始大小为480,460
self.__size = QSize(611, 461)
# 新建QPixmap作为画板,尺寸为__size
# 私有变量__board就是画板实体,大小就是__size
self.__board = QPixmap(self.__size)
self.__board.fill(Qt.white) # 用白色填充画板
self.__IsEmpty = True # 默认为空画板
self.EraserMode = False # 默认为禁用橡皮擦模式
self.__lastPos = QPoint(0, 0) # 上一次鼠标位置
self.__currentPos = QPoint(0, 0) # 当前的鼠标位置
self.__painter = QPainter() # 新建绘图工具:画笔
self.__thickness = 10 # 默认画笔粗细为10px
self.__penColor = QColor("black") # 设置默认画笔颜色为黑色
self.__colorList = QColor.colorNames() # 获取颜色列表
def __InitView(self):
# 设置界面的尺寸为__size
self.setFixedSize(self.__size)
def Clear(self):
# 清空画板
self.__board.fill(Qt.white)
self.update()
self.__IsEmpty = True
def ChangePenColor(self, color="black"):
# 改变画笔颜色
self.__penColor = QColor(color)
def ChangePenThickness(self, thickness=10):
# 改变画笔粗细
self.__thickness = thickness
def IsEmpty(self):
# 返回画板是否为空
return self.__IsEmpty
def GetContentAsQImage(self):
# 获取画板内容(返回QImage)
image = self.__board.toImage()
return image
def paintEvent(self, paintEvent):
# 绘图事件
# 绘图时必须使用QPainter的实例,此处为__painter
# 绘图在begin()函数与end()函数间进行
# begin(param)的参数要指定绘图设备,即把图画在哪里
# drawPixmap用于绘制QPixmap类型的对象
self.__painter.begin(self)
# 0,0为绘图的左上角起点的坐标,__board即要绘制的图
self.__painter.drawPixmap(0, 0, self.__board)
self.__painter.end()
def mousePressEvent(self, mouseEvent):
# 鼠标按下时,获取鼠标的当前位置保存为上一次位置
self.__currentPos = mouseEvent.pos()
self.__lastPos = self.__currentPos
def mouseMoveEvent(self, mouseEvent):
# 鼠标移动时,更新当前位置,并在上一个位置和当前位置间画线
self.__currentPos = mouseEvent.pos()
self.__painter.begin(self.__board)
if self.EraserMode == False:
# 非橡皮擦模式
self.__painter.setPen(QPen(self.__penColor, self.__thickness)) # 设置画笔颜色,粗细
else:
# 橡皮擦模式下画笔为纯白色,粗细为10
self.__painter.setPen(QPen(Qt.white, 20))
# 画线
self.__painter.drawLine(self.__lastPos, self.__currentPos)
self.__painter.end()
self.__lastPos = self.__currentPos
self.update() # 更新显示
def mouseReleaseEvent(self, mouseEvent):
self.__IsEmpty = False # 画板不再为空
5、源码获取方式
🍅由于篇幅限制,获取完整文章或源码、代做项目的,查看我的【用户名】、【专栏名称】、【顶部选题链接】就可以找到我啦🍅
感兴趣的可以先收藏起来,点赞、关注不迷路,下方查看👇🏻获取联系方式👇🏻
更多推荐


所有评论(0)