KNN实现手写字体的识别

1、KNN思想

KNN就是K最近邻,是一种分类算法,意思是选k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代表。在k个样本中,比重最大的那一类即可把目标归为这一类。

优点:不用训练

缺点:该算法在分类时有个主要的不足是,当样本不平衡时,K临近占比概率影响结果、计算量大

2、KNN如何实现手写字体的识别

①数据处理(图片处理为数字文本)

②待测图片与训练集每一张图片的向量做欧氏距离

③排序,选取最优K,使得结果最好

3、数据处理

①01文本转换图像

#coding:utf-8
import os
from PIL import Image
'''
①两个文件夹,一个存储数字文件、一个存储图像文件
②读取src文件夹下的文件名,统计个数
③src+文件名=每个数字txt的路径,读取其内容
④写入图片,保存图片
注意:
①目标文件夹只能是最后一层不存在,才能创建
②python于java/c的区别,路径分割/刚好相反
③数字文件为01序列
④putpixel((列,行))
'''
def fun(src,dst):
    #判断源文件夹是否存在,不存在结束
    if not os.path.exists(src):
        return
    # 判断目标文件夹是否存在,不存在创建一个
    if not os.path.exists(dst):
        os.mkdir(dst)
    #读取src文件中的文件名
    list=os.listdir(src)
    length=len(list)
    for i in range(length):
        #文件路径
        path=src+"/"+list[i];
        #读取文件内容
        read=open(path)
        #保存路径
        SavePath=dst+"/"+list[i][:-4]+".png"
        #写入图片,并保存,图片是32*32
        image =Image.new("L",(32,32))
        for j in range(32):
            line=read.readline()
            for k in range(32):
                bit=int(line[k])
                if bit ==1:
                    bit=255
                image.putpixel((k,j),bit)
        image.save(SavePath)
srcPath="C:/Users/Administrator/Desktop/src"
dstPath="C:/Users/Administrator/Desktop/dst"
fun(srcPath,dstPath)

②图片转换成01文本

#coding:utf-8
import os
from PIL import Image
import numpy as np
'''
Python图像处理库PIL的基本概念介绍”,我们知道PIL中有九种不同模式。
分别为1,L,P,RGB,RGBA,CMYK,YCbCr,I,F。
模式“1”为二值图像,非黑即白。但是它每个像素用8个bit表示,0表示黑,255表示白
模式“L”为灰色图像,它的每个像素用8个bit表示,0表示黑,255表示白,其他数字表示不同的灰度。
模式“P”为8位彩色图像,它的每个像素用8个bit表示,其对应的彩色值是按照调色板查询出来的。
'''
def fun(src,dst):
    if not os.path.exists(src):
        return
    if not os.path.exists(dst):
        os.mkdir(dst)
    list=os.listdir(src)
    length=len(list)
    for i in range(length):
        path=src+'/'+list[i]
        SavePath=dst+'/'+list[i][:-4]+".txt"
        read=Image.open(path).convert("1")          
        arr=np.asarray(read)
        np.savetxt(SavePath,arr,fmt="%d",delimiter='')    #保存格式为整数,没有间隔
        #np.savetxt(SavePath, arr,fmt="%d")
src="C:/Users/Administrator/Desktop/src"
dst="C:/Users/Administrator/Desktop/dst"
fun(src,dst)

4、具体实现

数据已经由图片处理为文本,且文本中像素点之间没有间隔。把每张图片处理为一个向量,32*32=1024。计算欧氏距离的时候也有技巧,不用遍历训练集一个一个与待测图片计算,可以利用np.title(),复制待测图片达到和训练集个数,直接矩阵相减。排序也有技巧,为了是每张图片和标签一一对应,排序的时候使用argsort(),统计众数的时候使用了字典,排序时候用sorted().

#coding:utf-8
import os
import numpy as np
import operator
'''
①难点:计算欧氏距离并排序,确定k值,这里k=3最优
②图片都处理为数字文本,文本中没有空格
③字典排序,排序后变为[(),()]形式
'''
#价值数据
def Load(src):
    if not os.path.exists(src):
        return
    list=os.listdir(src)
    length=len(list)
    label=[]
    train=[]
    for i in range(length):
        path=src+"/"+list[i]
        read=open(path)
        temp = []
        for j in range(32):
            line=read.readline()
            for k in range(32):
                bit=int(line[k])
                temp.append(bit)
        train.append(temp)
        label.append(int(list[i][0]))
    train=np.array(train)
    return train,label
def Classifier(train,laber,testPath,KK):
    list=os.listdir(testPath)
    length=len(list)
    errorCount=0
    for i in range(length):
        #数据处理
        path=testPath+"/"+list[i]
        #实际值
        ok=int(list[i][0])
        read=open(path)
        test=[]
        for j in range(32):
            line=read.readline()
            for k in range(32):
                bit=int(line[k])
                test.append(bit)
        #计算欧氏距离,不需要遍历,技巧
        m=train.shape[0]
        test=np.tile(test,(m,1))
        sum=train-test    #对应相减
        sum=sum**2       #平方
        sum=np.sum(sum,axis=1)  #行求和
        sum=sum**0.5     #开方
        # 排序,返回下标
        sum=np.argsort(sum)
        #前k个,取最大类
        ans={}
        for j in range(KK):
            lab=label[sum[j]]    #下标对应的标签
            if lab in ans.keys():
                ans[lab]=ans[lab]+1
            else:
                ans[lab] = 1
        ans=sorted(ans.items(),key=operator.itemgetter(1),reverse=True)
        print ("实际值=",ok,"预测值=",ans[0][0])
        if ok != ans[0][0]:
            errorCount += 1.0
    print("错误总数:%d" % errorCount)
    print("错误率:%f" % (errorCount / length))
trainPath="C:/Users/Administrator/Desktop/src"
testPath="C:/Users/Administrator/Desktop/dst"
#训练集处理
train,label=Load(trainPath)
#测试集处理
Classifier(train,label,testPath,3)
总结:

①文件夹判断是否存在?文件夹创建?文件夹下所有文件名的读取?文本读取?

②图像的创建?图像像素点的填充?图像的保存?图像读取?文本的写入?

③欧氏距离的计算?title()的使用?argsort()的使用?字典的排序sorted()?

④如何确定最优K?遍历K,针对每个k计算错误率。

def selectK():
    x = list()
    y = list()
    for i in range(1, 5):
        x.append(int(i))
        y.append(错误数)
    plt.plot(x, y)
    plt.show()
源码+数据下载

你可能感兴趣的:(KNN实现手写字体的识别)