python 手写数字识别 封装GUI,手写板获取鼠标写字轨迹信息
程序员文章站
2024-01-22 11:10:58
...
python 手写数字识别知识不用多说,本文用深度学习Python库Keras实现深度学习入门教程mnist手写数字识别。mnist手写数字识别是机器学习和深度学习领域的“hello world”,MNIST数据集是手写数字的数据集合,训练集规模为60000,测试集为10000。
模型优化和提高识别率请关注后续文章。本文知识对整体代码和原型预演
1、训练模型
通过keras训练模型,并保存该模型
import numpy
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import Flatten
from keras.layers.convolutional import Convolution2D
from keras.layers.convolutional import MaxPooling2D
from keras.utils import np_utils
from keras import backend as K
K.set_image_dim_ordering('th')
seed = 7
numpy.random.seed(seed)
# load data
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# reshape to be [samples][pixels][width][height]
X_train = X_train.reshape(X_train.shape[0], 1, 28, 28).astype('float32')
X_test = X_test.reshape(X_test.shape[0], 1, 28, 28).astype('float32')
X_train = X_train / 255
X_test = X_test / 255
# one hot encode
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
num_classes = y_test.shape[1]
def baseline_model():
# create model
model = Sequential()
model.add(Convolution2D(30, 5, 5, border_mode='valid', input_shape=(1, 28, 28), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Convolution2D(15, 3, 3, activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dense(50, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))
# Compile model
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
return model
model = baseline_model()
model.fit(X_train, y_train, validation_data=(X_test, y_test), nb_epoch=10, batch_size=200, verbose=2)
#
scores = model.evaluate(X_test, y_test, verbose=0)
print("Baseline Error: %.2f%%" % (100 - scores[1] * 100))
model.save('model.h5')
可看到,最终模型训练结果错误率0.75%
取该模型进行GUI封装
- 封装手写识别
# -*- coding:utf-8 -*-
"""
Based on CNN neural network, training handwritten numeral recognition model model.h5.
The class refers to the trained model for handwritten numeral recognition
"""
import numpy as np
from PIL import Image
from keras import backend as K
from keras.models import load_model
from cn.org.whj.ai.day_two.ImageUtils import changeImage28
class Recognition:
def __init__(self,path):
K.set_image_dim_ordering('th')
self.my_model = load_model(path+'/day_one/model.h5')
def readImage2result(self, rimg):
width, height = rimg.size
im = rimg.convert("L")
data = im.getdata()
data = np.matrix(data, dtype='float') / 255.0
new_data = np.reshape(data * 255.0, (height, width))
new_data = new_data[np.newaxis, np.newaxis, :]
pred = self.my_model.predict(new_data)
return np.argmax([pred[0]])
if __name__ == '__main__':
re = Recognition()
rimg = Image.open('only.png')
rimg = changeImage28(rimg)
resut = re.readImage2result(rimg)
print(resut)
- 编写手写板
# -*- coding:utf-8 -*-
"""
Write the number generator, first, into the tablet, which is set to interfere with the picture,
press the m key, the handwritten number. Second, after the handwritten number is completed,
press the w key on the keyboard and perform the screenshot operation.
Drag the screenshot area with the left mouse button, and save the screenshot information automatically after release.
Finally, press q on the keyboard and exit the script
"""
import numpy as np
import cv2 as cv
drawing = False # true if mouse is pressed
mode = True # if True, draw rectangle. Press 'm' to toggle to curve
ix, iy = -1, -1
class Mouse():
# mouse callback function
def __init__(self):
self.img = np.zeros((200, 200, 3), np.uint8)
def draw_circle(self, event, x, y, flags, param):
global ix, iy, drawing, mode
if event == cv.EVENT_LBUTTONDOWN:
drawing = True
ix, iy = x, y
elif event == cv.EVENT_MOUSEMOVE:
if drawing:
if self.mode:
cv.rectangle(self.img, (ix, iy), (x, y), (0, 255, 0), -1)
else:
cv.circle(self.img, (x, y), 5, (0, 0, 255), -1)
elif event == cv.EVENT_LBUTTONUP:
drawing = False
if self.mode:
cv.rectangle(self.img, (ix, iy), (x, y), (0, 255, 0), -1)
else:
cv.circle(self.img, (x, y), 5, (0, 0, 255), -1)
def on_mouse(self, event, x, y, flags, param):
global img, point1, point2
img2 = self.img.copy()
if event == cv.EVENT_LBUTTONDOWN: # 左键点击
point1 = (x, y)
cv.circle(img2, point1, 10, (0, 255, 0), 5)
cv.imshow('Digital writing pad', img2)
elif event == cv.EVENT_MOUSEMOVE and (flags & cv.EVENT_FLAG_LBUTTON): # 按住左键拖曳
cv.rectangle(img2, point1, (x, y), (255, 0, 0), 5)
cv.imshow('Digital writing pad', img2)
elif event == cv.EVENT_LBUTTONUP: # 左键释放
point2 = (x, y)
cv.rectangle(img2, point1, point2, (0, 0, 255), 5)
cv.imshow('Digital writing pad', img2)
min_x = min(point1[0], point2[0])
min_y = min(point1[1], point2[1])
width = abs(point1[0] - point2[0])
height = abs(point1[1] - point2[1])
cut_img = self.img[min_y:min_y + height, min_x:min_x + width]
cv.imwrite('only.png', cut_img)
def create_image(self):
self.mode = True
cv.namedWindow('Digital writing pad')
cv.setMouseCallback('Digital writing pad', self.draw_circle)
while (1):
cv.imshow('Digital writing pad', self.img)
k = cv.waitKey(1) & 0xFF
if k == ord('m'):
self.mode = not mode
elif k == 27:
break
elif k == ord('w'):
cv.setMouseCallback('Digital writing pad', self.on_mouse)
elif k == ord('q'):
break
cv.destroyAllWindows()
if __name__ == '__main__':
mn = Mouse()
mn.create_image()
- 整体GUI显示
# -*- coding:utf-8 -*-
from tkinter import *
import tkinter as tk
from cn.org.whj.ai.day_two.Mouse import Mouse
from PIL import Image, ImageTk
from cn.org.whj.ai.day_one.handwriting_recognition import Recognition
from cn.org.whj.ai.day_two.ImageUtils import changeImage28
import os
def creat_image():
mn = Mouse()
mn.create_image()
class App(tk.Frame):
def __init__(self, root):
super().__init__(root)
root.title('手写识别')
w = Canvas(root, width=500, height=20)
w.pack()
Label(root, text='欢迎使用手写识别系统,以下为使用说明').pack(side=TOP)
Label(root, text='1、点击生成手写图片按钮,摁下m切换到手写状态,点击鼠标左键,进行手写操作。').pack(side=TOP, anchor=W)
Label(root, text='2、手写✅后,摁下w进行切图操作,点击鼠标左键,选择截取数字区域').pack(side=TOP, anchor=W)
Label(root, text='3、点击刷新按钮,回显截图').pack(side=TOP, anchor=W)
Label(root, text='4、点击数字识别按钮,识别截图中数字(0~9)').pack(side=TOP, anchor=W)
Label(root, text='识别到数字是:').pack(side=TOP, anchor=W)
self.numLabel = Label(root, text='', relief=RAISED,fg="red", font=("黑体", 30, "bold"))
self.numLabel.pack(side=TOP, anchor=CENTER)
Label(root, text='').pack(side=TOP, anchor=W)
fm = Frame(root)
# Button是一种按钮组件,与Label类似,只是多出了响应点击的功能
Button(fm, text='生成手写图片', command=creat_image).pack(side=TOP, anchor=W, fill=X, expand=YES)
Button(fm, text='刷新', command=self.changeImage).pack(side=TOP, anchor=W, fill=X, expand=YES)
Button(fm, text='数字识别', command=self.recognition).pack(side=TOP, anchor=W, fill=X, expand=YES)
Button(fm, text='汉字识别').pack(side=TOP, anchor=W, fill=X, expand=YES)
fm.pack(side=LEFT, fill=BOTH, expand=YES, padx=20)
self.pilImage = Image.open("only.png")
self.tkImage = ImageTk.PhotoImage(image=self.pilImage)
self.label = Label(root, image=self.tkImage)
self.label.pack()
Label(root, text="按住鼠标左键并移动,开始绘制你的理想蓝图吧......").pack(side=BOTTOM)
def changeImage(self):
self.png = tk.PhotoImage(file="only.png") # 需要储存为实例属性,否则会被垃圾回收
self.label.configure(image=self.png)
def recognition(self):
base_dir = os.path.dirname(os.getcwd())
re = Recognition(base_dir)
img = Image.open('only.png')
img = changeImage28(img)
results = re.readImage2result(rimg=img)
self.numLabel.configure(text=str(results))
if __name__ == '__main__':
root = Tk()
app = App(root)
root.mainloop()
效果图:
源码地址:https://github.com/hongjieWang/python-Splder/tree/master/cn/org/whj/ai