win10+Python3.7.3+OpenCV3.4.1入门学习(二十章 K近邻算法)————20.4 自定义函数手写数字识别

Python版本是Python3.7.3,OpenCV版本OpenCV3.4.1,开发环境为PyCharm

20.4 自定义函数手写数字识别

OpenCV提供了函数cv2.KNearest()用来实现K近邻算法,在OpenCV中可以直接调用该函数。为了进一步了解K近邻算法及其实现方式,本节首先使用Python和OpenCV实现一个识别手写数字的实例。
eg:编写程序,演示K近邻算法。
在本例中,0~9的每个数字都有10个特征值。例如,数字“0”的特征值如下图所示。为了便于描述,将所有这些用于判断分类的图像称为特征图像。

在这里插入图片描述

下面分步骤实现手写数字的识别。

1.数据初始化
对程序中要用到的数据进行初始化。涉及的数据主要有路径信息、图像大小、特征值数量、用来存储所有特征值的数据等。
本例中:
● 特征图像存储在当前路径的“image”文件夹下。
● 用于判断分类的特征值有100个(对应100幅特征图像)。
● 特征图像的行数(高度)、列数(宽度)可以通过程序读取。也可以在图像上单击鼠标右键后通过查找属性值来获取。这里采用设置好的特征图像集,每个特征图像都是高240行、宽240列。
根据上述已知条件,对要用到的数据初始化:

s=‘image\’ # 图像所在的路径
num=100 # 共有特征值的数量
row=240 # 特征图像的行数
col=240 # 特征图像的列数
a=np.zeros((num, row, col))    # a用来存储所有特征的值

2.读取特征图像
本步骤将所有的特征图像读入到a中。共有10个数字,每个数字有10个特征图像,采用嵌套循环语句完成读取。具体代码如下:

n=0 # n用来存储当前图像的编号。
for i in range(0,10):
    for j in range(1,11):
      a[n, :, :]=cv2.imread(s+str(i)+'\\'+str(i)+'-'+str(j)+'.bmp',0)
      n=n+1

3.提取特征图像的特征值
在提取特征值时,可以计算每个子块内黑色像素点的个数,也可以计算每个子块内白色像素点的个数。这里我们选择计算白色像素点(像素值为255)的个数。按照上述思路,图像映射到特征值的关系如下图所示。
在这里插入图片描述

这里需要注意,特征值的行和列的大小都是原图像的1/5。所以,在设计程序时,如果原始图像内位于(row, col)位置的像素点是白色,则要把对应特征值内位于(row/5, col/5)处的值加1。
代码如下:


feature=np.zeros((num,round(row/5),round(col/5))) #用来存储所有样本的特征值
#print(feature.shape)  #看看feature的shape长什么样子
#print(row)            #看看row的值,有多少个特征(100)个
for ni in range(0,num):
    for nr in range(0,row):
        for nc in range(0,col):
            if a[ni,nr,nc]==255:
                feature[ni,int(nr/5),int(nc/5)]+=1
f=feature   #简化变量名称

4.计算待识别图像的特征值
读取待识别图像,然后计算该图像的特征值。编写代码如下:

o=cv2.imread('image\\test\\5.bmp',0) #读取待测图像
#读取图像值
of=np.zeros((round(row/5),round(col/5))) #用来存储测试图像的特征值
for nr in range(0,row):
    for nc in range(0,col):
        if o[nr,nc]==255:
            of[int(nr/5),int(nc/5)]+=1

5.计算待识别图像与特征图像之间的距离
依次计算待识别图像与特征图像之间的距离。编写代码如下:

d=np.zeros(100)
for i in range(0,100):
    d[i]=np.sum((of-f[i,:,:])*(of-f[i,:,:]))

数组d通过依次计算待识别图像特征值of与数据集f中各个特征值的欧氏距离得到。数据集f中依次存储的是数字0~9的共计100个特征图像的特征值。所以,数组d中的索引号对应着各特征图像的编号。例如,d[mn]表示待识别图像与数字“m”的第n个特征图像的距离。数组d的索引与特征图像之间的对应关系如下表所示。

在这里插入图片描述
如果将索引号整除10,得到的值正好是其对应的特征图像上的数字。例如d[34]对应着待识别图像到数字“3”的第4个特征图像的欧式距离。而将34整除10,得到 int(34/10)=3,正好是其对应的特征图像上的数字。
确定了索引与特征图像的关系,下一步可以通过计算索引达到数字识别的目的。

6.获取k个最短距离及其索引
从计算得到的所有距离中,选取k个最短距离,并计算出这k个最短距离对应的索引。具体实现方式是:
● 每次找出最短的距离(最小值)及其索引(下标),然后将该最小值替换为最大值。
● 重复上述过程k次,得到k个最短距离对应的索引。
每次将最小值替换为最大值,是为了确保该最小值在下一次查找最小值的过程中不会再次被找到。例如,要在数字序列“11, 6, 3, 9”内依次找到从小到大的值。
● 第1次找到了最小值“3”,同时将“3”替换为“11”。此时,要查找的序列变为“11, 6, 11, 9”。
● 第2次查找最小值时,在序列“11, 6, 11, 9”内找到的最小值是数字“6”,同时将“6”替换为最大值“11”,得到序列“11,11,11,9”。
不断地重复上述过程,依次在第3次找到最小值“9”,在第4次找到最小值“11”。当然,在本例中查找的是数值,具体实现时查找的是索引值。
根据上述思路,编写代码如下:

d=d.tolist()
temp=[]
Inf = max(d)
#print(Inf)
k=7
for i in range(k):
    temp.append(d.index(min(d)))
    d[d.index(min(d))]=Inf

7.识别

根据计算出来的k个最小值的索引,结合表20-2就可以确定索引所对应的数字。具体实现方法是将索引值整除10,得到对应的数字。
例如,在k=11时,得到最小的11个值所对应的索引依次为:66、60、65、63、68、69、67、78、89、96、32。它们所对应的特征图像如下表所示。

在这里插入图片描述

这说明,当前待识别图像与数字“6”的第6个特征图像距离最近;接下来,距离最近的第2个特征图像是数字“6”的第0个特征图像(序号从0开始);以此类推,距离最近的第11个特征图像是数字“3”的第2个特征图像。
上述结果说明,与待识别图像距离最近的特征图像中,有7个是数字“6”的特征图像。所以,待识别图像是数字“6”。
下面讨论如何通过程序识别数字。已知将索引整除10,就能得到对应特征图像上的数字,因此对于上述索引整除10:
(66, 60, 65, 63, 68, 69, 67, 78, 89, 96, 32)整除10=(6, 6, 6, 6, 6, 6, 6, 7, 8, 9, 3)
为了叙述上的方便,将上述整除结果标记为dr,在dr中出现次数最多的数字,就是识别结果。对于上例,dr中“6”的个数最多,所以识别结果就是数字“6”。
这里我们借助索引判断一组数字中哪个数字出现的次数最多:
● 建立一个数组r,让其元素的初始值都是0。
● 依次从dr中取数字n,将数组r索引位置为n的值加1。例如,从dr中取到的第1个数字为“6”,将r[6]加上1;
从dr中取到第2个数字也为“6”,将r[6]加上1;以此类推,对于dr=[6, 6, 6, 6, 6, 6, 6, 7, 8, 9, 3],得到数组r的值为[0, 0, 0, 1, 0, 0, 7, 1, 1, 1]。
在数组r中:
● r[0]=0,表示在dr中不存在值为0的元素。
● r[3]=1,表示在dr中有1个“3”。
● r[6]=7,表示在dr中有7个“6”。
● r[7]=1,表示在dr中有1个“7”。
● r[8]=1,表示在dr中有1个“8”。
● r[9]=1,表示在dr中有1个“9”。
● r中其余为0的值,表示其对应的索引在dr中不存在。
根据上述思路,编写代码如下:

temp=[i/10 for i in temp]
#数组r用来存储结果,r[0]表示k近邻中0的个数,r[n]K近邻中n的个数
r=np.zeros(10)
for i in temp:
    r[int(i)]+=1
#print(r)
print('当前的数字可能为:'+str(np.argmax(r)))

上述过程是分步骤的分析结果,以下是全部源代码:

import cv2
import numpy as np
import matplotlib.pyplot as plt
#读取样本(特征)图像的值
s='image\\'  #图像所在路径
num=100 #共有样本数量
row=240 #每个数字图像的行数
col=240 #每个数字图像的列数
a=np.zeros((num,row,col)) #用来存储所有样本的数值
#print(a.shape)
n=0 #用来存储当前图像的编号。
for i in range(0,10):
    for j in range(1,11):
        a[n,:,:]=cv2.imread(s+str(i)+'\\'+str(i)+'-'+str(j)+'.bmp',0)
        n=n+1

#提取样本图像的特征
feature=np.zeros((num,round(row/5),round(col/5))) #用来存储所有样本的特征值
#print(feature.shape)  #看看feature的shape长什么样子
#print(row)            #看看row的值,有多少个特征(100)个

for ni in range(0,num):
    for nr in range(0,row):
        for nc in range(0,col):
            if a[ni,nr,nc]==255:
                feature[ni,int(nr/5),int(nc/5)]+=1
f=feature   #简化变量名称

#####计算当前待识别图像的特征值
o=cv2.imread('image\\test\\5.bmp',0) #读取待测图像
##读取图像值
of=np.zeros((round(row/5),round(col/5))) #用来存储测试图像的特征值
for nr in range(0,row):
    for nc in range(0,col):
        if o[nr,nc]==255:
            of[int(nr/5),int(nc/5)]+=1


###开始计算,数字识别,计算最近的times个数字是谁,判断结果
d=np.zeros(100)
for i in range(0,100):
    d[i]=np.sum((of-f[i,:,:])*(of-f[i,:,:]))
#print(d)
d=d.tolist()
temp=[]
Inf = max(d)
#print(Inf)
k=7
for i in range(k):
    temp.append(d.index(min(d)))
    d[d.index(min(d))]=Inf
#print(temp)   #看看都被识别为哪些特征值了。

 
temp=[i/10 for i in temp]
#也可以返回去,处理为array,使用函数处理,意思差不多。
#temp=np.array(temp)
#temp=np.trunc(temp/10)
#print(temp)
#数组r用来存储结果,r[0]表示k近邻中0的个数,r[n]K近邻中n的个数
r=np.zeros(10)
for i in temp:
    r[int(i)]+=1
#print(r)
print('当前的数字可能为:'+str(np.argmax(r)))

算法准确度不够,测试照片中输入“7”,预测结果是“1”;输入“9”,预测结果是“7”

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
手写数字识别是深度学习的一个常见任务。在这个任务,我们使用深度神经网络(DNN)或LeNet模型来对手写数字进行识别。我们使用经典的手写数字识别数据集MNIST,该数据集包含60000个训练样本和10000个测试样本。每个样本都是一个28x28像素的像,对应着0到9这10个数字的标签。\[2\] 在实验,我们首先需要准备工作,包括设备和库的版本。例如,我们可以使用GTX1650显卡,tensorflow-gpu版本为2.4.0,keras版本为2.4.3,Python版本为3.7.3。然后,我们下载MNIST数据集作为我们的训练和测试数据。\[1\] 接下来,我们可以构建DNN模型或LeNet模型来进行手写数字识别实验。我们可以使用训练集对模型进行训练,并使用验证集进行模型的验证和调优。最后,我们可以使用测试集对模型进行评估。\[2\] 在实验过程,我们可以打印出传入网络的像尺寸,以确保数据集被正确传入网络。\[3\] 总结来说,手写数字识别是一个使用深度学习模型对手写数字进行自动识别的任务,我们可以使用DNN模型或LeNet模型,并使用MNIST数据集进行训练和测试。 #### 引用[.reference_title] - *1* *3* [【深度学习实战—1】:基于Keras的手写数字识别(非常详细、代码开源)](https://blog.csdn.net/qq_42856191/article/details/121420268)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [深度学习手写数字识别)](https://blog.csdn.net/weixin_65089713/article/details/123869254)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值