• (4) OpenCV图像处理kNN近邻算法-识别数字0和1


    目录

    一、识别数字0和1

            1. 识别数字0和1例程

            2.识别数字0和1运行效果

            3.识别数字0和1结果分析

    二、识别数字0~9

            1. 识别数字0~9例程

            2.识别数字0~9输出结果

            3.识别数字0~9结果分析

    三、扩展思路


    一、识别数字0和1

            我们的目标是构建一个可以识别手写数字的应用程序。为此,我们需要创建一个手写数字的图片文件 “ digits.png ”,图像的像素为:( 320*40 ), 其中包含 32个手写数字(每个数字16个),每个数字都是20x20的图像,如下图。

            因此,我们的第 1 步是将图像分割成 32 个不同的数字。对于每个数字,我们将其展平为400像素的一行。那就是我们的训练集,即所有像素的强度值。这是我们可以创建的最简单的功能集。我们将每个数字的前8个样本用作训练数据,然后将后8个样本用作测试数据

    1. 识别数字0和1例程

    1. import numpy as np # 导入numpy库,用于进行矩阵运算
    2. import cv2 as cv # 导入OpenCV库,用于图像处理
    3. img = cv.imread('digits.png') # 读取名为'digits.png'的图像
    4. gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) # 将图像转换为灰度图像
    5. # 现在我们将图像分割为32个单元格,每个单元格为20x20
    6. cells = [np.hsplit(row,16) for row in np.vsplit(gray,2)] # 将图像分割成2行16列的单元格,每个单元格为20x20像素
    7. # 使其成为一个Numpy数组。它的大小将是(2,16,20,20)
    8. x = np.array(cells) # 将分割后的图像转换为一个Numpy数组
    9. # 现在我们准备train_data和test_data。
    10. train = x[:,:8].reshape(-1,400).astype(np.float32) # 取数组的前50%作为训练数据,并将其形状转换为(16,400)的浮点数类型
    11. test = x[:,8:16].reshape(-1,400).astype(np.float32) # 取数组的后50%作为测试数据,并将其形状转换为(16,400)的浮点数类型
    12. # 为训练和测试数据创建标签
    13. k = np.arange(2) # 创建一个包含数字0到1的一维数组
    14. train_labels = np.repeat(k,8)[:,np.newaxis] # 将数组重复8次,得到一个(16,1)的二维数组,作为训练数据的标签
    15. test_labels = train_labels.copy() # 复制训练数据的标签,作为测试数据的标签
    16. # 初始化kNN,训练数据,然后使用k = 1的测试数据对其进行测试
    17. knn = cv.ml.KNearest_create() # 创建一个kNN分类器对象
    18. knn.train(train, cv.ml.ROW_SAMPLE, train_labels) # 使用训练数据和标签训练分类器
    19. ret,result,neighbours,dist = knn.findNearest(test,k=1) # 使用测试数据和k=1的参数调用分类器的findNearest方法,得到返回值、预测结果、最近邻样本和距离
    20. # 现在,我们检查分类的准确性
    21. #为此,将结果与test_labels进行比较,并检查哪个错误
    22. matches = result==test_labels # 将预测结果与测试标签进行比较,得到一个布尔类型的数组
    23. correct = np.count_nonzero(matches) # 统计布尔数组中非零元素的数量,即预测正确的数量
    24. accuracy = correct*100.0/result.size # 计算预测准确率,即正确预测的数量占总数量的比例
    25. print(accuracy) # 输出预测准确率
    26. # 打印预测结果。这是一个新样本的标签。
    27. print( "result: {}\n".format(result) )
    28. # 打印最近邻样本的索引。这是一个新样本的1个最近邻样本在训练数据集中的索引。
    29. print( "neighbours: {}\n".format(neighbours) )
    30. # 打印最近邻样本的距离。这是一个新样本与它的1个最近邻样本的距离。
    31. print( "distance: {}\n".format(dist) )

    2.识别数字0和1运行效果

    3.识别数字0和1结果分析

            我们通过获取result变量里面的值,确定1,2行的后8个样本图像被识别为数字几,来确定我们的准确率。通过下面我们可以看出,第1行后8个样本图像数字0,有2个被错误的识别为1,第2行后8个样本图像数字1,都被正确的识别为1。

    二、识别数字0~9

           上面的例程是识别0和1,只是为了更直观的进行演示,可以通过增加图像数据为 0~9 的手写图像数据,就可以识别全部的数字。而且自己可以通过增加更多的图像数据来训练,从而提高识别的准确率, 这里我开始做进一步的详细教程。

            为此,我们需要创建一个手写数字的文件 “ digits.png ”,图像的像素为:( 1800*400 ), 其中包含 900 个手写数字(每个数字 90 个),每个数字都是20x20的图像,如下图。

            因此,我们的第 1 步是将图像分割成 900 个不同的数字。对于每个数字,我们将其展平为400像素的一行。那就是我们的训练集,即所有像素的强度值。这是我们可以创建的最简单的功能集。我们将每个数字的 前45个样本 用作训练数据,然后将 后45个样本 用作测试数据

    1. 识别数字0~9例程

    1. import numpy as np # 导入numpy库,用于进行矩阵运算
    2. import cv2 as cv # 导入OpenCV库,用于图像处理
    3. img = cv.imread('digits.png') # 读取名为'digits.png'的图像
    4. gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) # 将图像转换为灰度图像
    5. # 现在我们将图像分割为900个单元格,每个单元格为20x20
    6. cells = [np.hsplit(row,90) for row in np.vsplit(gray,10)] # 将图像分割成10行90列的单元格,每个单元格为20x20像素
    7. # 使其成为一个Numpy数组。它的大小将是(10,90,20,20)
    8. x = np.array(cells) # 将分割后的图像转换为一个Numpy数组
    9. # 现在我们准备train_data和test_data。
    10. train = x[:,:45].reshape(-1,400).astype(np.float32) # 取数组的前50%作为训练数据,并将其形状转换为(450,400)的浮点数类型
    11. test = x[:,45:90].reshape(-1,400).astype(np.float32) # 取数组的后50%作为测试数据,并将其形状转换为(450,400)的浮点数类型
    12. # 为训练和测试数据创建标签
    13. k = np.arange(10) # 创建一个包含数字0到10的一维数组
    14. train_labels = np.repeat(k,45)[:,np.newaxis] # 将数组重复45次,得到一个(450,1)的二维数组,作为训练数据的标签
    15. test_labels = train_labels.copy() # 复制训练数据的标签,作为测试数据的标签
    16. # 初始化kNN,训练数据,然后使用k = 1的测试数据对其进行测试
    17. knn = cv.ml.KNearest_create() # 创建一个kNN分类器对象
    18. knn.train(train, cv.ml.ROW_SAMPLE, train_labels) # 使用训练数据和标签训练分类器
    19. ret,result,neighbours,dist = knn.findNearest(test,k=1) # 使用测试数据和k=1的参数调用分类器的findNearest方法,得到返回值、预测结果、最近邻样本和距离
    20. # 现在,我们检查分类的准确性
    21. #为此,将结果与test_labels进行比较,并检查哪个错误
    22. matches = result==test_labels # 将预测结果与测试标签进行比较,得到一个布尔类型的数组
    23. correct = np.count_nonzero(matches) # 统计布尔数组中非零元素的数量,即预测正确的数量
    24. accuracy = correct*100.0/result.size # 计算预测准确率,即正确预测的数量占总数量的比例
    25. print("预测准确率:",accuracy) # 输出预测准确率
    26. # 打印预测结果。这是一个新样本的标签。
    27. print( "result:\n{}\n".format(result) )
    28. # 打印最近邻样本的索引。这是一个新样本的1个最近邻样本在训练数据集中的索引。
    29. print( "neighbours: {}\n".format(neighbours) )
    30. # 打印最近邻样本的距离。这是一个新样本与它的1个最近邻样本的距离。
    31. print( "distance: {}\n".format(dist) )

    2.识别数字0~9输出结果

            我们通过获取result变量里面的值,确定1~10行的后45个样本图像被识别为数字几,来确定我们的准确率。

    1. 预测准确率: 87.11111111111111
    2. result:
    3. [
    4. [0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.][0.]
    5. [1.][1.][1.][1.][1.][1.][1.][1.][1.][1.][1.][1.][1.][1.][1.][1.][1.][1.][1.][1.][1.][9.][1.][9.][1.][8.][8.][1.][1.][1.][1.][1.][1.][1.][1.][1.][1.][1.][1.][1.][1.][1.][1.][8.][8.]
    6. [2.][2.][2.][2.][2.][2.][2.][2.][2.][2.][2.][2.][2.][2.][2.][2.][4.][7.][2.][5.][3.][3.][2.][2.][2.][2.][2.][6.][2.][2.][2.][2.][2.][2.][2.][2.][2.][2.][2.][2.][2.][2.][2.][5.][2.]
    7. [3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][1.][3.][3.][7.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][3.][1.]
    8. [4.][4.][4.][4.][4.][4.][4.][4.][5.][4.][4.][4.][4.][4.][4.][4.][4.][4.][4.][4.][4.][4.][4.][4.][4.][4.][4.][4.][4.][5.][4.][4.][0.][4.][4.][5.][4.][4.][4.][4.][4.][4.][0.][4.][1.]
    9. [5.][5.][5.][5.][5.][5.][5.][5.][5.][5.][5.][5.][5.][1.][5.][5.][5.][5.][5.][1.][5.][5.][5.][5.][5.][5.][3.][5.][5.][5.][5.][3.][2.][5.][3.][5.][5.][5.][5.][5.][5.][8.][5.][5.][5.]
    10. [6.][6.][6.][6.][6.][6.][6.][6.][6.][6.][6.][6.][6.][6.][6.][0.][6.][6.][6.][6.][6.][6.][6.][1.][6.][6.][6.][6.][6.][8.][6.][6.][6.][6.][6.][6.][6.][6.][6.][6.][6.][6.][6.][6.][6.]
    11. [7.][7.][7.][7.][7.][7.][7.][7.][7.][7.][7.][1.][7.][7.][7.][7.][7.][7.][7.][7.][7.][7.][7.][7.][9.][7.][7.][7.][7.][7.][7.][7.][7.][7.][7.][7.][7.][1.][7.][7.][7.][7.][7.][7.][1.]
    12. [6.][8.][8.][8.][4.][8.][8.][8.][8.][3.][8.][3.][8.][8.][8.][8.][8.][8.][8.][8.][8.][8.][8.][8.][9.][8.][8.][8.][8.][8.][4.][3.][8.][8.][8.][8.][4.][8.][8.][8.][8.][1.][8.][8.][0.]
    13. [9.][9.][9.][8.][9.][9.][9.][9.][9.][9.][9.][9.][7.][9.][9.][9.][9.][9.][9.][9.][1.][1.][9.][1.][9.][9.][9.][9.][9.][9.][9.][9.][9.][9.][9.][9.][7.][7.][9.][9.][7.][1.][7.][1.][7.]
    14. ]

    3.识别数字0~9结果分析

            通过上面我们可以看出,错误还是有很多的,那是为什么呢?其实我们查看图片就能清晰的看出前45个样本图像和后45个样本图像的相关性(字体样式)有很大区别,所以造成识别的准确率这么低

    三、扩展思路

            上面的例程只是教我们识别已经保存好的图像,进行数字的识别,但是这种通过自己手动保存,再去识别的方式太过笨拙了。那我们可以进一步扩展,通过摄像头拍照获取图像数据流,然后经过OpenCV的前处理后,再保存为测试数据,通过训练好的kNN近邻进行数字的识别,那我们这个项目是不是就更加的完美了呢?

  • 相关阅读:
    分类预测 | Matlab实现SSA-CNN-SVM麻雀算法优化卷积支持向量机分类预测
    【效率提升】maven 转 gradle 实战 | 京东云技术团队
    Plsql连接报Initialization Error:Could not initialize oci.dll
    [autojs]逍遥模拟器和vscode对接
    mysql常用语句之DML:数据操作语句:插入、修改、删除
    vue中keep-alive的作用
    Java程序设计实验4 | 面向对象(下)
    nohup训练pytorch模型时的报错以及tmux的简单使用
    clickhouse学习笔记04
    axios的get请求时数组参数没有下标
  • 原文地址:https://blog.csdn.net/qq_26043945/article/details/133313478