手写识别也是当前机器学习的一大热点,数字手写识别是手写识别中的基础,咱们用到的是knn算法,今天给你们讲一下个人实现方法;git
IDE:Eclipse
语言:Javagithub
数据采集:咱们知道,一张图片能够被看做一个个点组成的矩阵,对于手写数字,咱们只要建立一个全0数组看成背景,手写完毕把数字所占区域置为1,就能够保存看成一个样本了,以下图所示。
算法:KNN算法,其距离度量咱们采用欧拉距离。
欧拉距离计算方法:咱们将数组看做40*40向量,采用距离公式计算。web
请原谅做者对于美笨拙的感知,我所绘制的界面不可以再简单了。如图:算法
面板按钮介绍:数组
在数据读取存储上走了不少弯路,以后要好好总结下数据流的几个传输方式。
咱们将每张图片转化为一个二维数组后,存放进一个txt文件中。对于每一个单独的文件,咱们要产生一个独一无二的文件名,因此文件取名方式采起“数字+随机id .txt”的格式命名,随机id咱们经过构造UID对象,获取其hashcode值做为id。app
//获取下拉框选中的数字
String selectedNumber=cbItem.getSelectedItem().toString();
UID id=new UID();
//文件的前缀路径
String rootPath="C:\\Users\\DearYou\\eclipse-workspace\\GUI\\src\\Demo\\handwritingIdentify\\TrainingData\\";
//生成文件名
String fileName=selectedNumber+"-"+id.hashCode();
//生成绝对路径下的一个文件
String absoluteFile=rootPath+fileName+".txt";
File file=new File(absoluteFile);
try {
//建立文件
if(!file.exists())
file.createNewFile();
//将数组写入文件
FileWriter out = new FileWriter(file);
for(int i=0;i<40;i++) {
for(int j=0;j<40;j++) {
out.write(pixel[i][j]+"");
}
}
out.flush();
out.close();
}catch(Exception e1) {
e1.printStackTrace();
}
Common thinking :KNN目的是找到k个离测试样本最近的训练样本,看了下同窗的方法,大多都使用了排序,但本身想一想排序实在是多余,一个排序就将复杂度升到了O(nlgn),数据容量一大,性能就会降低。
My thinking:我想咱们只要找到k个距离最近的样本,和顺序并无关系。笔者细想了一下,我么只要构建一个大小为k的数组或者队列,对于前k个元素,咱们直接放进数组,后面的n-k个元素,咱们找到存放在数组中的k个元素中最大值,将两者比较看是否替代。这样咱们只需遍历一遍,复杂度降为O(n),也是一种小优化。eclipse
伪代码:
KnnNode[] dist=new KnnNode[k];
for(int i=0->k){
KnnNode temp=new KnnNode(distance);
dist.append(temp)
}
for(the rest of test set){
if(temp.distance < the maximum element in dist)
dist[index of max]=temp;
}
方法以下展现:
咱们也能够在识别以后保存该样本,这样不能不断扩大数据集,让精度更高。机器学习
虽然能在O(n)复杂度里实现Knn算法,可是个人knn延展性太差,我应该能够把这个knn的参数换成算好的距离,而不是传入的数组,这样就能将这个KNN封装好方便之后再用。
源代码参考地址:https://github.com/Gray-way/HandwritingRecognitionsvg