对手写字体图片进行识别最重要的一点就是要将其转化为二值化(就是就是将图像上的像素点或灰度值设置为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.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