机器学习之手写字识别(Knn算法应用)

手写字识别

对手写字体图片进行识别最重要的一点就是要将其转化为二值化(就是就是将图像上的像素点或灰度值设置为0或1,其呈现就是非黑即白)后的数据,然后再进行处理,在手写体处理中,二值化就是有手写笔画的部分用1表示,其余部分用0表示(当然也可以根据自己所写的算法进行调整)

手写字识别可以用很多种算法来计算,首先用Knn算法来实现:

  1. Knn算法进行手写数字的识别

    # -*- coding: utf-8 -*-
    # @Time    : 2021/7/19 20:30
    # @Author  : wcc
    # @FileName: HandwritingRecognition.py
    # @Software: PyCharm
    # @Blog    :https://blog.csdn.net/qq_41575517?spm=1000.2115.3001.5343
    
    import numpy as np
    from os import listdir
    import KnnAlog as Knn
    
    class HwRecognition:
    
        def __init__(self, dir_name):
            self.dirName = dir_name
    
        def pretreatment(self):
            # 读取目录下的所有文件的名称
            fileNameList = listdir(self.dirName)
            # 由于要用Knn算法进行处理,所以要将32*32的矩阵转化为1*1024的矩阵,此处先创建一个1*1024大小的0阵
            fileDataMat = np.zeros((1, 1024))
            # 判断目录中文件的个数
            m = len(fileNameList)
            # 创建一个列表用来保存标签字段
            labelSet = []
            # 把所有的1*1024行集中到一个文件中,变为一个m*1024的矩阵
            dataSet = np.zeros((m, 1024))
    
            for i in range(int(m)):
                # 由于目录中一共有m个文件,所以此处需要遍历循环m次来遍历所有文件
                fileNameStr = fileNameList[i]
                # 因为所有标签都在文件名称中隐含,所以此处直接用'_'切割字段,取出每个文件的标签
                label = fileNameStr.split('_')[0]
                # 将标签字段添加进标签集中
                labelSet.append(int(label))
    
                # 读文件,此处是读取'trainingDigits'/ + fileNameStr 处的文件
                fr = open('trainingDigits/%s'% fileNameStr)
                # 由于每一个文件都是32*32的文件,所以需要双层循环才能访问本文件的全部内容
                for j in range(32):
                    # 读取本行的数据并赋给linestr
                    lineStr = fr.readline()
                    for k in range(32):
                        # 将每一行的数据依次放入fileDataMat矩阵中,注意:双层循环结束之后fileDataMat中的数据是一个文件中的数据
                        fileDataMat[0, 32 * j + k] = int(lineStr[k])
                # 将本次循环访问的文件中的数据放入数据集的第i行
                dataSet[i, :] = fileDataMat
            labelSet = np.array(labelSet)
            return dataSet, labelSet
    
    
    
    
    if __name__ == '__main__':
        training_dir_name = 'trainingDigits'
        k = 3
        hw1 = HwRecognition(dir_name=training_dir_name)
        trainingSet, trainingLabelSet = hw1.pretreatment()
    
        test_dir_name = 'testDigits'
        hw1 = HwRecognition(dir_name=test_dir_name)
        testSet, testLabelSet = hw1.pretreatment()
    
        # 错误条数
        errorCount = 0
        # 错误记录
        errorRecords = {}
        # 错误值与正确值的比对
        correctRecords = {}
    
        for i in range(int(testSet.shape[0])):
            result = Knn.KnnAlog(testSet[i], trainingSet, trainingLabelSet, k).knn()
            if testLabelSet[i] != result:
                errorCount += 1
                errorRecords[i] = result
                correctRecords[i] = testLabelSet[i]
    
        print('错误个数:')
        print(errorCount)
        print('错误位置及错误值:')
        print(errorRecords)
        print('相应位置的正确值:')
        print(correctRecords)
        print("正确率:%f%%" % ((1-errorCount / int(testSet.shape[0]))*100))
    

    以上算法是根据已经提把手写字体的图片进行二值化并且生成32*32的数据文件后进行处理的,并不涉及二值化处理。

    对单个图片进行二值化处理并且进行knn算法识别的代码如下所示:

    # -*- coding: utf-8 -*-
    # @Time    : 2021/7/20 12:03
    # @Author  : wcc
    # @FileName: Binarization.py
    # @Software: PyCharm
    # @Blog    :https://blog.csdn.net/qq_41575517?spm=1000.2115.3001.5343
    
    import cv2
    import HandwritingRecognition as hw
    import KnnAlog as Knn
    
    image = cv2.imread("C:/Users/Administrator/Desktop/vocation/image/1_1.png")
    image2 = cv2.resize(image, (32, 32))
    gray = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)
    ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY)
    
    for i in range(32):
        for j in range(32):
            binary[i, j] = 255 - binary[i, j]
    binary = ~binary
    
    # cv2.imshow("binary", binary)
    # cv2.waitKey(0)
    cv2.imwrite("C:/Users/Administrator/Desktop/vocation/image/1_1.jpg", binary)
    
    test = []
    # 把二值化后的数据转化为测试数据
    for i in range(32):
        for j in range(32):
            if binary[i, j] == 255:
                test.append(0)
            else:
                test.append(1)
    
    training_dir_name = 'trainingDigits'
    k = 3
    trainingSet, trainingLabelSet = hw.HwRecognition(dir_name=training_dir_name).pretreatment()
    result = Knn.KnnAlog(test, trainingSet, trainingLabelSet, k).knn()
    
    print(result)
    

    上述代码中调用的Knn算法如下所示

import numpy as np
# 个模块是从Classify.py中抽离封装出来的

class KnnAlog:
    # inX:未知类型数据; trainSet:训练集;labels:训练集标签项(每个数据所属类型);k:样本所属范围
    def __init__(self, inX, trainSet, labels, k):
        self.inX = inX
        self.trainSet = trainSet
        self.labels = labels
        self.k = k

    def knn(self):
        # 此处sum()中的参数可以为0或者是1,若为0,则按列求和,若为1,则按行求和
        dist = (((self.inX - self.trainSet) ** 2).sum(1)) ** 0.5
        # argsort()函数是将x中的元素从小到大排列,提取其对应的index(索引),然后输出到y
        sortedDist = dist.argsort()

        # 定义一个字典,其作用是为了判断前k-1个样本中每个种类出现了几次
        classCount = {}
        for i in range(self.k):
            voteLable = self.labels[sortedDist[i]]
            # get()方法中第二个属性的意思是若关键字不存在于字典中,则返回0
            classCount[voteLable] = classCount.get(voteLable, 0) + 1

        # 在字典中寻找哪一类出现的次数最多
        maxType = 0
        maxCount = -1
        # 这种遍历方式是在字典中遍历的方式,直接用key和value取字典中的键值对即可
        for key, value in classCount.items():
            if value > maxCount:
                maxType = key
                maxCount = value
        return maxType

你可能感兴趣的:(机器学习笔记,python)