KNN识别图像上的数字及python实现
图像文本识别的步骤一般为图像预处理,图片切割,特征提取、文本分类和图像文本输出几个步骤,我们也可以按这个步骤来识别图像中的数字。
一、图像预处理
在图像预处理中,验证码识别还要对图像进行去燥,文字还原等比较复杂的处理,由于我的图像没什么干扰因素,所以直接对其进行二值处理即可。处理结果如下:
因为图片上的数据灰度值都是75或76,所以只需把灰度值等于75或76的赋为1,其余的为0即可,代码如下:
def pretreatment(ima):
ima=ima.convert('L') #转化为灰度图像
im=numpy.array(ima) #转化为二维数组
for i in range(im.shape[0]):#转化为二值矩阵
for j in range(im.shape[1]):
if im[i,j]==75 or im[i,j]==76:
im[i,j]=1
else:
im[i,j]=0
return im
ima=PIL.Image.open('e://bwtest2//6//6-1.png') #读入图像
im=pretreatment(ima) #调用图像预处理函数
for i in im:
print(i)
图像预处理
二、图片切割
因为最小的识别单位是10以内的个位数字,所以有必要对图片中的数据进行切割,然后逐个对其识别。切割的过程如下:
切割的过程其实就是对二值矩阵进行分片的过程,只要找到0到1和1到0的过度点就可以判断出切割点的位置了。
三、特征提取
对图片进行切割后,得提取出每个图片的特征,然后才能做后续的处理。图像的特征很多,本文选取1占所在区域的比例作为图片特征。首先将图片分为四部分,如下图所示:
然后计算左上部分1所占的比例A1、左下部分1所占的比例A2、右上部分1所占的比例A3、右下部分1所占的比例A4和所有1占整副图的比例A5。这样,就提取出了此幅图的特征向量A=[A1,A2,A3,A4,A5]。664那副图的特征分别为:
可见两个6的特征极其相似,和4的特征相差有点大。切割图片并提取特征的代码如下:
#提取图片特征
def feature(A):
midx=int(A.shape[1]/2)+1
midy=int(A.shape[0]/2)+1
A1=A[0:midy,0:midx].mean()
A2=A[midy:A.shape[0],0:midx].mean()
A3=A[0:midy,midx:A.shape[1]].mean()
A4=A[midy:A.shape[0],midx:A.shape[1]].mean()
A5=A.mean()
AF=[A1,A2,A3,A4,A5]
return AF #切割图片并返回每个子图片特征
def incise(im):
#竖直切割并返回切割的坐标
a=[];b=[]
if any(im[:,0]==1):
a.append(0)
for i in range(im.shape[1]-1):
if all(im[:,i]==0) and any(im[:,i+1]==1):
a.append(i+1)
elif any(im[:,i]==1) and all(im[:,i+1]==0):
b.append(i+1)
if any(im[:,im.shape[1]-1]==1):
b.append(im.shape[1])
#水平切割并返回分割图片特征
names=locals();AF=[]
for i in range(len(a)):
names['na%s' % i]=im[:,range(a[i],b[i])]
if any(names['na%s' % i][0,:]==1):
c=0
elif any(names['na%s' % i][names['na%s' % i].shape[0]-1,:]==1):
d=names['na%s' % i].shape[0]-1
for j in range(names['na%s' % i].shape[0]-1):
if all(names['na%s' % i][j,:]==0) and any(names['na%s' % i][j+1,:]==1):
c=j+1
elif any(names['na%s' % i][j,:]==1) and all(names['na%s' % i][j+1,:]==0):
d=j+1
names['na%s' % i]=names['na%s' % i][range(c,d),:]
AF.append(feature(names['na%s' % i])) #提取特征
for j in names['na%s' % i]:
print(j)
return AF ima=PIL.Image.open('e://bwtest2//test//5.png')
im=pretreatment(ima) #图片预处理
AF=incise(im) #切割图片并提取特征
for i in AF:
print(i)
切割图片并提取特征
四、数字分类
文本分类的方法有k最近邻算法、支持向量机、神经网络等,本文选用的是最简单的最近邻算法。
K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。KNN算法中,所选择的邻居都是已经正确分类的对象。相比于其他算法,其时间复杂度和空间复杂度都很高,但具有精度高、对异常值不敏感、无输入数据假定的优点。
要让计算机识别东西,首先得告诉它这东西长啥样,然后它才能正确的识别。所以我把系统中的“0、1、2、3、4、5、6、7、8、9、.”各截了15副图放到文件夹中,如下图所示:
其中,‘‘10’’夹中放的是“.”,test文件夹中放的是待识别的数据。KNN算法的具体实现步骤如下:
1)提取1-10文件夹中所有图片的特征并保存在字典train_set中
2)分割并提取待识别图片的的特征
3)每个特征都和train_set中的所有特征计算距离
4)对距离进行排序,并选出排名前K个的键值
5)统计K个键值中每个类别出现的个数,出现个数最多的类别就是最终的分类
6)合并所有子特征的分类结果即是这幅图片上的数字
664那副图的KNN分类结果和源程序如下
#训练已知图片的特征
def training():
train_set={}
for i in range(11):
value=[]
for j in range(15):
ima=PIL.Image.open('e://bwtest2//'+str(i)+'//'+str(i)+'-'+str(j)+'.png')
im=pretreatment(ima)
AF=incise(im)
value.append(AF[0])
train_set[i]=value
#把训练结果存为永久文件,以备下次使用
output=open('e://bwtest2//train_set.pkl','wb')
pickle.dump(train_set,output)
output.close()
return train_set #计算两向量的距离
def distance(v1,v2):
vector1=numpy.array(v1)
vector2=numpy.array(v2)
Vector=(vector1-vector2)**2
distance = Vector.sum()**0.5
return distance #用最近邻算法识别单个数字
def knn(train_set,V,k):
key_sort=[11]*k
value_sort=[11]*k
for key in range(11):
for value in train_set[key]:
d=distance(V,value)
for i in range(k):
if d<value_sort[i]:
for j in range(k-2,i-1,-1):
key_sort[j+1]=key_sort[j]
value_sort[j+1]=value_sort[j]
key_sort[i]=key
value_sort[i]=d
break
max_key_count=-1
key_set=set(key_sort)
for key in key_set:
if max_key_count<key_sort.count(key):
max_key_count=key_sort.count(key)
max_key=key
return max_key #合并一副图片的所有数字
def identification(train_set,AF,k):
result=''
for i in AF:
key=knn(train_set,i,k)
if key==10:
key='.'
result=result+str(key)
return float(result) train_set=training()
ima=PIL.Image.open('e://bwtest2//test//5'.png')
im=pretreatment(ima) #预处理
AF=incise(im) #分割并提取图片
identification(train_set,AF,7) #knn识别
KNN分类实例
五、图片数字输出
最后,我们需要识别test文件夹中的所有图片并把识别出的数字输出到EXCEL文件中。并对数据的状态做一些简单的判断,输出部分结果如下:
其中,第一列为昨日的备份数据(尚未采集),第二列为今日需识别的数据,第三列为今日数据的状态。此程序识别正确率达到百分之百,看来用图像识别的方法完成录入图片数据工作不失为一种好的策略啊。本文用的版本为python3.5,完整程序如下:
import numpy
import PIL.Image
import pickle
import xlwt #图片预处理
def pretreatment(ima):
ima=ima.convert('L') #转化为灰度图像
im=numpy.array(ima) #转化为二维数组
for i in range(im.shape[0]):#转化为二值矩阵
for j in range(im.shape[1]):
if im[i,j]==75 or im[i,j]==76:
im[i,j]=1
else:
im[i,j]=0
return im #提取图片特征
def feature(A):
midx=int(A.shape[1]/2)+1
midy=int(A.shape[0]/2)+1
A1=A[0:midy,0:midx].mean()
A2=A[midy:A.shape[0],0:midx].mean()
A3=A[0:midy,midx:A.shape[1]].mean()
A4=A[midy:A.shape[0],midx:A.shape[1]].mean()
A5=A.mean()
AF=[A1,A2,A3,A4,A5]
return AF #切割图片并返回每个子图片特征
def incise(im):
#竖直切割并返回切割的坐标
a=[];b=[]
if any(im[:,0]==1):#避免截图没截好的情况
a.append(0)
for i in range(im.shape[1]-1):
if all(im[:,i]==0) and any(im[:,i+1]==1):
a.append(i+1)
elif any(im[:,i]==1) and all(im[:,i+1]==0):
b.append(i+1)
if any(im[:,im.shape[1]-1]==1):
b.append(im.shape[1])
#水平切割并返回分割图片特征
names=locals() #初始化分割后子图片的动态变量名
AF=[] #初始化子图片的特征列表
for i in range(len(a)):
names['na%s' % i]=im[:,range(a[i],b[i])]
if any(names['na%s' % i][0,:]==1):
c=0
elif any(names['na%s' % i][names['na%s' % i].shape[0]-1,:]==1):
d=names['na%s' % i].shape[0]-1
for j in range(names['na%s' % i].shape[0]-1):
if all(names['na%s' % i][j,:]==0) and any(names['na%s' % i][j+1,:]==1):
c=j+1
elif any(names['na%s' % i][j,:]==1) and all(names['na%s' % i][j+1,:]==0):
d=j+1
names['na%s' % i]=names['na%s' % i][range(c,d),:]
AF.append(feature(names['na%s' % i]))
for j in names['na%s' % i]:
print(j)
return AF #训练已知图片的特征
def training():
train_set={}
for i in range(11):
value=[]
for j in range(15):
ima=PIL.Image.open('e://bwtest2//'+str(i)+'//'+str(i)+'-'+str(j)+'.png')
im=pretreatment(ima)
AF=incise(im) #切割并提取特征
value.append(AF[0])
train_set[i]=value
#把训练结果存为永久文件,以备下次使用
output=open('e://bwtest2//train_set.pkl','wb')
pickle.dump(train_set,output)
output.close()
return train_set #计算两向量的距离
def distance(v1,v2):
vector1=numpy.array(v1)
vector2=numpy.array(v2)
Vector=(vector1-vector2)**2
distance = Vector.sum()**0.5
return distance #用最近邻算法识别单个数字
def knn(train_set,V,k):
key_sort=[11]*k
value_sort=[11]*k
for key in range(11):
for value in train_set[key]:
d=distance(V,value)
for i in range(k):#从小到大排序
if d<value_sort[i]:
for j in range(k-2,i-1,-1):
key_sort[j+1]=key_sort[j]
value_sort[j+1]=value_sort[j]
key_sort[i]=key
value_sort[i]=d
break
max_key_count=-1
key_set=set(key_sort)
for key in key_set: #统计每个类别出现的次数
if max_key_count<key_sort.count(key):
max_key_count=key_sort.count(key)
max_key=key
return max_key #合并一副图片的所有数字
def identification(train_set,AF,k):
result=''
for i in AF:
key=knn(train_set,i,k)
if key==10:
key='.'
result=result+str(key)
return float(result) #识别文件夹中的所有图片上的数据并输出到EXCELL中
def main(k,trained=None,backup=None):
# k:knn算法的的k,即取训练集中最相邻前k个样本进行判别
#trained:trained=0则程序会开始训练出训练集,否则会用已保存的训练集
#backup:backup=0则程序令昨日数据均为0,并备份今日数据到昨日数据和昨日测试数据
# backup=1则程序会令昨日数据为昨日测试数据,并备份今日数据到昨日测试数据
# backup等于其他时则程序会令昨日数据为昨日数据,并备份今日数据到昨日数据
if trained==0:
train_set=training()
else:
pkl_file=open('e://bwtest2//train_set.pkl','rb')
train_set=pickle.load(pkl_file)
pkl_file.close()
if backup==0:
yestoday_data=[0]*32
elif backup==1:
pkl_file=open('e://bwtest2//yestoday_data_test.pkl','rb')
yestoday_data=pickle.load(pkl_file)
pkl_file.close()
else:
pkl_file=open('e://bwtest2//yestoday_data.pkl','rb')
yestoday_data=pickle.load(pkl_file)
pkl_file.close()
backups=[]
workbook = xlwt.Workbook('e://bwtest2//bwtest2.xls')
sheet = workbook.add_sheet("record and contrast")
#设置EXCEL字体为绿色
font = xlwt.Font()
font.colour_index = 3
style = xlwt.XFStyle()
style.font = font
#识别所有图片的数字并输出到EXCELL中
for i in range(1,33):
ima=PIL.Image.open('e://bwtest2//test//'+str(i)+'.png')
im=pretreatment(ima)
AF=incise(im)
result=identification(train_set,AF,k)
backups.append(result)
sheet.write(i-1, 0, yestoday_data[i-1])
if result==yestoday_data[i-1]:
sheet.write(i-1, 1, result,style)
sheet.write(i-1, 2, '正常')
else:
sheet.write(i-1, 1, result)
sheet.write(i-1, 2, '待定')
workbook.save('e://bwtest2//bwtest2.xls')
if backup==0:
output=open('e://bwtest2//yestoday_data_test.pkl','wb')
pickle.dump(backups,output)
output.close()
output=open('e://bwtest2//yestoday_data.pkl','wb')
pickle.dump(backups,output)
output.close()
elif backup==1:#/yestoday_data_test用来测试之用
output=open('e://bwtest2//yestoday_data_test.pkl','wb')
pickle.dump(backups,output)
output.close()
else:
output=open('e://bwtest2//yestoday_data.pkl','wb')
pickle.dump(backups,output)
output.close() main(4,0,0) #表示:4近邻,还没有训练集备份,还没有昨日数据备份
knn_classify
KNN识别图像上的数字及python实现的更多相关文章
- python 识别图片上的数字
https://blog.csdn.net/qq_31446377/article/details/81708006 ython 3.6 版本 Pytesseract 图像验证码识别 环境: (1) ...
- C#识别图片上的数字
通过Emgu实现对图片上的数字进行识别. 前期步骤: 1.下载Emgu安装文件,我的版本是2.4.2.1777.3.0版本则实现对中文的支持. 2.安装后需填写环境变量,环境变量Path值后加入Emg ...
- 分享C#识别图片上的数字
通过Emgu实现对图片上的数字进行识别.前期步骤:1.下载Emgu安装文件,我的版本是2.4.2.1777.3.0版本则实现对中文的支持.2.安装后需填写环境变量,环境变量Path值后加入Emgu安装 ...
- python 在图像上写中文字体 (python write Chinese in image)
本人处理图像的时候经常使用opencv的包,但是 cv2.putText 显示不了中文,所以查找了如何在python在图像上写中文的方法,在伟大的Stack Overflow上面找到一个方法,分享给大 ...
- 如何用python和苹果Turicreate学习框架来识别图像?
大多数人听到深度学习,都会望而却步,因为会觉得很难,在这个人工智能飞速进步的时代,我也来抓一下时代的尾巴~ 两周前,我开始接触到python和Turicreate框架,经过不懈的努力,终于有所收获,特 ...
- python 识别图像主题并切割
两种办法,一种是用百度的API,效果还可以,不过好像每天有50次的调用的限制 from aip import AipImageClassify import cv2 """ ...
- c#实现识别图片上的验证码数字
这篇文章主要介绍了c#实现识别图片上的验证码数字的方法,本文给大家汇总了2种方法,有需要的小伙伴可以参考下. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 1 ...
- 利用CNN进行流量识别 本质上就是将流量视作一个图像
from:https://netsec2018.files.wordpress.com/2017/12/e6b7b1e5baa6e5ada6e4b9a0e59ca8e7bd91e7bb9ce5ae89 ...
- 基于OpenCV的KNN算法实现手写数字识别
基于OpenCV的KNN算法实现手写数字识别 一.数据预处理 # 导入所需模块 import cv2 import numpy as np import matplotlib.pyplot as pl ...
随机推荐
- Fiddler替换HTTP Request Host
原文链接:http://caibaojian.com/fiddler.html 这边指的替换HTTP Request Host是,所有原先发到a.com的HTTP Request , Fiddler都 ...
- Android SD卡存储
原创文章,转载请注明出处:http://www.cnblogs.com/baipengzhan/p/Android_SDcard_store.html 一 概念 SD卡存储空间比较大,当需要存取较大的 ...
- Jmeter插件监控服务器性能
处理利用jmeter实施监控压测时受压机的各项性能 操作步骤: 施压机上的jmeter/lib/ext中放入下载的插件包 jmeter-plugins-perfmon-2.1.jar 受压机上放入Se ...
- UML大战需求分析--阅读笔记02
这次阅读了第三章--类图.本章主要讲解了类图的基本使用规则和一些使用的例子.类图是UML中非常重要的一部分,作用很大. 类图之间有五种关系:关联关系,聚合关系,组合关系,泛化关系,依赖关系.关联关系有 ...
- marked.js简易手册
marked.js简易手册 本文介绍的是marked.js.秉持"来之即用"的原则,对它进行简要的翻译和归纳, 安装 在网上引用或者是引用本地文件即可.要么就用命令行: npm i ...
- redis技巧--自动完成功能实现
自动完成功能一般都伴随搜索框出现,就是用户在输入时帮助其自动补全. 比如对成语进行补全,现有如下成语:一心一意,一心二用,一帆风顺. 两种实现方式: 实现方式一: 为每个成语的每个前缀都使用一个集合类 ...
- mysql 常用函数整理
1.length(字段名) 2.UNIX_TIMESTAMP(字段名) 3.FROM_UNIXTIME( 1249488000, '%Y%m%d' ) 4.ceil() 5.floor() 6.CAS ...
- linux下安装postgresql
环境:Linux localhost.localdomain 2.6.32-431 GNU/Linux x86_64 Postgresql版本:postgresql.9.5.3 添加开启自启设置:ht ...
- iOS-Block总结 && 全面解析逆向传值
1.block的特点: block是C语言: block是一种数据类型.可以当做参数,也可以用做返回值:--总之,对比int的用法用即可(当然,定义的时候,最好跟函数对比): ...
- Oracle操作
1.查询表空间地址: select name from v$datafile; 2.创建表空间: create tablespace yysspace datafile ‘D:\APP\MIAO\OR ...