Python实现基于KNN算法的笔迹识别功能详解


Posted in Python onJuly 09, 2018

本文实例讲述了Python实现基于KNN算法的笔迹识别功能。分享给大家供大家参考,具体如下:

需要用到:

  • Numpy库
  • Pandas库
  • 手写识别数据 点击此处本站下载

数据说明:

数据共有785列,第一列为label,剩下的784列数据存储的是灰度图像(0~255)的像素值 28*28=784

KNN(K近邻算法):

从训练集中找到和新数据最接近的K条记录,根据他们的主要分类来决定新数据的类型。

这里的主要分类,可以有不同的判别依据,比如“最多”,“最近邻”,或者是“距离加权”。

整个程序的几个部分:

1.数据的归一化处理(normalization)
2.(重要)找出与test数据最接近的train数据的编号,根据编号查找到对应的label,将label赋给test数据的预测值
3.统计知道的test的label值与test的预测label值得正确率

Step 1

导入Numpy与Pandas库

import numpy as np
import pandas as pd

Step 2

对数据进行归一化

对数据归一化的方法很多,比如:

一、max-Min标准化

max - Min标准化方法是对原始数据进行线性变换。设minA和maxA分别为属性A的最小值和最大值,将A的一个原始值x通过max-Min标准化映射成在区间[0,1]中的值x',其公式为:

新数据=(原数据-极小值)/(极大值-极小值)

二、

新数据=原数据/(原数据的平方和开根号)

三、

y = ( x - min )/( max - min ) 其中min为x的最小值,max为x的最大值,输入向量为x,归一化后的输出向量为y 。上式将数据归一化到 [ 0 , 1 ]区间,当激活函数采用S形函数时(值域为(0,1))时这条式子适用

在这里采用方法二

def normalize(x):
 norms = np.apply_along_axis(np.linalg.norm,1,x)
 return x / np.expand_dims(norms,-1)

调用np中的linalg.norm(x)apply_along_axis(func, axis, x)函数

linalg.norm(x)函数的作用是 return sum(abs(xi)**2)**0.5

apply_along_axis(func, axis, x)函数的作用是将x按axis方向执行func函数,axis=0表示做列方向上的运算,axis=1表示做行方向上的运算

step 3

找出与test数据最接近的train数据,这步是最关键的一步。

在这里,test数据与train数据就是空间的两个向量,问题就变成了如何计算这两个向量的相似程度。

我们可以把它们想象成空间中的两条线段,都是从原点([0, 0, ...])出发,指向不同的方向。两条线段之间形成一个夹角,如果夹角为0度,意味着方向相同、线段重合;如果夹角为90度,意味着形成直角,方向完全不相似;如果夹角为180度,意味着方向正好相反。因此,我们可以通过夹角的大小,来判断向量的相似程度。夹角越小,就代表越相似。

假定a向量是[x1, y1],b向量是[x2, y2],那么可以将余弦定理改写成下面的形式:

Python实现基于KNN算法的笔迹识别功能详解

余玄定理

def nearest_neighbor(norm_func,train_data,train_label,test_data):
 train_data = norm_func(train_data)
 test_data = norm_func(test_data)
 cos = np.dot(train_data,np.transpose(test_data))#np.transpose为求转置,dot为矩阵的乘积,结果为cos的一列值为test与train的相似度
 max_cos = np.argmax(cos,axis=0)#np.argmax为cos中一列上方的最大值
 test_pred = train_label[max_cos]#train_label为一列,max_cos为一个数组,train_label[max_cos]会读出train_label中max_cos数组编号的元素
 return test_pred#返回test的预测值

step 4

统计预测值的正确率

def validate(test_pred,test_label):
 c=len(test_pred)#在数组里面套数组的时候,len得到的是大数组里数组的个数,在只有一层数组的时候,得到的是数组中元素的个数
 correct=(test_pred == test_label).sum()#统计两个数组中有多少个元素相同
 return float(correct)/c#必须转变成浮点数再做除法,之前使用correct/c得到0

测试代码:

if __name__ == '__main__':
 train_num = 200
 test_num = 300#测试数据起始是test_num-train_num
 x = pd.read_csv('train.csv')
 x_train = x.values[0:train_num,1:]#读取pandas中读取出来的数据,需要用data.values[]
 x_train_label = x.values[0:train_num,0]#第一列是label,每幅图的数据是一行
 x_test = x.values[train_num:test_num,1:]
 x_test_label = x.values[train_num:test_num,0]
 test_pred=nearest_neighbor(normalize,x_train,x_train_label,x_test)
 prec=validate(test_pred,x_test_label)
 print u"正确率为%.2f"%(prec)#浮点数是%f

完整代码点击此处本站下载

注解:

上面部分主要是讲解KNN算法,运用到的是现成的28*28的数据,而在实际做笔迹分析的时候,首先需要将图像转化成矩阵数据。

现在介绍一下,图像转化成矩阵与矩阵转化成图像的方法

矩阵转化成图像

需要用到的库是图像处理库Python Imaging Library (PIL)

在Windows下使用pip install PIL安装失败,采取了下载PIL.exe双击安装的方法
下载地址:

PIL官方下载地址

import pandas as pd
import numpy as np
from PIL import Image
# load data
train = pd.read_csv('train.csv')
# now draw the numbers
for ind, row in train.iloc[0:3].iterrows():#iloc方法(介绍见后)来获得前3行数据
 i = row[0]#[0]为标签项
 arr = np.array(row[1:], dtype=np.uint8)#1-784列组成一幅图,,uint8为8位无符号整数
 #arr = np.array(255 - row[1:], dtype=np.uint8)#如果需要颜色取反,用255减去当前每个像素点的值
 arr.resize((28, 28))#把它变成28*28的矩阵
 #save to file
 im = Image.fromarray(arr)
 im.save("./train_pics/%s-%s.png" % (ind, i))#第一个%s(ind)表示它是第几幅图像,第二个%s表示这个图像里面数字是几 ,注意该语句不能产生文件夹,需要现在指定目录建一个文件夹

.iloc()方法

iloc[行位置,列位置]
df.iloc[1,1]#选取第二行,第二列的值,返回的为单个值
df.iloc[0,2],:]#选取第一行及第三行的数据

图像转化成矩阵

需要用到的库是opencv(open source computer vision),下载安装方式请参照附录:python_OpenCV安装

这里主要讲它的几个简单功能

1.静态图像的输入,输出

cv2.imread('xxx.png')#输入,#这里输入image的维度image.shape = (w,h,3),w*h是图片的长宽,3是BGR等三种颜色的channel值,每个值为0~255
cv2.imwrite('xxx.jpg', image)#输出

2.将图片转化为灰度图片

#灰度图片的颜色channel只有一个,0~255表示灰度值
grayImage = cv2.imread('xxx.png',cv2.CV_LOAD_IMAGE_GRAYSCALE)

3.改变图像的大小

print grayImage.shape#查看图像的shape,shape为(137,301),如果查看的是图像的size,则为42137(41237=137*301)
res=cv2.resize(grayImage,(28,28),interpolation=cv2.INTER_CUBIC)#将图片grayImage以cv2.INTER_CUBIC方式变化为(28,28)大小的图片

变换的方法:

  • CV_INTER_NN - 最近邻插值,
  • CV_INTER_LINEAR - 双线性插值 (缺省使用)
  • CV_INTER_AREA - 使用象素关系重采样。当图像缩小时候,该方法可以避免波纹出现。当图像放大时,类似于 CV_INTER_NN 方法..
  • CV_INTER_CUBIC -立方插值.

下面是有关输入,输出,改变成灰度图,改变图像大小,显示的完整程序,注意图像在窗口中的显示

import cv2
image = cv2.imread('111.png')#读
cv2.imwrite('111.jpg', image)#写
grayImage = cv2.imread('111.png',cv2.CV_LOAD_IMAGE_GRAYSCALE)
print grayImage.shape
res=cv2.resize(grayImage,(28,28),interpolation=cv2.INTER_CUBIC)
#显示图像
cv2.imshow('test',grayImage)#显示灰度图
cv2.imshow('change',res)#显示改变了大小的图
#捕获键盘输入
k=cv2.waitKey(0)
if k==27:#27表示ESC键
 cv2.destroyWindow()

cv2.imshow()用于将图片显示在窗口中,后面必须跟个cv2.waitKey()函数,才能让显示持续,不然显示出来程序就中止了,窗口就会被关闭。cv2.waitKey()函数是捕获键盘的输入,cv2.destroyWindow()是释放窗口。

在学习了如果读取,输出图片后,我们就可以用写好的KNN算法识别我们的笔迹了。

问题:

我使用了很多手写的数据去验证识别是否准确,发现准确率还不够高。主要存在的问题是

1.图片大小问题,大小的调节不应该把整张图片变为28*28的图,而应该识别出写有数字的中心图片,把旁边的白边去掉

2.手写的数字照片,不能保证写字的地方为黑(像素值为255)

解决方式:需要使用一个滤波器,把因纸张,拍摄问题出现的像素值降。再没有使用滤波器的条件下,我把照片换成了在画图板上写的数字。

3.写字的粗细会影响判断

解决办法:这个可能是训练样本不够多,整体训练样本的字迹偏粗,在输入很细的笔迹时,不能识别出来。还有就是应该监测输入字体的粗细,对输入的很细的笔迹做膨胀处理,对很粗的笔迹做腐蚀处理

附:python_OpenCV安装

看到网上好多教程的是在VS环境下OpenCV的安装,而我一直都是在windows7,32位,sublime+cmd环境下,进行python的编程,所以琢磨了下这种条件下的OpenCV安装

使用pip install numpy语句安装numpy
(如果出现错误:Microsoft Visual C++ 9.0 is required <unable to find vcvarsall.bat>,使用管理员身份安装 Microsoft Visual C++ 9.0,重新启动计算机,再使用使用pip install numpy语句安装numpy

opencv2.4.10下载

下载之后解压(随便解压到哪里),将解压目录opencv文件夹中,build->python->2.7->x86下的文件cv2.pyd 复制到python2.7\Lib\site-packages

测试是否安装成功,执行解压目录下的sources\samples\python\drawing.py或者进入python环境,使用import cv2

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
Python 专题五 列表基础知识(二维list排序、获取下标和处理txt文本实例)
Mar 20 Python
Python socket实现的简单通信功能示例
Aug 21 Python
python调用百度语音REST API
Aug 30 Python
python实现移位加密和解密
Mar 22 Python
python做反被爬保护的方法
Jul 01 Python
python实现两张图片拼接为一张图片并保存
Jul 16 Python
详解python中*号的用法
Oct 21 Python
python3.8 微信发送服务器监控报警消息代码实现
Nov 05 Python
django实现web接口 python3模拟Post请求方式
Nov 19 Python
pyspark给dataframe增加新的一列的实现示例
Apr 24 Python
Python实现壁纸下载与轮换
Oct 19 Python
PyCharm 安装与使用配置教程(windows,mac通用)
May 12 Python
Python 16进制与中文相互转换的实现方法
Jul 09 #Python
python 文件转成16进制数组的实例
Jul 09 #Python
使用Python读取二进制文件的实例讲解
Jul 09 #Python
Python实现随机漫步功能
Jul 09 #Python
Python2包含中文报错的解决方法
Jul 09 #Python
对numpy数据写入文件的方法讲解
Jul 09 #Python
可能是最全面的 Python 字符串拼接总结【收藏】
Jul 09 #Python
You might like
基于php伪静态的实现详细介绍
2013/04/28 PHP
解析linux下安装memcacheq(mcq)全过程笔记
2013/06/27 PHP
PHP获取php,mysql,apche的版本信息示例代码
2014/01/16 PHP
thinkPHP模板中for循环与switch语句用法示例
2016/11/30 PHP
Yii2实现自定义独立验证器的方法
2017/05/05 PHP
Yii2 队列 shmilyzxt/yii2-queue 简单概述
2017/08/02 PHP
Array.prototype.slice.apply的使用方法
2010/03/17 Javascript
JavaScript 操作键盘的Enter事件(键盘任何事件),兼容多浏览器
2010/10/11 Javascript
JQuery操作表格(隔行着色,高亮显示,筛选数据)
2012/02/23 Javascript
JS获取URL中的参数数据
2013/12/05 Javascript
js与运算符和或运算符的妙用
2014/02/14 Javascript
使用JavaScript实现旋转的彩圈特效
2015/06/23 Javascript
jquery实现的树形目录实例
2015/06/26 Javascript
分享15个大家都熟知的jquery小技巧
2015/12/02 Javascript
Node.js Streams文件读写操作详解
2016/07/04 Javascript
JS button按钮实现submit按钮提交效果
2016/11/01 Javascript
js实现随机抽选效果、随机抽选红色球效果
2017/01/13 Javascript
浅谈原型对象的常用开发模式
2017/07/22 Javascript
vue改变对象或数组时的刷新机制的方法总结
2019/04/24 Javascript
JQuery的加载和选择器用法简单示例
2019/05/13 jQuery
Python实现包含min函数的栈
2016/04/29 Python
python调用百度语音识别api
2018/08/30 Python
Python自定义函数计算给定日期是该年第几天的方法示例
2019/05/30 Python
pytorch之添加BN的实现
2020/01/06 Python
pytorch 彩色图像转灰度图像实例
2020/01/13 Python
CSS3实现时间轴效果
2016/07/11 HTML / CSS
美国二手奢侈品寄售网站:TheRealReal
2016/10/29 全球购物
类成员函数的重载、覆盖和隐藏区别
2016/01/27 面试题
毕业生求职推荐信
2013/11/04 职场文书
董事长岗位职责
2013/11/30 职场文书
热情服务标语
2014/10/07 职场文书
2014年乡镇安全生产工作总结
2014/12/02 职场文书
原告离婚代理词
2015/05/23 职场文书
2015年暑期实践报告范文
2015/07/13 职场文书
期中考试后的感想
2015/08/07 职场文书
解决python存数据库速度太慢的问题
2021/04/23 Python