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


Posted in Python onMarch 23, 2020

写在前面

这一段的内容可以说是最难的一部分之一了,因为是识别图像,所以涉及到的算法会相比之前的来说比较困难,所以我尽量会讲得清楚一点。

而且因为在编写的过程中,把前面的一些逻辑也修改了一些,将其变得更完善了,所以一切以本篇的为准。当然,如果想要直接看代码,代码全部放在我的GitHub中,所以这篇文章主要负责讲解,如需代码请自行前往GitHub。

本次大纲

上一次写到了数据库的建立,我们能够实时的将更新的训练图片存入CSV文件中。所以这次继续往下走,该轮到识别图片的内容了。

首先我们需要从文件夹中提取出需要被识别的图片test.png,并且把它经过与训练图片相同的处理得到1x10000大小的向量。因为两者之间存在微小的差异,我也不是很想再往源代码之中增加逻辑了,所以我就直接把增加待识别图片的函数重新写一个命名为GetTestPicture,内容与GetTrainPicture类似,只不过少了“增加图片名称”这一个部分。

之后我们就可以开始进行正式图片识别内容了。

主要是计算待识别图片与所有训练图片的距离。当两个图片距离越近的时候,说明他们越相似,那么他们很有可能写的就是同一个数。所以利用这个原理,我们可以找出距离待识别图像最近的几个训练图片,并输出他们的数字分别是几。比如说我想输出前三个,前三个分别是3,3,9,那就说明这个待识别图片很有可能是3.

之后还可以对每一个位置加个权重,具体的就放在下一次再讲,本节内容已经够多了。

(第一篇文章之中我说过利用图片洞数检测。我尝试了一下,认为有些不妥,具体原因放在本文末。)

MAIN代码

所以直接把主要代码放上来,逻辑相对来说还是比较清晰的

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类,分别代表十个数字,那么被识别数字靠近哪一个类,那说明它有可能属于这一个类。

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

以上是第一篇文章中的内容,下面我着重讲一下数学方面的内容。

考虑到某些地方不能够输入数学公式(或不方便输入),我还是把这一段内容贴成图片出来。

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

之后直接挑出前几个离被识别图片最近的向量数字,基本上这几个数字就是被识别图片的数字了。但这样做未免有些简单,所以下一篇文章我会再深入一下,这张先讲计算距离的内容。

主代码

下面的代码中文件夹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函数,代表识别图片所用到的算法。

函数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)

函数CalculateDistance

函数中我导入了四个参数:被识别向量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

首先建立一个行数为test内被识别向量数量,列数为2*n的矩阵,每一行前n个放距离,后n个放数字。之后针对每一个被识别向量进行循环。

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

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

这一行代码就是上文中的算法过程,我个人觉得还是比较复杂的,可以详细的拆开看一下,我这里不细讲了。下面的内容就是开始排序并且找到距离最近的前几个向量。

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

这样子就相当于完成了所有内容,返回dis即可。

实际测试

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

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

所以我又写了一个数字作为待识别图像,通过程序运行以后,我们的以直接输出前十个最相似的向量:

第1个向量为2.0,距离为33.62347223932534
第2个向量为2.0,距离为35.64182105224185
第3个向量为2.0,距离为38.69663119274146
第4个向量为2.0,距离为43.52904133387693
第5个向量为2.0,距离为43.69029199677604
第6个向量为1.0,距离为43.730883339256714
第7个向量为6.0,距离为44.94800943845918
第8个向量为2.0,距离为45.033283944455924
第9个向量为4.0,距离为45.43926712996951
第10个向量为7.0,距离为45.64893989116544

之后我又依次从1-9试了一遍,我自己手写的数字全部识别正确,可以看出准确率还是挺高的。所以做到这一步相当于已经完成度很高了。

所以我就试了一下从网上找的图片,发现几乎没有正确的了。说明我们的数据库还是太小,只认得我的字体。不过话说这样,也可以做一个字体识别的程序。

所以如果要提高准确率,那么扩大图库是必须的。这一次就到这里。

总结

所有源代码我都放在了我的GitHub中,如果有兴趣的话可以去看看。

到这里就相当于算法内容写完了,比较简单,只用了一个类似于K最近邻的算法。

下一篇文章将会讲一个给前n个排名加权的想法,这样来提高准确度。

所以这一次就先到这里为止,谢谢。

如果喜欢的话,麻烦点一个喜欢和关注一下噢,谢谢~

本文已被收录到专题《python图片处理操作》 ,欢迎大家点击学习更多精彩内容。

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

Python 相关文章推荐
Python自定义函数的创建、调用和函数的参数详解
Mar 11 Python
Python3实现生成随机密码的方法
Aug 23 Python
Python pickle模块用法实例分析
May 27 Python
python rsa 加密解密
Mar 20 Python
pyqt 实现QlineEdit 输入密码显示成圆点的方法
Jun 24 Python
python读取图片的方式,以及将图片以三维数组的形式输出方法
Jul 03 Python
对python中的*args与**kwgs的含义与作用详解
Aug 28 Python
Python模块汇总(常用第三方库)
Oct 07 Python
Pytorch 实现focal_loss 多类别和二分类示例
Jan 14 Python
python3发送request请求及查看返回结果实例
Apr 30 Python
python 使用raw socket进行TCP SYN扫描实例
May 05 Python
python垃圾回收机制原理分析
Apr 13 Python
Python实现简易版的Web服务器(推荐)
Jan 29 #Python
python实现图像识别功能
Jan 29 #Python
Python使用正则表达式获取网页中所需要的信息
Jan 29 #Python
python实现K最近邻算法
Jan 29 #Python
python简单实现操作Mysql数据库
Jan 29 #Python
Django框架教程之正则表达式URL误区详解
Jan 28 #Python
python通过百度地图API获取某地址的经纬度详解
Jan 28 #Python
You might like
php在线解压ZIP文件的方法
2014/12/30 PHP
详解Window7 下开发php扩展
2015/12/31 PHP
php下载文件,添加响应头的简单实例
2016/09/22 PHP
PHP面向对象之领域模型+数据映射器实例(分析)
2017/06/21 PHP
利用PHP判断是手机移动端还是PC端访问的函数示例
2017/12/14 PHP
javascript prototype,executing,context,closure
2008/12/24 Javascript
javascript xml为数据源的下拉框控件
2009/07/07 Javascript
html+javascript实现可拖动可提交的弹出层对话框效果
2013/08/05 Javascript
跨域传值即主页面与iframe之间互相传值
2013/12/09 Javascript
js获取字符串字节数方法小结
2015/06/09 Javascript
深入理解jquery跨域请求方法
2016/05/18 Javascript
JS组件系列之使用HTML标签的data属性初始化JS组件
2016/09/14 Javascript
jquery 动态增加删除行的简单实例(推荐)
2016/10/12 Javascript
js实现可输入可选择的select下拉框
2016/12/21 Javascript
微信小程序中子页面向父页面传值实例详解
2017/03/20 Javascript
JS实现图片点击后出现模态框效果
2017/05/03 Javascript
理解Koa2中的async&await的用法
2018/02/05 Javascript
javascript中join方法实例讲解
2019/02/21 Javascript
layui table设置某一行的字体颜色方法
2019/09/05 Javascript
使用Promise封装小程序wx.request的实现方法
2019/11/13 Javascript
JS内置对象和Math对象知识点详解
2020/04/03 Javascript
Vue中使用wangeditor富文本编辑的问题
2021/02/07 Vue.js
[13:18]《一刀刀一天》之DOTA全时刻21:详解TI新赛制 A队再露獠牙
2014/06/24 DOTA
[42:56]VGJ.S vs Serenity 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
[35:39]完美世界DOTA2联赛PWL S2 FTD.C vs Rebirth 第二场 11.22
2020/11/24 DOTA
python获得一个月有多少天的方法
2015/06/04 Python
np.dot()函数的用法详解
2020/01/17 Python
Python字符串对齐、删除字符串不需要的内容以及格式化打印字符
2021/01/23 Python
俄罗斯药房连锁店:ASNA
2020/06/20 全球购物
论文指导教师评语
2014/04/28 职场文书
局火灾防控工作方案
2014/05/25 职场文书
七一讲话心得体会
2014/09/05 职场文书
求职自我评价范文100字
2014/09/23 职场文书
学院党的群众路线教育实践活动整改方案
2014/10/04 职场文书
求职自荐信范文(优秀篇)
2015/03/27 职场文书
MySQL 8.0 Online DDL快速加列的相关总结
2021/06/02 MySQL