手写字识别
对手写字体图片进行识别最重要的一点就是要将其转化为二值化(就是就是将图像上的像素点或灰度值设置为0或1,其呈现就是非黑即白)后的数据,然后再进行处理,在手写体处理中,二值化就是有手写笔画的部分用1表示,其余部分用0表示(当然也可以根据自己所写的算法进行调整)
手写字识别可以用很多种算法来计算,首先用Knn算法来实现:
-
Knn算法进行手写数字的识别
# -*- coding: utf-8 -*- # @Time : 2021/7/19 20:30 # @Author : wcc # @FileName: HandwritingRecognition.py # @Software: PyCharm # @Blog :https://blog.youkuaiyun.com/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.youkuaiyun.com/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