图像文本识别的步骤一般为图像预处理,图片切割,特征提取、文本分类和图像文本输出几个步骤,我们也可以按这个步骤来识别图像中的数字。

一、图像预处理

在图像预处理中,验证码识别还要对图像进行去燥,文字还原等比较复杂的处理,由于我的图像没什么干扰因素,所以直接对其进行二值处理即可。处理结果如下:

因为图片上的数据灰度值都是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实现的更多相关文章

  1. python 识别图片上的数字

    https://blog.csdn.net/qq_31446377/article/details/81708006 ython 3.6 版本 Pytesseract 图像验证码识别 环境: (1) ...

  2. C#识别图片上的数字

    通过Emgu实现对图片上的数字进行识别. 前期步骤: 1.下载Emgu安装文件,我的版本是2.4.2.1777.3.0版本则实现对中文的支持. 2.安装后需填写环境变量,环境变量Path值后加入Emg ...

  3. 分享C#识别图片上的数字

    通过Emgu实现对图片上的数字进行识别.前期步骤:1.下载Emgu安装文件,我的版本是2.4.2.1777.3.0版本则实现对中文的支持.2.安装后需填写环境变量,环境变量Path值后加入Emgu安装 ...

  4. python 在图像上写中文字体 (python write Chinese in image)

    本人处理图像的时候经常使用opencv的包,但是 cv2.putText 显示不了中文,所以查找了如何在python在图像上写中文的方法,在伟大的Stack Overflow上面找到一个方法,分享给大 ...

  5. 如何用python和苹果Turicreate学习框架来识别图像?

    大多数人听到深度学习,都会望而却步,因为会觉得很难,在这个人工智能飞速进步的时代,我也来抓一下时代的尾巴~ 两周前,我开始接触到python和Turicreate框架,经过不懈的努力,终于有所收获,特 ...

  6. python 识别图像主题并切割

    两种办法,一种是用百度的API,效果还可以,不过好像每天有50次的调用的限制 from aip import AipImageClassify import cv2 """ ...

  7. c#实现识别图片上的验证码数字

    这篇文章主要介绍了c#实现识别图片上的验证码数字的方法,本文给大家汇总了2种方法,有需要的小伙伴可以参考下. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 1 ...

  8. 利用CNN进行流量识别 本质上就是将流量视作一个图像

    from:https://netsec2018.files.wordpress.com/2017/12/e6b7b1e5baa6e5ada6e4b9a0e59ca8e7bd91e7bb9ce5ae89 ...

  9. 基于OpenCV的KNN算法实现手写数字识别

    基于OpenCV的KNN算法实现手写数字识别 一.数据预处理 # 导入所需模块 import cv2 import numpy as np import matplotlib.pyplot as pl ...

随机推荐

  1. Xamarin.ios 目录结构

    1.Resources: 文件夹存放应用程序所. 2.AppDelegate.cs: 主要的应用程序类别(class) ,并接听 系统事件及相对应的事件处理. 3.Entitlements.plist ...

  2. logistic regression与SVM

    Logistic模型和SVM都是用于二分类,现在大概说一下两者的区别 ① 寻找最优超平面的方法不同 形象点说,Logistic模型找的那个超平面,是尽量让所有点都远离它,而SVM寻找的那个超平面,是只 ...

  3. js正则匹配过滤 特殊字符

    function stripscript(s)  {      var pattern = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\].<& ...

  4. 深入浅出学Spring Data JPA

    第一章:Spring Data JPA入门 Spring Data是什么 Spring Data是一个用于简化数据库访问,并支持云服务的开源框架.其主要目标是使得对数据的访问变得方便快捷,并支持map ...

  5. PHPCMS调用点击量的方法

    具体方法: 首先:需要在show.html 模板中首先加载jquery.min.js 这个js 其次:需要在要显示点击次数的位置写入: <span>点击:<span id=" ...

  6. thinkphp3.2和phpexcel导入

    先整个最基础的代码,理解了这个,后面的就非常简单了 $file_name= './Upload/excel/123456.xls'; import("Org.Util.PHPExcel&qu ...

  7. 每天写点shell--命令行参数

    1.读取参数:位置参数变量是标准的数字: $0是程序名, $1是第一个参数, $2是第二个参数... #!/bin/bash # using one command line parameter fa ...

  8. mysql 主主复制搭建用的命令

    # mysql 容器的启动docker run -d -p 3306:3306 -v /database_files/products/data:/var/lib/mysql -v /database ...

  9. The current identity (NT AUTHORITY/NETWORK SERVICE)

    IIS错误提示: The current identity (NT AUTHORITY/NETWORK SERVICE) does not have write access to 'C:/WINDO ...

  10. Jquery客户端校验——jquery.validate.js

    jQuery Validate 插件为表单提供了强大的验证功能,让客户端表单验证变得更简单,同时提供了大量的定制选项,满足应用程序各种需求.该插件捆绑了一套有用的验证方法,包括 URL 和电子邮件验证 ...