AI手写输入法 - pytorch从入门到入道(二)
本章承接上一篇的手写数字识别,利用训练好的模型,结合pyqt画板,实现简易手写输入法,为"hello world"例子增添乐趣。
pyqt是开发图形界面的框架,可以百度查找相关资料了解安装及基础方法,我搭建的环境是pycharm+pyqt5+qtdesigner,配置好之后的界面长这样:

在左边的项目中右键某个文件,也可以打开qt菜单
具体怎么画界面不展开了,直接看下代码:
# coding: utf-8
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
sys.path.append(r'../ml/torch')
from digit_recog import Net
import torch
import os
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
net = Net().to(device)
# 加载参数
nn_state = torch.load(os.path.join('../ml/torch/model/', 'net.pth'))
# 参数加载到指定模型
net.load_state_dict(nn_state)
net.eval() def predict(img):
# 读取图片并重设尺寸
image = Image.open(img).resize((28, 28))
# 灰度图
gray_image = image.convert('L')
# plt.imshow(gray_image)
# plt.show()
# 图片数据处理
im_data = np.array(gray_image)
im_data = torch.from_numpy(im_data).float()
im_data = im_data.view(1, 1, 28, 28)
# 神经网络运算
outputs = net(im_data)
# 取最大预测值
_, pred = torch.max(outputs, 1)
return pred.item() class SimpleDrawingBoard(QWidget):
win = ''
wins = [] @classmethod
def showWin(cls):
# 聚焦到已有窗口
if not cls.win:
cls.win = cls()
cls.win.show()
else:
cls.win.activateWindow() def __init__(self, parent=None):
super(SimpleDrawingBoard, self).__init__(parent) self.setWindowTitle(u"手写数字识别")
self.setWindowFlags(Qt.WindowStaysOnTopHint)
self.size = (400, 350)
self.resize(*self.size)
self.setWindowFlag(Qt.FramelessWindowHint) # 隐藏边框
# self.setWindowOpacity(0.9) # 设置窗口透明度
# self.setAttribute(Qt.WA_TranslucentBackground) # 设置窗口背景透明 self.canvasSize = (280, 350)
self.sizeOffset = [a - b for a, b in zip(self.size, self.canvasSize)]
self.canvas = QPixmap(*self.canvasSize)
self.canvas.fill(Qt.black)
self.tempCanvas = QPixmap()
self.lastPoint = QPoint()
self.endPoint = QPoint()
self.isDrawing = False
self.penSize = 15 self.initUI() def initUI(self):
self.penSizeLabel = QLabel(u'画笔粗细')
self.penSizeSpinBox = QSpinBox()
self.penSizeSpinBox.setValue(self.penSize)
self.penSizeSpinBox.valueChanged.connect(self.penSizeSpinBox_valueChanged)
self.penSizeSpinBox.setFixedWidth(80) self.clearButton = QPushButton(u'清空')
self.clearButton.setFixedWidth(80)
self.clearButton.clicked.connect(self.clearPainter) self.closeButton = QPushButton(u'关闭')
self.closeButton.setFixedWidth(80)
self.closeButton.clicked.connect(self.close) self.inputLabel = QLabel(self)
self.inputLabel.setFixedSize(80, 200)
self.inputLabel.setAutoFillBackground(True)
self.inputLabel.setAlignment(Qt.AlignCenter)
self.inputLabel.setStyleSheet('''QLabel{background:#F76677;border-radius:5px;font-size:60px;font-weight:bolder;}''') mainLayout = QVBoxLayout(self) toolbarLayout = QGridLayout()
# toolbarLayout.setSpacing(20)
toolbarLayout.addWidget(self.penSizeLabel, 0, 0, 1, 1)
toolbarLayout.addWidget(self.penSizeSpinBox, 1, 0, 1, 1)
toolbarLayout.addWidget(self.clearButton, 2, 0, 1, 1)
toolbarLayout.addWidget(self.closeButton, 3, 0, 1, 1)
toolbarLayout.addWidget(self.inputLabel, 4, 0, 1, 1) toolbarLayout.setAlignment(Qt.AlignLeft) mainLayout.addLayout(toolbarLayout)
mainLayout.addStretch(1) def penSizeSpinBox_valueChanged(self):
# 设置画笔粗细
self.penSize = self.penSizeSpinBox.value() def paintEvent(self, event):
pp = QPainter(self.canvas)
pen = QPen(QColor(255, 255, 255), self.penSize)
pp.setPen(pen)
if self.lastPoint != self.endPoint:
pp.drawLine(self.lastPoint - QPoint(*self.sizeOffset), self.endPoint - QPoint(*self.sizeOffset))
painter = QPainter(self)
painter.drawPixmap(self.sizeOffset[0], self.sizeOffset[1], self.canvas)
self.lastPoint = self.endPoint def clearPainter(self):
print('clear...')
self.canvas.fill(Qt.black)
painter = QPainter(self)
painter.drawPixmap(self.sizeOffset[0], self.sizeOffset[1], self.canvas)
self.lastPoint = self.endPoint
self.update()
self.inputLabel.clear() def mousePressEvent(self, event):
# 按下左键
if event.button() == Qt.LeftButton:
self.lastPoint = event.pos()
self.endPoint = self.lastPoint
self.isDrawing = True def mouseMoveEvent(self, event):
if self.isDrawing:
self.update()
self.endPoint = event.pos() def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
self.isDrawing = False
self.endPoint = event.pos()
self.update()
self.canvas.toImage().save('input.png')
input = predict('input.png')
self.inputLabel.setText(str(input))
print('你输入的是{}'.format(input)) if __name__ == '__main__':
app = QApplication.instance()
if not app:
app = QApplication(sys.argv)
SimpleDrawingBoard.showWin()
app.exec_()
上面引入前一章训练好的模型,位于不同的文件夹内,需要加上这一行代码:
sys.path.append(r'../ml/torch')
看下运行效果:


上面写了两个数字,识别输出正确!
helloworld例子比较枯燥,通过动手参与与AI交互增强信心乐趣,信心是一步步建立起来的,而大的突破亦是如此,后面会持续围绕简单的例子,深入发掘AI的乐趣与应用场景。
AI手写输入法 - pytorch从入门到入道(二)的更多相关文章
- 识别手写数字增强版100% - pytorch从入门到入道(一)
手写数字识别,神经网络领域的“hello world”例子,通过pytorch一步步构建,通过训练与调整,达到“100%”准确率 1.快速开始 1.1 定义神经网络类,继承torch.nn.Modul ...
- 《深度学习框架PyTorch:入门与实践》的Loss函数构建代码运行问题
在学习陈云的教程<深度学习框架PyTorch:入门与实践>的损失函数构建时代码如下: 可我运行如下代码: output = net(input) target = Variable(t.a ...
- 通通WPF随笔(4)——通通手写输入法(基于Tablet pc实现)
原文:通通WPF随笔(4)--通通手写输入法(基于Tablet pc实现) 从我在博客园写第一篇博客到现在已经有1年半了,我的第一篇博客写的就是手写识别,当时,客户需求在应用中加入手写输入功能,由于第 ...
- 《深度学习框架PyTorch:入门与实践》读书笔记
https://github.com/chenyuntc/pytorch-book Chapter2 :PyTorch快速入门 + Chapter3: Tensor和Autograd + Chapte ...
- pytorch怎么入门学习
pytorch怎么入门学习 https://www.zhihu.com/question/55720139
- pytorch从入门到放弃(目录)
目录 前置基础 Pytorch从入门到放弃 推荐阅读 前置基础 Python从入门到放弃(目录) 人工智能(目录) Pytorch从入门到放弃 01_pytorch和tensorflow的区别 02_ ...
- 【笔记】PyTorch快速入门:基础部分合集
PyTorch快速入门 Tensors Tensors贯穿PyTorch始终 和多维数组很相似,一个特点是可以硬件加速 Tensors的初始化 有很多方式 直接给值 data = [[1,2],[3, ...
- [OpenCV入门教程之十二】OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑
http://blog.csdn.net/poem_qianmo/article/details/25560901 本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog ...
- Redis入门很简单之二【常见操作命令】
Redis入门很简单之二[常见操作命令] 博客分类: NoSQL/Redis/MongoDB redisnosql缓存 Redis提供了丰富的命令,允许我们连接客户端对其进行直接操作.这里简单介绍一 ...
随机推荐
- (JavaScript) base64 字符串 和 ArrayBuffer 之间转换
base64 --> ArrayBuffer function base64ToUint8Array(base64String) { const padding = '='.repeat((4 ...
- mac os 10.15 virtualBox6.0.12崩溃
VBoxManage setextradata global GUI/HidLedsSync 0 参考:https://www.virtualbox.org/ticket/18990
- SpringCloud之Hystrix-Dashboard监控,以及踩的坑...
前言: 最近刚入职,公司使用了SpringCloud,之前有了解过SpringCloud,但是长时间不去搭建不去使用很容易就忘了,因此空闲时间重新复习一下SpringCloud.但是之前开的Sprin ...
- SVD分解
首先,有y = AX,将A看作是对X的线性变换 但是,如果有AX = λX,也就是,A对X的线性变换,就是令X的长度为原来的λ倍数. *说起线性变换,A肯定要是方阵,而且各列线性无关.(回想一下,A各 ...
- 使用“反向传播”迭代法求解y=√10
X=√10,求X,也就是求Y=10 =X2 , X是多少. *重要的思想是,如何转化为可迭代求解的算法问题. *解数学问题,第一时间画图,求导,“直线化”. Y = X2 假如已知Y = 10 ,要求 ...
- 深入理解C#第三版部分内容
最近,粗略的读了<深入理解C#(第三版)>这本技术书,书中介绍了C#不同版本之间的不同以及新的功能. 现在将部分摘录的内容贴在下面,以备查阅. C#语言特性: 1.C#2.0 C#2的主 ...
- 爬虫学习--Day4(网页采集器的实现)
#UA: User-Agent {请求载体的身份标识}#(反爬机制)UA检测:门户网站的服务器回检测对应请求的载体身份标识,如果检测到请求的载体身份为某一款浏览器就说明该请求时一个正常的请求.但是,如 ...
- 百度艾尼ERNIE专场再入魔都,11月23日线下开讲!
这个十一月,是属于深度学习开发者们的秋季盛宴.『WAVE Summit+』2019 深度学习开发者秋季峰会刚刚落下帷幕,基于ERNIE的语义理解工具套件也在此次峰会上全新发布,旨在为企业级开发者提供更 ...
- 深入理解计算机系统 第八章 异常控制流 part2
关于进程,需要关注其提供给应用程序的两个关键抽象: 1.一个独立的逻辑控制流,它提供一个假象,好像我们的程序独占地使用处理器 2.一个私有的地址空间,它提供一个假象,好像我们的程序独占地使用内存系统 ...
- 微擎框架商业版 V2.1.2 去后门一键安装版+去除云平台+无附带模块
下载地址:http://dd.ma/AdVvoDu5 关注微信公众号codervip,点击公众号菜单,获取提取码! 这个是一键安装版本,所以微擎安装比较简单,不用大家手动去改数据库了,而且修复上个2. ...