KNN算法识别手写数字

一,MNIST数据集

MNIST 数据集来自美国国家标准与技术研究所National Institute of Standards and Technology (NIST) 训练集 (training set) 由来自 250 个不同人手写的数字构成, 其中 50% 是高中学生, 50% 来自人口普查局 (the Census Bureau) 的工作人员测试集(test set) 也是同样比例的手写数字数据

MNIST数据集由四部分组成,如图3.1所示,分别是训练图片集,训练标签集,测试图片集,测试标签集。官网下载仅仅是压缩文件,下载并解压就是二进制文件,通过编程读取二进制文件的内容如图所示。

           

图 MNIST组成部分

        

图MNIST二进制文件格式

3.2 训练图片集

训练图片集的二进制文件解说如图3.3所示, 可以看出在train-images.idx3-ubyte中,第一个数为32位的整数(魔数,图片类型的数),第二个数为32位的整数(图片的张数为60000),第三和第四个也是32为的整数(分别代表图片的行数和列数,都是28),接下来的都是一个字节的无符号数(即像素值,值域为0~255),因此,我们只需要依次获取魔数和图片的个数,然后获取图片的长和宽,最后逐个像素读取就可以了。在MINIST数据集中,一张图片的大小为28*28,那么每784个字节就是一张图片。利用Python解析后,读取的前20张图片如图所示。

           

图  训练图片集数据格式分布

     

图 训练图片集中的部分图片

 训练标签集

训练标签集的二进制文件解说如图3.5所示,可以看出在train-labels.idx1-ubyte中,第一个数为32位的整数(魔数,图片类型的数),第二个数为32位的整数(图片的张数为60000),接下来都是一个字节的无符号数,表示每张图片对应的数字,范围是0-9,并且与训练图片集的图片是一一对应的关系。

图 训练标签集数据格式分布

测试图片集和测试标签集和训练集的数据结构是一样的。

二,利用MNIST测试KNN算法

1,将矩阵test_image中的每一行像素值与train_image的所有行的像素值进行计算,并对结果排序,得出前K个中比例最多的label,那么这张图片的label就确定。以此计算出test_image中所有图片的label矩阵。

2,将求出的label与实际的test_label进行对比,计算出准确度。

import numpy as np
import struct
import cv2 as cv
from KNN import KNNClassifier
from module_selection import train_test_split

#  1,打开文件
with open("D:\Pycharm\MNIST\\t10k-images.idx3-ubyte",'rb') as image_f:
    buf_test_image = image_f.read()
with open("D:\Pycharm\MNIST\\t10k-labels.idx1-ubyte",'rb') as label_f:
    buf_test_label = label_f.read()
with open("D:\Pycharm\MNIST\\train-images.idx3-ubyte","rb") as train_image_f:
    buf_train_image = train_image_f.read()
with open("D:\Pycharm\MNIST\\train-labels.idx1-ubyte","rb") as train_label_f:
    buf_train_label = train_label_f.read()


#2,设置索引值,并指向文件的初始端
index_train_image = 0
index_train_label = 0
index_test_image = 0
index_test_label = 0

#3,读取image和label文件的注释信息,并将相应文件的指针索引向后移动。
magic_train_image, train_numImages, train_numRows, train_numColumns = struct.unpack_from('>IIII', buf_train_image, index_train_image)
magic_train_label,train_labels = struct.unpack_from('>II', buf_train_label, index_train_label)
magic_test_image, test_numImages, test_numRows, test_numColumns = struct.unpack_from('>IIII', buf_test_image, index_test_image)
magic_test_label,test_labels = struct.unpack_from('>II', buf_test_label, index_test_label)

index_train_image += struct.calcsize('>IIII')
index_train_label += struct.calcsize('>II')
index_test_image += struct.calcsize('>IIII')
index_test_label += struct.calcsize('>II')


# 3,读取图片存储值,并转换成矩阵
data_train_image = []
data_train_label = []
data_test_label = []
data_test_image = []

for i in range(test_numImages):
    write_test_label = int(struct.unpack_from('>B', buf_test_label, index_test_label)[0])
    index_test_label += struct.calcsize('>B')
    data_test_label.append(write_test_label)
    for j in range(784):
        if(int((struct.unpack_from('>B', buf_test_image, index_test_image)[0])) > 150):
            piexl = 1
        else:
            piexl = 0
        data_test_image.append(piexl)
        index_test_image += struct.calcsize('>B')

for x in range(train_numImages):
    write_train_label = int(struct.unpack_from('>B', buf_train_label, index_train_label)[0])
    index_train_label += struct.calcsize('>B')
    data_train_label.append(write_train_label)
    for y in range(784):
        if(int((struct.unpack_from('>B', buf_train_image, index_train_image)[0])) > 150):
            piexl = 1
        else:
            piexl = 0
        data_train_image.append(piexl)
        index_train_image += struct.calcsize('>B')
data_train_image =np.array(data_train_image)
data_train_label =np.array(data_train_label)
data_test_label = np.array(data_test_label)
data_test_image = np.array(data_test_image)
data_test_image = data_test_image.reshape(test_numImages,784)
data_train_image = data_train_image.reshape(train_numImages,784)





# 测试KNN算法的准确度
for i in range (5,10):
    clf = KNNClassifier(k = i)
    clf.fit(data_train_image,data_train_label)
    label_predict = clf.predict(data_test_image)
    print((sum(label_predict == data_test_label)) / len(data_test_label))

其中KNN函数是已经写好的,可以参照之前的博客。

三,测试实际手写数字的图片

1,将图片转换成28*28的大小,并将一张RGB的图片转换成灰度图像。

2,将灰度图像二值化。这样得到的像素值只有0和1。 3,将二值化图片转换成矩阵,矩阵的大小是1*784,方便进行计算。

# predict = []
# for i in range(10):
#     test_image = cv.imread("D:\\Python\\test\\" + str(i) + ".png")
#     gray = cv.cvtColor(test_image,cv.COLOR_BGR2GRAY)
#     ret, binary = cv.threshold(gray, 100, 255, cv.THRESH_BINARY_INV)
#     for x in range(28):
#         for y in range(28):
#             if binary[x,y] == 255:
#                 binary[x,y] = 1
#             else:
#                 binary[x,y] = 0
#     predict.append(binary)
# predict = np.array(predict).reshape(10,784)

# X_train,y_train,X_test,y_test = train_test_split(data_image,data_label)
# clf = KNNClassifier(k = 8)
# # clf.fit(X_train,y_train)
# clf.fit(data_test_image,data_test_label)
# y_predict = clf.predict(predict)
# print("图片的数字是:%s "%(y_predict))

 

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值