在计算机视觉和机器学习领域,手写数字识别是一个经典的问题,广泛应用于各种实际场景,如邮政编码识别、银行支票处理等。KNN(K-Nearest Neighbors)算法因其简单易懂、无需复杂模型训练而被广泛应用于此类任务。本文将通过一个具体的案例,展示如何使用Python、OpenCV和实现KNN算法,并对手写数字进行识别和准确率评估。
一。数据集说明
digits.png
是一个包含多个手写数字的图像文件,每个数字占据图像的一个小区域。该图像文件通常用于训练和测试手写数字识别模型。图像中包含50行100列的数字,总共5000个数字样本,每个数字的大小为20x20像素。
代码实现
以下代码展示了如何使用OpenCV和KNN算法实现手写数字识别,并计算模型的准确率
import numpy as np
import cv2 #3.1本身就自带了机器学的函数 sklearn
img = cv2.imread('digits.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转换为灰度图
#将原始图像划分成独立的数字,每个数字大小20*20,共计5000个
cells = [np.hsplit(row,100) for row in np.vsplit(gray,50)]
# 装进array,形状(50,100,20,20),50行,100列,每个图像20*20大小
x = np.array(cells)
train = x[ : , :50]#划分为训练集和测试集:比例各占一半
test = x[:,50:100]
#将数据构造为符合KNN的输入,将每个数字的尺寸由20*20调整为1*400(一行400个像素)
train_new = train.reshape(-1,400).astype(np.float32)# Size = (2500,400)
test_new = test.reshape(-1,400).astype(np.float32)# Size = (2500,400)
#分配标签,分别为训练数据,测试数据分配标签(图像对应的实际值)
k = np.arange(10)#(0123456789)
labels = np.repeat(k,250)#重复数组中的元素,每个元素重复250次
train_labels = labels[:np.newaxis]#np.newaxis是NumPy库中的一个特殊对象,由于在数组中增加一个新的维度
test_labels = np.repeat(k,250)[:,np.newaxis]
#模型构建+训练,sklearn,knn,,opencv里面也有knn
knn = cv2.ml.KNearest_create()#通过cv2创建一个knn模型
knn.train(train_new,cv2.ml.ROW_SAMPLE, train_labels)#np.newaxis是NumPy库中的一个特殊对象,用于在数组中增加一个新的维度。
ret,result,neighbours,dist = knn.findNearest(test_new,k=1)
#ret: 表示查找操作是否成功
#result: 浮点数数组,表示测试样本的预测标签
#neighbours: 这是一个整数数组,表示与测试样本最近的k个邻居的索引
#dist: 这是一个浮点数数组,表示测试样本与每个最近邻居之间的距离
#通过测试集校验准确率
matches = result==test_labels
correct = np.count_nonzero(matches)
accuracy = correct*100.0/result.size
print( "当前使用KNN识别手写数字的准确率为{}%:".format(accuracy))
输出结果
运行上述代码后,您将看到类似以下的输出结果:
K值选择:
k
参数的值对模型性能有重要影响。通常需要通过交叉验证等方法进行优化。
k=2时,当前使用KNN识别手写数字的准确率为91.24%:
k=3时,当前使用KNN识别手写数字的准确率为91.64%:
二.对自己手写数字图像进行预测,数据处理
图像预处理:
-
对于自定义手写数字图像,需要确保图像大小为 20×20。
1.对自己手写数字图像进行第一次预测,数据处理
#对自己手写数字进行预测,数据处理
img = cv2.imread('4.png')
img1 = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转换为灰度图
# 将数据构造为符合KNN的输入,将每个数字的尺寸由20*20调整为1*400(一行400个像素)
mytest=img1.reshape(-1,400).astype(np.float32)
#对数据进行预测
ret,result1,neighbours,dist = knn.findNearest(mytest,k=1)
print('测试结果是',ret)
运行结果
2.对自己手写数字图像 第二次进行预测,数据处理
#对自己手写数字进行预测,数据处理
img = cv2.imread('7.png')
img1 = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转换为灰度图
# 将数据构造为符合KNN的输入,将每个数字的尺寸由20*20调整为1*400(一行400个像素)
mytest=img1.reshape(-1,400).astype(np.float32)
#对数据进行预测
ret,result1,neighbours,dist = knn.findNearest(mytest,k=1)
print('测试结果是',ret)
运行结果
3..对自己手写数字图像 第三次 进行预测,数据处理
#对自己手写数字进行预测,数据处理
img = cv2.imread('6.png')
img1 = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转换为灰度图
# 将数据构造为符合KNN的输入,将每个数字的尺寸由20*20调整为1*400(一行400个像素)
mytest=img1.reshape(-1,400).astype(np.float32)
#对数据进行预测
ret,result1,neighbours,dist = knn.findNearest(mytest,k=1)
print('测试结果是',ret)
运行结果
从以上测试结果可知,使用训练好的 KNN 模型对手写自定义图像进行预测,效果很差。
总结
通过上述代码,我们完成了以下任务:
-
加载手写数字图像并进行预处理。
-
将图像划分为训练集和测试集,并提取特征。
-
分配标签并训练 KNN 模型。
-
使用测试集评估模型的准确率。
-
对自定义手写数字图像进行预测。
这个过程展示了如何利用 OpenCV 和 KNN 算法实现简单的图像识别任务。虽然 KNN 是一种简单的方法,但它在数据集完整且预处理得当的情况下,仍然可以取得较好的效果。