opencv-进阶05 手写数字识别原理及示例

前面我们仅仅取了两个特征维度进行说明。在实际应用中,可能存在着更多特征维度需要计算。

下面以手写数字识别为例进行简单的介绍。

假设我们要让程序识别图 20-2 中上方的数字(当然,你一眼就知道是“8”,但是现在要让计算机识别出来)。识别的方式是,依次计算该数字图像(即写有数字的图像)与下方数字图像的距离,与哪个数字图像的距离最近(此时 k =1),就认为它与哪幅图像最像,从而确定这幅图像中的数字是多少。

在这里插入图片描述

下面分别从特征值提取和数字识别两方面展开介绍。

1. 特征值提取

步骤 1:我们把数字图像划分成很多小块,如图 20-3 所示。该图中每个数字被分成 5 行 4列,共计 5×4 = 20 个小块。此时,每个小块是由很多个像素点构成的。当然,也可以将每一个像素点理解为一个更小的子块。
为了叙述上的方便,将这些小块表示为 B(Bigger),将 B 内的像素点,记为 S(Smaller)。
因此,待识别的数字“8”的图像可以理解为:

  • 由 5 行 4 列,共计 5×4=20 个小块 B 构成。
  • 每个小块 B 内其实是由 M×N 个像素(更小块 S)构成的。为了描述上的方便,假设每个小块大小为 10×10 =100 个像素。

在这里插入图片描述
步骤 2:计算每个小块 B 内,有多少个黑色的像素点。或者这样说,计算每个小块 B 内有
多少个更小块 S 是黑色的。
仍以数字“8”的图像为例,其第 1 行中:

  • 第 1 个小块 B 共有 0 个像素点(更小块 S)是黑色的,记为 0。
  • 第 2 个小块 B 共有 28 个像素点(更小块 S)是黑色的,记为 28。
  • 第 3 个小块 B 共有 10 个像素点(更小块 S)是黑色的,记为 10。
  • 第 4 个小块 B 共有 0 个像素点(更小块 S)是黑色的,记为 0。

以此类推,计算出数字“8”的图像中每一个小块 B 中有多少个像素点是黑色的,如图 20-4 所示。我们观察后会发现,不同的数字图像中每个小块 B 内黑色像素点的数量是不一样的。正是这种不同,使我们能用该数量(每个小块 B 内黑色像素点的个数)作为特征来表示每一个数字。

在这里插入图片描述
步骤 3:有时,为了处理上的方便,我们会把得到的特征值排成一行(写为数组形式),如图 20-5 所示。

在这里插入图片描述
当然,在 Python 里完全没有必要这样做,因为 Python 可以非常方便地直接处理图 20-5 中上方数组(array)形式的数据。这里为了说明上的方便,仍将其特征值处理为一行数字的形式。

经过上述处理,数字“8”图像的特征值变为一行数字,如图 20-6 所示。

在这里插入图片描述
步骤 4:与数字“8”的图像类似,每个数字图像的特征值都可以用一行数字来表示。从某种意义上来说,这一行数字类似于我们的身份证号码,一般来说,具有唯一性。

按照同样的方式,获取每个数字图像的特征值,如图 20-7 所示。

在这里插入图片描述

2. 数字识别

数字识别要做的就是比较待识别图像与图像集中的哪个图像最近。这里,最近指的是二者之间的欧氏距离最短。

本例中为了便于说明和理解进行了简化,将原来下方的 10 个数字减少为 2 个(也即将分类从 10 个减少为 2 个)。

假设要识别的图像为图 20-8 中上方的数字“8”图像,需要判断该图像到底属于图 20-8 中下方的数字“8” 图像的分类还是数字“7”图像的分类。

在这里插入图片描述
步骤 1:提取特征值,分别提取待识别图像的特征值和特征图像的特征值。

为了说明和理解上的方便,将特征进行简化,每个数字图像只提取 4 个特征值(划分为 2×2 = 4 个子块 B),如图 20-9 所示。此时,提取到的特征值分别为:

  • 待识别的数字“8”图像:[3, 7, 8, 13]
  • 数字“8”特征图像:[3, 6, 9, 12]
  • 数字“7”特征图像:[8, 1, 2, 98]

在这里插入图片描述
步骤 2:计算距离。按照 20.1 节介绍的欧氏距离计算方法,计算待识别图像与特征图像之间的距离。

首先,计算待识别的数字“8”图像与下方的数字“8”特征图像之间的距离,如图 20-10所示。计算二者之间的距离:

在这里插入图片描述
接下来,计算待识别的数字“8”图像与数字“7”特征图像之间的距离,如图 20-11 所示。二者之间的距离为:

在这里插入图片描述
通过计算可知,待识别的数字“8”图像:

  • 与数字“8”特征图像的距离为根号3=1.732050807568877。
  • 与数字“7”特征图像的距离为根号7322=85.56868586112562。

步骤 3:识别。
根据计算的距离,待识别的数字“8”图像与数字“8”特征图像的距离更近。所以,将待识别的数字“8”图像识别为数字“8”特征图像所代表的数字“8”。

上面介绍的是 K 近邻算法只考虑最近的一个邻居的情况,相当于 K 近邻中 k =1 的情况。在实际操作中,为了提高可靠性,需要选用大量的特征值。例如,每个数字都选用不同的形态的手写体 100 个,对于 0 ~ 9 这 10
个数字,共需要 100×10 =1000 幅特征图像。在识别数字时, 分别计算待识别的数字图像与这些特征图像之间的距离。这时,可以将 k
调整为稍大的值,例如 k =11,然后看看其最近的 11 个邻居分属于哪些特征图像。

例如,其中:

  • 有 8 个属于数字“6”特征图像。
  • 有 2 个属于数字“8”特征图像。
  • 有 1 个属于数字“9”特征图像。
    通过判断,当前待识别的数字为数字“6”特征图像所代表的数字“6”。

自定义函数手写数字识别

在本例中,0~9 的每个数字都有 10 个特征值。例如,数字“0”的特征值如图 20-12 所示。
为了便于描述,将所有这些用于判断分类的图像称为特征图像。

在这里插入图片描述
下面分步骤实现手写数字的识别。

1. 数据初始化
对程序中要用到的数据进行初始化。涉及的数据主要有路径信息、图像大小、特征值数量、用来存储所有特征值的数据等。

本例中:

  • 特征图像存储在当前路径的“image_number”文件夹下。
  • 用于判断分类的特征值有 100 个(对应 100 幅特征图像)。
  • 特征图像的行数(高度)、列数(宽度)可以通过程序读取。也可以在图像上单击鼠标右键后通过查找属性值来获取。这里采用设置好的特征图像集,每个特征图像都是高240 行、宽 240 列。

根据上述已知条件,对要用到的数据初始化:

s='image_number\\' # 图像所在的路径
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)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小海聊智造

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值