基于模板匹配的手写数字识别

【实验项目名称】

手写数字特征提取方法与实现

【实验目的】

通过手写数字特征的提取,了解数字的特征提取方法,掌握特征匹配准则。

【实验原理】

读取标准化后的数字0~9,二值化,对每个数字进行等分区域分割,统计每个区域内的黑色像素点的个数,即为特征初值。采用欧式距离的模板匹配法判断数字。

【实验要求】

给定数字0-9的原始样本集合,每个数字都有100个大小为28*28的样本图像。要求如下:

1、将上述图像切分成标准图像库,存储为文件。

2、对每个数字进行等分区间分割。

3、给出统计结果:每个区域内的黑色像素点个数值以及占总量的百分比,显示出计算结果。

4、采用欧氏距离模板匹配法,给出识别结果。

5、从统计意义上,给出每个数字的识别率。


1.Python库的相关配置:OpenCV 

2.实验流程图:

3.实验步骤分析(包含有train图片集、test图片集):

  1.图片预处理,该实验使用图片均已做过预处理,均为二值化的图像(0 和 255),黑底白字,28*28大小,如下图所示;

                  

  2.对所有train图片进行数据压缩,设计为28*28->7*7,也就是,每一个小方块中含有4*4=16个像素点,通过统计小方块中的像素值,分别给小方块标记为0或1(其中当白点超过16/2 = 8 个时,记该小方块为1,反之,记为0。可以知道,每一张图片可以被49个0_1字符串刻画。

  3.对train图片集中所有图片进行上述处理,并将其字符串数据进行存储(可以设计为存储在一个txt文档,,称为模板库)。然后对test图片集中的每一张图片进行字符串转化,同样可以得到49个字符串的0_1数据,然后将其与模板库中的字符串数据进行对比,其中,欧氏距离最小的即认为是和该测试图片是同一类数字。以此分辨手写数字图片。

  4.关于各种统计率的计算:[正确率]--(最小距离唯一,且两个图片数字属于同一类)或者(存在多个最小距离,但是均属于同一类数字);

              [拒绝识别率]--(存在多个最小距离,并且不全部属于同一类数字,无法正常分类);

              [错误率]--(最小距离唯一,并且两个图片不属于同一类数字);

  5.为了更好地判断两个图片是否属于同一类数字,故一般在其49个字符数据前加上一些标记符号,用来表示该字符串属于哪个数字。

4.Python实现(其中路径绝对方式给出

one_test.py文件:(该文件中代码复杂主要在于三种识别率的计算,其中关于每类识别得统计判断有点繁杂,需耐心)

Function.Image_Compression(root_dir) -------图像压缩,返回压缩数据流

Function.Distance(test_str, train_str)--------计算样本间距

 1 # 基于模板的手写数字识别
 2 import os
 3 import cv2
 4 import Function     # 关于该实验中需要调用的函数
 5 # 1.样本特征,不需预处理
 6 # 2.图像压缩表示,28*28——7*7,存储于(E:PatternRecognitionpicture7_7.txt)
 7 root_dir = "E:/train-images"           # 训练数据集
 8 file7_7 = open("E:/PatternRecognition/picture7_7.txt", 'w')     # 覆盖写模式
 9 for fl in os.listdir(root_dir):      # 循环处理所有train图片
10     img_str = fl[0:-4] + ":" + Function.Image_Compression(root_dir + '/' + fl)      # 图像压缩,返回压缩数据流
11     file7_7.write(img_str + '
')      # 压缩后的图像数据写入文本存储
12 file7_7.close()
13 # 3.待测样本的相似性比较,根据最近距离判断
14 # 4.根据相似性比较给出识别结果,并给出统计意义上的正确率,错误率,拒绝识别率
15 file7_7 = open("E:/PatternRecognition/picture7_7.txt", 'r')     # 只读模式
16 root_dir = "E:/test-images"          # 测试test-images数据集
17 Correct_rate = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
18 Error_rate = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
19 Rejection_rate = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
20 ############
21 for fl in os.listdir(root_dir):      # 循环处理所有test图片
22     # 一些必备的基础数据变量
23     Same_dist_number = 0    # 用于记录最小距离时,是否存在多个标准样本,并标记个数
24     Same_class = -1         # 当有多个相同距离时,如果他们均为同一类别,则标记为该类别;-1表示可直接判断。
25     min_dist = 7            # 用于存储判断最小距离
26     dist_img = ""           # 用于标记当前最小距离时,属于哪个数字图片
27     # 开始处理test图片的匹配识别
28     test_img_str = Function.Image_Compression(root_dir + '/' + fl)      # test图片数据
29     while True:
30         line = file7_7.readline()
31         if not line:        # 已读完整个文档,光标返回开头,结束此次匹配
32             file7_7.seek(0)
33             break
34         train_str = line[-50:-1]        # train图片数据
35         temp_dist = Function.Distance(test_img_str, train_str)      # 计算样本间距
36         if temp_dist < min_dist:        # 更新min_dist/dist_img/Same_dist_number
37             min_dist = temp_dist
38             dist_img = line[0:-51]      # 提取最小距离的图片名称,即属于哪个数字
39             Same_dist_number = 0        # 出现最小距离,个数归零
40             Same_class = -1             # 出现最小距离,不需要类别判断
41         elif temp_dist == min_dist:
42             Same_dist_number += 1       # 表示具有相同距离的数字
43             if dist_img[0:1] == line[0:1]:      # 样本间距相等,同时是同一类的样本
44                 Same_class = eval(line[0:1])    # 记录同一类别
45             else:
46                 Same_class = -1         # 表明,同时具有不同类的数字样本与测试数字距离相等
47     # 识别结果 以及 识别结果的数据统计
48     # a.Same_dist_number = 0 ,表明可以直接识别出来,但不保证正确率
49     # b.Same_dist_number != 0 and Same_class = -1 ,拒绝识别,同时有不同数字与其距离相等
50     # c.Same_dist_number != 0 and Same_class ,可以识别,表示同一类数字中多个样本与其距离相等
51     if Same_dist_number == 0:           # 该数字可以识别
52         print("测试数字:", fl[0:-4], "  --  识别出来的结果:", dist_img)    # 数字的识别结果
53         if fl[0] == dist_img[0]:
54             Correct_rate[eval(fl[0])] += 1        # 正确识别
55         else:
56             Error_rate[eval(fl[0])] += 1          # 识别错误
57     elif Same_class == -1:              # 拒绝识别
58         print("测试数字:", fl[0:-4], "  --  该数字拒绝识别!")
59         Rejection_rate[eval(fl[0])] += 1      # 拒绝识别
60     else:                               # 同一类数字中多个样本与其距离相等
61         print("测试数字:", fl[0:-4], "  --  识别出来的结果(类):", Same_class)
62         if eval(fl[0]) == Same_class:
63             Correct_rate[eval(fl[0])] += 1  # 正确识别
64         else:
65             Error_rate[eval(fl[0])] += 1  # 识别错误
66 file7_7.close()
67 print("------------------------------------------------")
68 for i in range(10):
69     print("数字 {:d} 识别的正确率 = {:.2f}% ,错误率 = {:.2f}% ,拒绝识别率 = {:.2f}%".format(i, Correct_rate[i]*5, Error_rate[i]*5, Rejection_rate[i]*5))
70 print("success!")
View Code

  <<----------------------数据流显示

5.两个函数:

Function.py文件:(包含两个需要常调用的函数)

Image_Compression(img_path)

 1 import cv2
 2 
 3 #######################
 4 # 实现图像压缩,28*28——7*7,并以49数据流返回,img_path--图片路径
 5 # 划分为4*4的像素矩阵,其中八个及以上的像素点超过127即记为1,反之为0
 6 # 参数img_path,必须为完成的图片路径
 7 #######################
 8 def Image_Compression(img_path):
 9     # 数据按行存储
10     img_str = ""        # 存数据流
11     img = cv2.imread(img_path)
12     # print("图像的形状,返回一个图像的(行数,列数,通道数):", img.shape)
13     x = y = 0           # img像素点坐标表示img[x][y]
14     for k in range(1, 50):      # k的范围1-49
15         totle_img = 0           # 统计满足要求的像素点数目
16         for i in range(4):
17             for j in range(4):
18                 if img[x + i - 1][y + j - 1][0] > 127:
19                     totle_img += 1
20         y = (y + 4) % 28
21 # 一个矩形阵中包含16个像素点,其中像素值大于127的点超过八个记为1,反之记为0
22         if totle_img >= 8:
23             img_str += '1'
24         else:
25             img_str += '0'
26         if k % 7 == 0:      # 控制x,y的变化
27             x = x + 4
28             y = 0
29     return img_str
View Code

 Distance(test_str, train_str)

 1 #######################
 2 # 计算测试样本与标准样本之间的距离,返回以距离,test_str--测试,train_str--标准
 3 # 其中test_str,train_str均必须保证为49个字符串形式的数字
 4 # 返回一个double类型的数据
 5 #######################
 6 def Distance(test_str, train_str):
 7     len_str = len(train_str)        # 数据长度
 8     dist = 0.0
 9     for i in range(len_str):        # 计算距离
10         dist += (eval(test_str[i:i+1]) - eval(train_str[i:i+1]))**2
11     dist **= 0.5
12     return dist
View Code

6.1匹配结果:(test是从train里面提取出来的若干图片合集)

     

数字 0 识别的正确率 = 100.00% ,错误率 = 0.00% ,拒绝识别率 = 0.00%

数字 1 识别的正确率 = 45.00% ,错误率 = 0.00% ,拒绝识别率 = 55.00%

数字 2 识别的正确率 = 85.00% ,错误率 = 0.00% ,拒绝识别率 = 15.00%

数字 3 识别的正确率 = 80.00% ,错误率 = 0.00% ,拒绝识别率 = 20.00%

数字 4 识别的正确率 = 90.00% ,错误率 = 0.00% ,拒绝识别率 = 10.00%

数字 5 识别的正确率 = 80.00% ,错误率 = 0.00% ,拒绝识别率 = 20.00%

数字 6 识别的正确率 = 90.00% ,错误率 = 0.00% ,拒绝识别率 = 10.00%

数字 7 识别的正确率 = 95.00% ,错误率 = 0.00% ,拒绝识别率 = 5.00%

数字 8 识别的正确率 = 100.00% ,错误率 = 0.00% ,拒绝识别率 = 0.00%

数字 9 识别的正确率 = 85.00% ,错误率 = 0.00% ,拒绝识别率 = 15.00%

6.2匹配结果:(其他方式构建的图片)

 暂无

7.总结:

  实验可以通过特征压缩的方式来适当减少特征值的数量,然后再进行模板匹配,需要注意的是,特征值得压缩需要处于适当的范围。特征值过多会导致计算数据多大,匹配速度较慢,反之,特征值过少,对数据的判别存在较大的误差。总的来说,对于模板匹配识别方式,计算量较大,匹配速度较慢。

2021-04-29

原文地址:https://www.cnblogs.com/2015-16/p/14720111.html