1.手写数字识别技术的含义
手写数字识别(Handwritten Digit Recognition)是光学字符识别技术的一个分支,是模式识别学科的一个传统研究领域。主要研究如何利用电子计算机自动辨认手写在纸张上的阿拉伯数字。手写数字识别分为脱机手写数字识别和联机手写数字识别。本文主要讨论脱机手写数字的识别。 随着信息化的发展,手写数字识别的应用日益广泛,研究高识别率、零误识率和低拒识率的高速识别算法具有重要意义。
2.手写数字识别技术的理论价值
由于手写数字识别本身的特点,对它的研究有重要的理论价值:
(1)阿拉伯数字是唯一被世界各国通用的符号,对手写体数字识别的研究基本上与文化背景无关,各地的研究工作者基于同一平台开展工作,有利于研究的比较和探讨。
(2) 手写数字识别应用广泛,如邮政编码自动识别,税表系统和银行支票自动处理等。这些工作以前需要大量的手工录入,投入的人力物力较多,劳动强度较大。手写数字识别的研究适应了无纸化办公的需要,能大大提高工作效率。
⑶由于数字类别只有 10 个,较其他字符识别率较高,可用于验证新的理论和做深入的分析研究。许多机器学习和模式识别领域的新理论和算法都是先用手写数字识别进行检验,验证理论的有效性,然后才应用到更复杂的领域当中。这方面的典型例子就是人工神经网络和支持向量机(Support Vector Machine)。
⑷手写数字的识别方法很容易推广到其它一些相关问题,如对英文之类拼音文字的识别。事实上,很多学者就是把数字和英文字母的识别放在一起研究的。
3.数字识别技术的难点
数字的类别只有 10
种,笔划简单,其识别问题似乎不是很困难。但事实上,一些测试结果表明,数字的正确识别率并不如印刷体汉字识别率高,甚至也不如联机手写体汉字识别率高,而只仅仅优于脱机手写体汉字识别。这其中的主要原因是:
⑴数字笔划简单,其笔划差别相对较小,字形相差不大,使得准确区分某些数字相当困难;
⑵数字虽然只有 10 种,且笔划简单,但同一数字写法千差万别,全世界各个国家各个地区的人都在用,其书写上带有明显的区域特性,很难做出可以兼顾世界各种写法的、识别率极高的通用性数字识别系统。
虽然目前国内外对脱机手写数字识别的研究已经取得了很大的成就,但是仍然存在两大难点:
一是识别精度需要达到更高的水平。手写数字识别没有上下文,数据中的每一个数据都至关重要。而数字识别经常涉及金融、财会领域,其严格性更是不言而喻。因此,国内外众多的学者都在为提高手写数字的识别率,降低误识率而努力。
二是识别的速度要达到很高的水平。数字识别的输入通常是很大量的数据,而高精度与高速度是相互矛盾的,因此对识别算法提出了更高的要求。
首先,我们拿到了两个文件夹。
一个文件夹里的图片同来训练出一个分类器/模型
另一个文件夹的图片对训练出的分类器/模型性能进行评估
图片预处理我没有采用二值化的方法,因为我的数字图片比较清晰吧,我觉得对于这些数字没有必要,根据实际情况吧,但二值化对于后面的预测还是有点点影响的
算法选择
以下列举三个算法代码都会实现(但选其中一个就可以了)
KNN算法
逻辑回归算法
卷积神经网络
构建模型,训练,对模型进行评分
image_process.py
from PIL import Image
import numpy as np
import os, re
import matplotlib.pylab as plt
def get_img_names(path):
file_names = os.listdir(path)
img_names = []
for i in file_names:
if re.findall('\d_\d+\.png', i) != []:
img_names.append(i)
return img_names
def get_img_data(path):
data = [] # 特征数据(图像数组)
labels = [] # 目标(标签)数据
img = get_img_names(path)
# print(img)
img = np.array(img)
# print(img.shape)
n = int(img.shape[0] / 10) + 1 # 得到每个数字的图片数
for i in range(10):
for j in range(1, n):
img = Image.open(path + "%d_%d.png" % (i, j)) # 打开图片
# print(img) #
img = img.resize((32, 32)) # 将图片化为32*32的
img = img.convert('RGBA') # "L"为灰度化
raw_data = img.load() # 得到图片的像素值
# 将其降噪并转化为黑白两色
for y in range(img.size[1]):
for x in range(img.size[0]):
if raw_data[x, y][0] < 90:
raw_data[x, y] = (0, 0, 0, 255)
for y in range(img.size[1]):
for x in range(img.size[0]):
if raw_data[x, y][1] < 136:
raw_data[x, y] = (0, 0, 0, 255)
for y in range(img.size[1]):
for x in range(img.size[0]):
if raw_data[x, y][2] > 0:
raw_data[x, y] = (255, 255, 255, 255)
# print(img) #
img.save(path + '%d_%d(%d).png' % (i, j, i)) # 保存,方便查看
# 读取图片,一共有10个数字(0-9),每个有12张图片.图片命名格式为:_0_1.png
digit = plt.imread(path + '%d_%d(%d).png' % (i, j, i))
data.append(digit) # 逐个图片添加
labels.append(i)
# 把列表转成数组
data = np.array(data)
labels = np.array(labels)
# 查看数组形状
# print(data.shape) # (120,)
# 随机显示一张图片(方便查看,上述操作后是否有变化)
# index = np.random.randint(0, 20, size=1)[0]
# img_ = data[index]
# plt.figure(figsize=(0.3, 0.3)) # 设置画布宽为0.3,高为0.3
# plt.imshow(img_, cmap='gray') # 显示颜色为gray
# plt.axis("off") # 去掉坐标轴
# plt.show()
# print(labels[index])
return data, labels
data.py
from image_process import get_img_data
from sklearn.neighbors import KNeighborsClassifier # KNN算法
from sklearn.metrics import classification_report, confusion_matrix
import matplotlib.pyplot as plt
# 得到训练集和测试集样本
data_tr, labels_tr = get_img_data("trainImages/")
data_te, labels_te = get_img_data("testImages/")
# (120, 32, 32, 4) (120,) (30, 32, 32, 4) (30,)
# 训练数据要为二维数组,如果不做转换会报如下错误,说4维数组不能做运算。报错: ValueError: Found array with dim 4. Estimator expected <= 2.
# data_tr = data_tr.reshape(120, -1)
# data_te = data_te.reshape(30, -1)
# print(data_tr.shape, labels_tr.shape, data_te.shape, labels_te.shape) # (120, 4096) (120,) (30, 4096) (30,)
# 使用KNN算法 n_neighbors: int,默认值为5,表示knn算法中选取离测试数据最近的k个点,
model = KNeighborsClassifier(n_neighbors=1) # 构建模型
model.fit(data_tr.reshape(120, -1), labels_tr) # 训练模型
pre = model.predict(data_te.reshape(30, -1)) # 预测
print(pre)
# 对训练后的模型进行评分(# 模型在测试集上的精度)
acc = model.score(data_te.reshape(30, -1), labels_te)
print(acc)
# 性能评价
print(confusion_matrix(labels_te, pre)) # confusion_matrix:混淆矩阵
print(classification_report(labels_te, pre))
# 可视化预测结果
# 画布大小10行10列,每行高为1,每列宽为1.5
plt.figure(figsize=(10*1, 10*1.5))
for i in range(30):
#绘制子图
axes = plt.subplot(10, 10, i+1)
#测试数据为500张,绘制其中的30张
axes.imshow(data_te[i], cmap='gray')
#添加标题
t = labels_te[i]
p = pre[i]
axes.set_title('True:%d\nPred:%d' % (t, p))
#不显示坐标刻度
axes.axis('off')
plt.savefig('axes.png')
plt.show()
KNN算法的正确率不是特别高,如果想要达到0.9几的可以尝试卷积神经网络
这里有设计了一个知识点:监督算法和无监督算法
结果:
[1 0 0 1 1 1 2 1 7 3 7 3 4 1 4 5 5 6 6 6 6 7 7 7 8 6 8 9 3 9]
0.7333333333333333
[[2 1 0 0 0 0 0 0 0 0]
[0 3 0 0 0 0 0 0 0 0]
[0 1 1 0 0 0 0 1 0 0]
[0 0 0 2 0 0 0 1 0 0]
[0 1 0 0 2 0 0 0 0 0]
[0 0 0 0 0 2 1 0 0 0]
[0 0 0 0 0 0 3 0 0 0]
[0 0 0 0 0 0 0 3 0 0]
[0 0 0 0 0 0 1 0 2 0]
[0 0 0 1 0 0 0 0 0 2]]
precision recall f1-score support
0 1.00 0.67 0.80 3
1 0.50 1.00 0.67 3
2 1.00 0.33 0.50 3
3 0.67 0.67 0.67 3
4 1.00 0.67 0.80 3
5 1.00 0.67 0.80 3
6 0.60 1.00 0.75 3
7 0.60 1.00 0.75 3
8 1.00 0.67 0.80 3
9 1.00 0.67 0.80 3
accuracy 0.73 30
macro avg 0.84 0.73 0.73 30
weighted avg 0.84 0.73 0.73 30
Process finished with exit code 0