网页采集器的自动识别算法( 2020年03月23日15:55:59python实现识别手写数字)

优采云 发布时间: 2022-01-23 18:18

  网页采集器的自动识别算法(

2020年03月23日15:55:59python实现识别手写数字)

  python实现手写数字识别 python图像识别算法

  更新时间:2020-03-23 15:55:59 作者:Hanpu_Liang

  本文文章主要详细介绍python识别手写数字的实现,python图像识别算法,有一定的参考价值,感兴趣的朋友可以参考一下

  写在前面

  这一段的内容可以说是最难的部分之一。因为是识别图像,涉及到的算法会比上一个难度更大,所以我尽量说清楚。

  并且因为在写的过程中,对之前的一些逻辑也进行了修改和完善,所以一切以本文为准。当然,如果你想直接看代码,代码都放在我的GitHub上,所以这个文章主要负责讲解,如果需要代码,请自行去GitHub。

  这个大纲

  上次我写了关于建立数据库的文章,我们能够将更新的训练图像实时存储在 CSV 文件中。所以这次继续往下看,就到了识别图片内容的时候了。

  首先,我们需要从文件夹中提取出要识别的图片test.png,和训练图片一样的处理,得到一个1x10000的向量。因为两者有细微的差别,我并不想在源码中添加逻辑,所以直接重写了添加待识别图片的函数,命名为GetTestPicture。内容与GetTrainPicture类似,但缺少“添加图片名称”部分。

  之后,我们就可以开始正式的图像识别内容了。

  主要目的是计算待识别图像与所有训练图像之间的距离。当两张图片更接近时,意味着它们更相似,因此它们很可能会写相同的数字。所以利用这个原理,我们可以找出最接近待识别图像的训练图像,并输出它们的数量。比如我要输出前三个,而前三个分别是3、3、9,则表示要识别的图像很可能是3.

  之后,还可以给每个位置加一个权重,细节下次再说。本节内容足够。

  (在第一篇文章中,我提到了使用图片孔数来检测,我试过了,觉得有点不合适,具体原因在文末。)

  主要代码

  所以直接放主代码,逻辑比较清晰

  

import os

import OperatePicture as OP

import OperateDatabase as OD

import PictureAlgorithm as PA

import csv

##Essential vavriable 基础变量

#Standard size 标准大小

N = 100

#Gray threshold 灰度阈值

color = 200/255

n = 10

#读取原CSV文件

reader = list(csv.reader(open('Database.csv', encoding = 'utf-8')))

#清除读取后的第一个空行

del reader[0]

#读取num目录下的所有文件名

fileNames = os.listdir(r"./num/")

#对比fileNames与reader,得到新增的图片newFileNames

newFileNames = OD.NewFiles(fileNames, reader)

print('New pictures are: ', newFileNames)

#得到newFilesNames对应的矩阵

pic = OP.GetTrainPicture(newFileNames)

#将新增图片矩阵存入CSV中

OD.SaveToCSV(pic, newFileNames)

#将原数据库矩阵与新数据库矩阵合并

pic = OD.Combination(reader, pic)

#得到待识别图片

testFiles = os.listdir(r"./test/")

testPic = OP.GetTestPicture(testFiles)

#计算每一个待识别图片的可能分类

result = PA.CalculateResult(testPic, pic)

for item in result:

for i in range(n):

print('第'+str(i+1)+'个向量为'+str(item[i+n])+',距离为'+str(item[i]))

  与上一篇文章的内容相比,本文文章只增加了如下一段代码,即获取待识别图片的名称,获取待识别的图片向量,并计算分类。

  下面我们将重点介绍CalculateResult函数的内容,即识别图像的算法。

  算法内容

  一般算法

  我们在大纲里已经简单介绍过了,我就照搬一下,补充一些内容。

  假设我们在二维平面上有两个点 A=(1,1) 和 B=(5,5),我现在将另一个点 C=(2,2),那么,哪一个更接近C点?

  初中学过数学的都知道,肯定离A点比较近。所以换个说法,我们现在有A和B两个班,A班包括点(1,1) ,B类包括点(5,5),那么对于点(2,2),它可能属于哪个类别?

  因为这个点离A类的点有点近,所以很可能属于A类。这就是结论。那么对于3维空间,A类是点(1,1,1),B类是(5,5,5),那么对于点(2,2,2) 必须相同)属于 A 类。

  可以看出,我们以两点之间的距离作为判断属于哪个类别的标准。那么对于我们把图片拉进去的1xn维向量,投影到n维空间上其实就是一个点,所以我们把训练向量分成10个类别,分别代表十个数字,那么哪个类别是识别出来的数字close to,然后说明它可能属于这一类。

  那么我们这里可以假设对于识别出的向量,列出离他最近的前十个向量属于哪个类别,然后根据排名加上一个权重,计算一个值。这个值代表它可能属于哪个类,所以这就是我们得到的最终结果——识别出的手写数字图片的值。

  以上是第一个文章的内容,现在我重点讲数学的内容。

  考虑到有些地方不能输入数学公式(或者输入不方便),我还是把这一段贴图。

  

  然后直接挑出最接近识别图片的前几个向量。基本上,这些数字是识别图片的数字。但是这样做有点简单,所以在下一篇文章我会深入,这篇先讲计算距离。

  主要代码

  在下面的代码中,文件夹test用来存放要识别的图片,通过函数GetTestPicture得到图片向量,然后和训练图片pic一起放入计算距离的函数CalculateResult中计算距离在每个要识别的向量和所有其他图像向量之间。.

  

#得到待识别图片

testFiles = os.listdir(r"./test/")

testPic = OP.GetTestPicture(testFiles)

#计算每一个待识别图片的可能分类

result = PA.CalculateResult(testPic, pic)

for item in result:

for i in range(n):

print('第'+str(i+1)+'个向量为'+str(item[i+n])+',距离为'+str(item[i]))

  函数 CalculateResult 在文件 PictureAlgorithm.py 中。该文件收录两个函数:CalculateDistance 函数和CalculateResult 函数,代表用于识别图片的算法。

  函数计算结果

  这个函数的逻辑比较简单,没什么好说的。主要连接是计算距离的CalculateDistance 函数。

  

def CalculateResult(test, train):

'''计算待识别图片test的可能分类'''

#得到每个图片的前n相似图片

testDis = CalculateDistance(test[:,0:N**2], train[:,0:N**2], train[:,N**2], n)

#将testDis变成列表

tt = testDis.tolist()

#输出每一个待识别图片的所有前n个

for i in tt:

for j in i:

print(j)

  函数计算距离

  在函数中,我导入了四个参数:识别向量test,训练向量train,每个向量对应的训练向量所代表的数字num,以及我要导出的前n个最近的向量。

  

def CalculateDistance(test, train, num, n):

'''计算每个图片前n相似图片'''

#前n个放距离,后n个放数字

dis = np.zeros(2*n*len(test)).reshape(len(test), 2*n)

for i, item in enumerate(test):

#计算出每个训练图片与该待识别图片的距离

itemDis = np.sqrt(np.sum((item-train)**2, axis=1))

#对距离进行排序,找出前n个

sortDis = np.sort(itemDis)

dis[i, 0:n] = sortDis[0:n]

for j in range(n):

#找到前几个在原矩阵中的位置

maxPoint = list(itemDis).index(sortDis[j])

#找到num对应位置的数字,存入dis中

dis[i, j+n] = num[maxPoint]

return dis

  首先,创建一个矩阵,其行数为测试中识别的向量数,列数为 2*n。每行的前 n 是距离,最后 n 是数字。然后循环每个识别的向量。

  首先,直接计算每张训练图像与识别图像的距离,可以直接用一行代码表示

  itemDis = np.sqrt(np.sum((item-train)**2, axis=1))

  这行代码就是上面的算法过程。我个人认为是比较复杂的。你可以仔细看看。我不会在这里详细介绍。下面开始排序,找到最接近的前几个向量。

  这里的逻辑是:先排序,找到距离最小的前n个,存入矩阵。求原矩阵的前n个位置,求对应位置的num个数,存入dis的最后n个。

  这相当于完​​成了一切,只需返回dis即可。

  实际测试

  我手写了一些数字,如图所示。所以实际上我们的数据库还是比较小的。

  

  所以我写了另一个数字作为要识别的图像。运行完程序,我们直接输出前十个最相似的向量:

  第一个向量为2.0,距离为33.62347223932534

  第二个向量是2.0,距离是35.645

  第三个向量为2.0,距离为38.69663119274146

  第四个向量为2.0,距离为43.529

  第5个向量是2.0,距离是43.694

  第6个向量为1.0,距离为43.7314

  第7个向量为6.0,距离为44.948

  第8个向量为2.0,距离为45.5924

  第9个向量为4.0,距离为45.43926712996951

  第10个向量为7.0,距离为45.64893989116544

  之后,我又从 1 到 9 再试一次,我手写的数字都被正确识别了。可以看出,准确率还是挺高的。所以做了这一步就相当于完成度很高。

  于是我试了一下网上找的图片,发现几乎没有正确的。这意味着我们的数据库仍然太小,只能识别我的字体。不过话虽如此,你也可以做一个字体识别程序。

  所以如果你想提高准确率,那么扩展图库是必须的。这次就到这里了。

  总结

  我的 GitHub 里有全部源代码,有兴趣的可以去看看。

  这相当于完​​成了算法内容,比较简单,只使用了类似于K最近邻的算法。

  下一篇文章会讲一个对前n个排名进行加权提高准确率的思路。

  所以这次我就到这里了,谢谢。

  喜欢的话请点个赞关注一下,谢谢~

  本文已被收录收录在“python图像处理操作”专题中,欢迎大家点击了解更多精彩内容。

  以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持Scripting Home。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线