最近学了一下Python,找个东西练练手。
Python写东西是真的简洁!真的简洁!真的简洁!
要做到手写数字识别基本得靠机器学习,这里用了监督学习里的KNN算法。我参考了这一篇。
KNN算法的思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。
对于识别数字,可以把数字图片先转化成一个n*n的数字矩阵,矩阵中的数字为1个字节即0到255,代表像素点。数字的大小描述这个像素点是接近黑色还是接近白色。接着不妨把这个矩阵转成一个n*n大小的行向量,于是这个图片就可以看成一个n*n维的向量。两个样本即图片的距离就定义成空间欧几里得距离。
这样建出的模型显然是很粗糙的。如同一个形状的同一个数字出现在图中的不同位置,就会被认为是n*n维空间里不同的点。显然我们希望它们能被认为是一个点。为了处理这种情况,实际上是可以把图片进行拉伸、平移等操作以进行调整。但是好麻烦,不想写(逃
手写数字的数据集在这:THE MNIST DATABASE。里面有60000个训练数据,10000个测试数据。因为程序跑得太慢,10000组全测要等一万年,只测了1000组,正确率在0.96左右。
除此之外我还试着测了自己(用mspaint)画的数字,正确率令我绝望…因为没有特殊处理图片,稍微写偏一点就识别不出来也很正常。
下面有两份代码,main.py是主程序,converter.py是一个写了把数据集里的数据解析出来和把图片转成矩阵的函数的模块。
# main.py
import converter # 自己写的能够进行图片和文字转化的module
import numpy as np
import time
beginTime = time.time()
K = 5 # KNN的K
MAX = 10**9
testPath = "test.png" # 待测试图片
traImgPath = "train-images.idx3-ubyte"
traLblPath = "train-labels.idx1-ubyte"
testImgPath = "t10k-images.idx3-ubyte"
testLblPath = "t10k-labels.idx1-ubyte"
traImgArr, rows, cols = converter.convertImage(traImgPath)
traLblList = converter.convertLabel(traLblPath)
testImgArr, rows, cols = converter.convertImage(testImgPath)
testLblList = converter.convertLabel(testLblPath)
def showImg(Img): # 把图片以01矩阵的形式打印出来
for i in range(rows):
print(""