数字手写体识别的基本原理
在一家邮局,有许多包裹和信件的快递单都是手工填写的,如果需要利用计算机视觉进行分拣,则可以根据邮政编码进行,这就涉及大量的手写体数字需要识别。由于数字是从0,1,2一直到9的,数量较少,可以采用类似我们进行语音识别的方式进行。只不过这次我们采集的不是声波,而是图像信息。
在一个图像信息中,有图的地方就存在一定信息,例如笔画、颜色等,而其余部分是空白。
手写体数字
如果按照计算机的数据存储方式,一个简单的表示方法是空白处用0表示,而有颜色的部分用1表示,更进一步,有颜色的部分可以根据颜色的深浅写成小数,表示其灰度信息。如果我们希望每个数字的表达都是统一规格的,我们可以加上一个规定大小的栅格,根据栅格上的灰度值确定数值,如下图所示。
数字的灰度信息
这样每个手写体数字都对应一个栅格图(图中设计了一个8×8的栅格),如果我们只取其灰度信息,就可以把一个数字表示成一个8×8的数阵(矩阵)。我们来看一看下面两个数阵,大家发挥一下想象力,看看这分别是数字几。
数字的灰度值一
此时,我们把0的部分想象成空白,把有数字的部分(特别是数值较大的部分)连在一起,发现了吗?
数字的轮廓
再来看一组0和2。
数字的灰度值二
1.关于输入向量
每一个0或者2都是不完全相同的,它们之间的差别还是比较大的,如第7章所介绍的解决分类问题,手写体数字识别同样也是一个分类问题,需要我们建立模型,进行训练,适应不同的输入,给出正确的预测结果。手写体数字识别与分类问题的区别在于输入向量的处理以及模型类型的选择等。如前面鸢尾花的识别问题一样,对于大多数模型来说,处理一个1×n的输入向量相对容易,因此可以将上面的数阵转换为一个1×64的向量来送入模型并进行处理。当然,这种处理方式割裂了上下行之间的联系,随着模型的发展,深度网络可以对矩阵进行直接的处理,可取得更好的效果,这在后面的物体检测中会介绍。对于这个相对简单的数字手写体识别问题,可以采用向量方式输入。
2.关于模型
这里采用的模型是支持向量机(SVM)。支持向量机将向量映射到一个更高维的空间里,在这个空间里建有一个最大间隔超平面。这个超平面将数据分开,使得两类数据离这个超平面的距离最大化。我们可以这样理解这个问题,比如有两个数字1和-1,那么区分这两个数字的界限可以是0,0.3,-0.5,在这些数字中,0具备最好的区分度,离两边都比较远。这是一个一维的情况。如果是二维空间中的点,区分它们的就将是一条线;在三维空间中,就将是一个面;而在更高维的空间中,就将是一个超平面。支持向量机就是将低维空间中无法用直线分开的数据映射到高维空间中,并找到这样一个超平面,尽可能地将不同的类分开。
支持向量机原理
低维空间中不可分的两种物体在高维空间中就会变得可分,这如何理解?例如数学中的三棱锥和圆锥,从正视图看,两个图形是一样的,是三角形,而在三维空间中,它们完全不一样。支持向量机对原输入进行一个非线性映射,映射到高维空间中,使原有信息发生改变,从而使计算机能够更好地进行区分。
不同维度的视角
数字手写体识别的Python程序
这个程序和第7章的程序流程类似,都需要导入相应的库,导入数据集,建立模型,进行训练和预测。本程序参考http://scikit-learn.org/stable/auto_examples/classification/plot_digits_classification.html#sphx-glr-auto-examplesclassification-plot-digits-classification-py。原作者为Gael Varoquaux。
----------------------part 1 导入相关库----------------------
#需要安装matplotlib 和sklearn ,可以在cmd窗口通过pip install指令进行安装
import matplotlib.pyplot as plt
from sklearn import datasets,svm,metrics
----------------------part 2 导入数据集----------------------
#说明:每个手写体数字存储成图像后,进行栅格化处理,即将图像分为一个8×8的网格,每个数字都表示为网格上的灰度值的组合,即每个数字都表达为一个8×8的矩阵(digits.images)或者一个64维的向量(digits.data),目标值为数字的值,如0,1,2等
digits=datasets.load_digits()
print(digits.data)
digits.data.shape
images_and_labels=list(zip(digits.images,digits.target))#zip()函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表,这里实际上就是将每一个数字的特征输入和特征输出进行一一对应,组成一个个元组,最后组成列表。下面给出列表images_and_labels中的第一项
----------------------part 3 绘制图像----------------------(www.xing528.com)
#enumerate()函数用于遍历序列中的元素以及它们的下标
for index,(image,label)in enumerate(images_and_labels[:4]):
plt.subplot(2,4,index+1)
plt.axis('off')
plt.imshow(image,cmap=plt.cm.gray_r,interpolation='nearest')
plt.title('Training:%i'% label)
------------------part 4 建立模型、训练模型------------------
#在建立分类器模型之前,为了让分类器可以处理这些图像,我们需要将图像的存储格式进行改变,此处利用reshape()函数将样本数据的格式重新进行存储,形成一个1 797×64的输入矩阵,每一行都对应一个数字
n_samples=len(digits.images)#数据的个数计算,共有1797组数据
data=digits.images.reshape((n_samples,-1))
#创建分类器SVM(支持向量机分类器)
classifier=svm.SVC(gamma=0.001)
#用分类器学习前一半的样本数据
classifier.fit(data[:n_samples//2],digits.target[:n_samples//2])
----------------------part 5 模型预测----------------------
#用训练好的分类器预测另一半数据
expected=digits.target[n_samples//2:]#期望值
predicted=classifier.predict(data[n_samples//2:])#预测值
print("Classification report for classifier %s:\n%s\n"%(classifier,metrics.classification_report(expected,predicted)))
print("Confusion matrix:\n%s" % metrics.confusion_matrix(expected,predicted))
#将预测结果绘图展示
images_and_predictions=list(zip(digits.images[n_samples//2:],predicted))
for index,(image,prediction)in enumerate(images_and_predictions[:4]):
plt.subplot(2,4,index+5)
plt.axis('off')
plt.imshow(image,cmap=plt.cm.gray_r,interpolation='nearest')
plt.title('Prediction:%i'% prediction)
plt.show()
小P说一说
数字手写体的识别过程包括提取信息(数阵),建立训练集合与校验集,建立模型,训练模型以及选择模型。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。