项目介绍
手写数字识别增强版。 在 MNist示例程序 的基础上进一步扩展,
阶段要求:
- 能实现多个数字的手写体识别
- 能实现加减乘除符号的识别
- 能做一个手写体识别四则运算的APP (可以是网页服务或手机App)
对此,我们延续 MNist示例程序中使用的模型,将mnist数据集进行扩充,添加了'+', '-', '*', '/', '(', ')'这些符号数据,这通过鼠标手写的人工数据构成。另外,我们修改了使用的CNN中一些参数,包括input,epoch, optimizer等。主要使用的是python以及相应的tensorflow, cv2. PIL等库,最后通过django进行网页制作,简单制作了一个网页版的小画板,将鼠标手写的公式传达至后端进行处理之后,将识别出的公式以及计算结果传至前端。从而实现了一个简约而不简单的手写体识别四则运算的网页。
具体过程描述如下:
- 手写符号数据
- 添加图像处理模块,用于手写数据和手写公式的分割以及标准化(与MNIST数据一致)
- 使用tensorflow建立cnn模型并进行训练
- 添加计算器模块,使用两个栈来实现
- 将使用django整合在一起,并实现一个网页版的画板
项目的github地址为:https://github.com/Godforever/ms
小组成员为: 周雄, 钟宇宏, 杨帆, 吴沛钢
贡献分值为:20.2, 20.1, 19.9, 19.8
各自的github用户名为: Godforever, nanua, Yangf010333, 1163710216
注:使用python环境是python3, 需要安装的库包括django, sklearn, tensorfow, cv2,还有一个tqdm(进度条库)。
二、项目实现
1. 数据获取与处理
结合mnist数据集和人工手写扩充的符号集,作为训练数据和测试数据。由于没有现成的手写符号数据集, 人工手写符号的过程是相当的痛苦的,(唉,允悲!),这里是我们人工手写的数据集并经过标准化处理之后的,点这里!0.0。密码: jods
对于原始输入的数据集,我们采用连通域算法进行图片切割,当然这有个弊端就是我们手写的公式不能连在一起,对于'÷'这个特殊符号,我们特地进行了一些额外的处理。这个算法也会在处理包含公式的图片中用到,下面是连通域算法的主要代码:
def get_x_y_cuts(data, n_lines=1):
// 获取各个小图像的位置范围
w, h = data.shape
visited = set()
q = queue.Queue()
offset = [(-1, -1), (0, -1), (1, -1), (-1, 0), (1, 0), (-1, 1), (0, 1), (1, 1)]
cuts = []
for y in range(h):
for x in range(w):
x_axis = []
y_axis = []
if data[x][y] < 200 and (x, y) not in visited:
q.put((x, y))
visited.add((x, y))
while not q.empty():
x_p, y_p = q.get()
for x_offset, y_offset in offset:
x_c, y_c = x_p + x_offset, y_p + y_offset
if (x_c, y_c) in visited:
continue
visited.add((x_c, y_c))
try:
if data[x_c][y_c] < 200:
q.put((x_c, y_c))
x_axis.append(x_c)
y_axis.append(y_c)
except:
pass
if x_axis:
min_x, max_x = min(x_axis), max(x_axis)
min_y, max_y = min(y_axis), max(y_axis)
if max_x - min_x > 3 and max_y - min_y > 3:
cuts.append([min_x, max_x + 1, min_y, max_y + 1])
if n_lines == 1:
cuts = sorted(cuts, key=lambda x: x[2])
pr_item = cuts[0]
count = 1
len_cuts = len(cuts)
new_cuts = [cuts[0]]
pr_k = 0
for i in range(1, len_cuts):
pr_item = new_cuts[pr_k]
now_item = cuts[i]
if not (now_item[2] > pr_item[3]):
new_cuts[pr_k][0] = min(pr_item[0], now_item[0])
new_cuts[pr_k][1] = max(pr_item[1], now_item[1])
new_cuts[pr_k][2] = min(pr_item[2], now_item[2])
new_cuts[pr_k][3] = max(pr_item[3], now_item[3])
else:
new_cuts.append(now_item)