KNN实现0-9数字手写板识别

通过Knn算法来识别手写的0-9的数字图片

1. 首先把 .png格式的图片处理成标准化后的数组矩阵

  • 处理思路:
    需要用导pllow库下的Image类。通过getpixel()
    方法可以 提取图片中像素的色彩RGB值。
    比如:(0,0,0)=黑色,(255,255,255)=白色

编写图片转换

# png  :为存储32x32的图片集
#txt :为存储每张图片标准化后的矩阵集

pngpath = './png/' #存放手写提数字图片
txtpath = './txt/' #保存转换后的数字矩阵文档

def png2txt(pngpath,txtpath):
    '''将固定尺寸的手写体图片转换成0,1数组矩阵文件'''
    pnglist = listdir(pngpath)
    for i in pnglist:
        fname = i.split(".")[0]
        im = Image.open(pngpath+"/"+i)
        fh = open(txtpath+"/"+fname+".txt","a")
        for m in range(0,32):  #像素高度
            for n in range(0,32): #像素宽度
                pix = im.getpixel((n,m))  #获取该图片的每个RGB像素点
                pixs = pix[0]+pix[1]+pix[2]  
                if pixs==0:
                    fh.write("1")   #若该像素点RGB为0的话,打印1
                else:
                    fh.write("0")    #该像素点不为0,即打印0
            fh.write("\n")
        fh.close()

注释:因为实现代码后,朋友问起RGB该问题。我觉得对于我这种新手还是解释一下为妙。也为查寻该资料的同行者少走弯路。

 im = Image.open(pngpath+"/"+i)   #这里是获取一张图片

如该行代码获取 一张显示为 9 的图
在这里插入图片描述

pix = im.getpixel((n,m))  #获取该图片的每个RGB像素点

如我们通过遍历获取到该图片坐标(0,0)的位置
该位置为白色,则:(R,G,B) = (255,255,255)
在这里插入图片描述
因为该图片是黑白组成,则可打印出一个由 0,1组成的32 × 32的标准化矩阵。
在这里插入图片描述

2. 划分训练集和测试集

  • 将 txt 文件下的 每个数字的15号文档提取出来放入testdata
  • 剩余的都移动到traindata
  • 亦可以随自己意愿任意提取测试文档。
trainpath = './traindata/'
testpath = './testdata/'

#提取训练集和测试集
def shutildata():
    """将后缀为15的文件分拣出来作为测试集
        其他文件作为训练集
    """
    txt_list = listdir(txtpath)
    for i in txt_list:
          if(i.split('.')[0].split('_')[1]=='15'):
               shutil.move(txtpath+'/'+i,testpath)
           else:
               shutil.move(txtpath +'/'+ i, trainpath)

3.加载数据

def data2array(fname):
'''读取0,1组成的矩阵数据,把矩阵存放入列表中'''
    arr = []
    fh = open(fname)
    for i in range(0,32):
        thisline = fh.readline()   
        for j in range(0,32):
            arr.append(int(thisline[j]))  #
    return arr

4.建立训练集数据及测试集数据

def traindata():
'''建立训练数据'''
    labels = [] #建空列表存放标签
    trainfile = listdir(trainpath) #获取训练集文件夹下的所有文件名

    #先建立一个行数为训练样本数,列数为1024的0数组矩阵,1024为图片像素总和,即32*32。
    trainarr = np.zeros((len(trainfile),1024))
    #提取文件名的第一个数字为标签名
    for i in range(0,len(trainfile)):
        thislabel = trainfile[i].split(".")[0].split("_")[0]
        if len(thislabel)!=0: 
            labels.append(int(thislabel)) #保存标签
            # 将所有traindata文件下的标准化矩阵铺平组成了200x1024 大矩阵
        trainarr[i,:] = data2array(trainpath+trainfile[i]) 
    return trainarr,labels

5.KNN算法实现

  • K值:选择距离最近的k个邻居。
  • 距离计算:这里使用的是欧式距离
    L 2 ( x i , y j ) = ( l = 1 n x i l x j l 2 ) 1 / 2 L_2(x_i,y_j)=(\sum^n_{l=1}|x^l_i - x^l_j|^2)^{1/2}
  • 分类标签:文本的分类标签即0-9这10个数字
def knn(k,testdata,traindata,labels):

    traindatasize = traindata.shape[0] #获取训练集长度
   
    #因为测试样本和训练集差异,需要扩展至与训练集相同(欧式距离)
    #testdata 沿着Y轴复制200次:np.tile(data(Y,X))
    dif = np.tile(testdata,(traindatasize,1)) - traindata
    #计算距离
    sqrdif = dif**2 
    sumsqdif = sqrdif.sum(axis=1)  #按行求平方和
    dsitance = sumsqdif**0.5
    sorted_distance = dsitance.argsort()    #返回按元素值从小到大排序,并返回元素的下标 len = 200

    count = {} #存放投票结果
    for i in range(0,k):  
        vote = labels[sorted_distance[i]]#提取索引多对应的标签值作为字典
        count[vote] = count.get(vote,0) + 1
 
    sorted_count = sorted(count.items(),key=lambda x:x[1],reverse=True)  #按V值排序
    return sorted_count[0][0]

6.测试数据

def datatest():
    trainarr,labels = traindata()
    testfiles = listdir(testpath)
    for i in range(0,len(testfiles)):
        testpicname = testfiles[i].split("_")[0]
        testarr = data2array(testpath+testfiles[i])
        result = knn(2,testarr,trainarr,labels)
        print("真正数字:"+testpicname+"  "+"测试结果为:{}".format(result))

0-9数字识别 KNN原理

即测试集的单集(1,1024)减去训练集的全集(200,1024)的每一行。共减200次。再这200行中,把最小值的 index 根据 k 的个数进行提取。再通过 该下标提取训练集的标签(即全集与之对应的行下标)

摘自知乎https://zhuanlan.zhihu.com/p/51326751 (python数据分析入门)。

发布了3 篇原创文章 · 获赞 2 · 访问量 100

猜你喜欢

转载自blog.csdn.net/weixin_41668848/article/details/104864472
今日推荐