机器学习——KNN实现手写数字识别:基于 OpenCV 和 scikit-learn 的实战教学 (超级超级超级简单)

用KNN实现手写数字识别:基于 OpenCV 和 scikit-learn 的实战教学

在这篇文章中,我们将使用 KNN(K-Nearest Neighbors)算法对手写数字进行分类识别。我们会用 OpenCV 读取图像并预处理数据,用 scikit-learn 构建并训练模型,最终识别新的数字图像。

为什么像素可以被代码读取为数据:

图像的本质:像素的数字矩阵

任何数字图像(如照片、截图、手写数字图片)都是由无数个微小的 “像素点”(Pixel)组成的

  • 每个像素点的数值含义

    • 对于灰度图(如代码中的手写数字),每个像素用一个 0-255 的整数表示亮度:0 代表纯黑,255 代表纯白,中间值表示不同深浅的灰色。
    • 对于彩色图(如 RGB 格式),每个像素由三个数值(R、G、B)组成,分别对应红、绿、蓝三种颜色的亮度,组合后呈现出各种颜色。

(可以在调试时看一看代码里的‘gray’参数里面 单个数字图像的矩阵)

此20×20 像素的数字图像就是一个数字矩阵显示出的一个大大的 0

使用的数据集

我们使用的是一个包含 5000 个手写数字(0-9) 的图像文件(digits5000.png),每种数字500个,总共10类。图像被排布成了一个 50 行 × 100 列 的网格,每个小格是一个 20×20 像素的数字图像

数据图像:

保存下面代码所需的三张图片:

 

上面的 ‘3’,‘6’ 图片可在‘开始’里的‘画图’中,可以创建我们想要自定义的数字图片:


然后使用画笔写一个数字后(笔粗一点):

把比例调到   20×20 像素

即可得到。

 完整代码:

import numpy as np
from sklearn.neighbors import KNeighborsClassifier
import cv2# 读取包含5000个手写数字的大图,每个数字为20x20像素
img = cv2.imread('digits5000.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转换为灰度图# 将大图分割为50行100列的小单元格,每个单元格包含一个手写数字
cells = [np.hsplit(row,100) for row in np.vsplit(gray,50)]# 将单元格列表转换为四维数组: (50行, 100列, 20像素高, 20像素宽)
x = np.array(cells)# 准备训练集和测试集数据
# 前50列作为训练集,后50列作为测试集
# 数据重塑为: (样本数, 特征数),每个样本包含400个像素值
train = x[:,:50].reshape(-1,400)
test = x[:,50:].reshape(-1,400)# 创建标签数据
n = np.arange(10)  # 创建数字0-9的数组
# 每个数字对应250个样本(50行×5列),生成训练标签
tags = np.repeat(n,250)
tag = tags[:,np.newaxis]  # 转换为二维数组,形状为(2500, 1)# 创建并训练KNN分类器,使用k=5最近邻
knn = KNeighborsClassifier(n_neighbors=5)    #给初学者的建议:在此处设置断点 或 直接在import处设置断点,开启调试一行一行地运行,更好的看到每一个参数的变化
knn.fit(train, tag)# 评估模型在训练集上的准确率
predictions_train = knn.predict(train)    #此行结果没有运行,建议在开启调试,可看到
accuracy_train = knn.score(train, tag)
print(f"训练集准确率: {accuracy_train:.4f}")# 评估模型在测试集上的准确率
predictions_test = knn.predict(test)
accuracy_test = knn.score(test, tag)
print(f"测试集准确率: {accuracy_test:.4f}")# 预测外部数字3的图像
digit3 = cv2.imread('digit3.png')
digit3gray = cv2.cvtColor(digit3, cv2.COLOR_BGR2GRAY)
digit3test = digit3gray.reshape(-1,400)  # 重塑为模型期望的输入格式
predictions_digit3 = knn.predict(digit3test)
print(f"预测数字3的结果: {predictions_digit3}")# 预测外部数字6的图像
digit6 = cv2.imread('digit6.png')
digit6gray = cv2.cvtColor(digit6, cv2.COLOR_BGR2GRAY)
digit6test = digit6gray.reshape(-1,400)  # 重塑为模型期望的输入格式
predictions_digit6 = knn.predict(digit6test)
print(f"预测数字6的结果: {predictions_digit6}")

红色断点:

调试:

点击 单步执行 或 其他   ,多尝试尝试

点击“作为...查看”即可清晰查看


所需库导入

import numpy as np
from sklearn.neighbors import KNeighborsClassifier
import cv2
  • numpy: 用于矩阵操作。

  • sklearn.neighbors.KNeighborsClassifier: 实现KNN分类器。

  • cv2: OpenCV库,用于图像读取与处理。


图像加载与预处理

img = cv2.imread('digits5000.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

  • cv2.imread() 读取图像。

  • cv2.cvtColor() 将图像从彩色(BGR)转换为灰度(GRAY),便于处理。


图像分割成小数字图块

cells = [np.hsplit(row,100) for row in np.vsplit(gray,50)]
x = np.array(cells)
  • 使用 np.vsplit() 将图像竖直切成50行(每行包含100个数字)。

  • 对每行使用 np.hsplit() 水平切分成100列,最终每个小格是一个20x20的数字图像。

  • 得到的 x 是一个形状为 (50, 100, 20, 20) 的数组。


构建训练集与测试集

train = x[:,:50].reshape(-1,400)
test = x[:,50:].reshape(-1,400)
  • 将每个 20×20 图像展开为 1×400 的一维向量。

  • 前 50 列作为训练集,后 50 列作为测试集。

  • traintest 的形状均为 (2500, 400)


构造标签

n = np.arange(10)                   #(0123456789)
tags = np.repeat(n,250)            #每个数字重复250次 -> [0,...0,1,...,1,...9,...9]
tag = tags[:,np.newaxis]           #添加新维度,变成列向量
# test_tag = np.repeat(n,250)[:np.newaxis]   
  • tags 是长度为 2500 的一维标签数组。

  • tag 是形状为 (2500, 1) 的列向量,作为训练和测试的真实标签。

为什么重复250次,因为我们把数据从中间对半切开,每个数字有500个,左二百五十为训练集,右二百五十个为测试集。

所以其实训练集和测试集的标签是一样的,标签就是每一个20x20数字图像所显示的数字。


训练模型并评估准确率

knn = KNeighborsClassifier(n_neighbors=5)
knn.fit(train, tag)predictions_train = knn.predict(train)
accuracy_train = knn.score(train, tag)
print(accuracy_train)predictions_test = knn.predict(test)
accuracy_test = knn.score(test, tag)
print(accuracy_test)
  • 初始化一个 KNN 分类器,选择 k=5

  • 使用 .fit() 训练模型。

  • 使用 .predict().score() 对训练集和测试集进行预测和评分。

  • 打印准确率:理论上训练集精度应很高,测试集略低(但通常也超过 97%)。


识别自定义手写数字

digit3 = cv2.imread('digit3.png')   #图片中的数字是3
digit3gray = cv2.cvtColor(digit3, cv2.COLOR_BGR2GRAY)
digit3test = digit3gray.reshape(-1,400)
predictions_digit3 = knn.predict(digit3test)
print(predictions_digit3)digit6 = cv2.imread('digit6.png')   #图片中的数字是6
digit6gray = cv2.cvtColor(digit6, cv2.COLOR_BGR2GRAY)
digit6test = digit6gray.reshape(-1,400)
predictions_digit6 = knn.predict(digit6test)
print(predictions_digit6)
  • 读取两张额外图像 digit3.pngdigit6.png

  • 将其转换为灰度、再reshape成与训练数据一致的 (1, 400) 形状。

  • 使用模型预测数字类别。


总结

我们用 KNN 成功实现了手写数字的分类识别,关键步骤包括:

  1. 图像预处理和切分

  2. 标签构造与数据 reshape

  3. 使用 KNeighborsClassifier 建模

  4. 预测未知图像的数字类别

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/91139.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/91139.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Git】分支

文章目录理解分支创建分支切换分支合并分支删除分支合并冲突分支管理策略分支策略bug 分支删除临时分支小结理解分支 本章开始介绍 Git 的杀手级功能之一(注意是之一,也就是后面还有之二,之三……):分支。分支就是科幻…

【32】C# WinForm入门到精通 ——打开文件OpenFileDialog 【属性、方法、事件、实例、源码】

WinForm 是 Windows Form 的简称,是基于 .NET Framework 平台的客户端(PC软件)开发技术,是 C# 语言中的一个重要应用。 .NET 提供了大量 Windows 风格的控件和事件,可以直接拿来使用。 本专栏内容是按照标题序号逐渐…

Wan2.2开源第1天:动态灯光功能开启创意氛围新境界

在开源软件蓬勃发展的今天,每一次新版本的发布都如同在创意的星空中点亮了一颗璀璨的新星。今天,(通义万相国际版wan)Wan2.2正式开源,它带着令人眼前一亮的动态灯光功能惊艳登场,为所有追求创意与氛围营造的…

Excel制作滑珠图、哑铃图

Excel制作滑珠图、哑铃图效果展示在较长时间周期内,很多参数都是在一定范围内浮动的,并不是一成不变的,为了直观表达各类别的浮动范围,使用“滑珠图”就是一个不错的选择,当滑珠图两侧均有珠子的时候,又称为…

Day07 JDBC+MyBatis

1.JDBC入门程序2.JDBC执行DQL语句3.JDBC预编译SQL 防止SQL注入随便输入用户名,密码为or1 1,sql注入4.Mybatis入门 Mapper 持久层XxxMapper替代Dao4.1调用接口的findAll()方法时自动执行上方的SQL语句,并将SQL查询的语句自动封装到返回值中5.Mybatis辅助…

OSS-服务端签名Web端直传+STS获取临时凭证+POST签名v4版本开发过程中的细节

这里写自定义目录标题配置OSS服务端代码初始化STS Client获取STS临时凭证创建policy计算SigningKeyOSSUtil.javaSTSPolicyDTO.java提供接口Apifox模拟Web端文件直传本文主要结合服务端STS获取临时凭证(签名)直传官方文档对开发中比较容易出错的地方加以提醒;建议主要…

uniapp实现微信小程序导航功能

1.导航按钮<button click"navigation()">导航到仓库</button>2.导航功能const navigation (item) > {let address item.province item.city item.district item.address //地址let latitude Number(item.latitude) …

07.4-使用 use 关键字引入路径

使用 use 关键字引入路径 每次调用函数时都必须写出完整路径&#xff0c;可能会感觉不便且重复。在清单7-7中&#xff0c;无论我们选择绝对路径还是相对路径来调用 add_to_waitlist 函数&#xff0c;每次调用时都必须指定 front_of_house 和 hosting。幸运的是&#xff0c;有一…

7.Linux :进程管理,进程控制与计划任务

Linux &#xff1a;进程管理&#xff0c;进程控制与计划任务 一、进程管理 1. 进程与程序 程序&#xff1a;静态的可执行文件&#xff08;存储于磁盘&#xff09;。进程&#xff1a;动态执行的程序实例&#xff08;占用CPU/内存&#xff09;。 2. 查看进程命令作用常用组合ps静…

Matplotlib(四)- 图表样式美化

文章目录一、Matplotlib图表样式介绍1. 图表样式简介2. 默认图表样式2.1 查看默认配置2.2 常用的配置3. 图表样式修改3.1 局部修改3.1.1 通过绘图方法设置参数修改3.1.2 通过rcParams修改3.1.3 通过rc()方法修改3.2 全局修改二、颜色设置1. 颜色的三种表示方式1.1 颜色单词1.2 …

三十四、【Linux常用工具】rsync+inotify实时同步演示

实时同步演示技术架构全景核心组件详解1. inotify 内核子系统2. Rsync 高效同步工具实践演示一、环境准备与安装1. 检查内核支持2. 安装 inotify-tools二、配置 Rsync 服务端&#xff08;目标机&#xff09;1. 创建 Rsync 配置文件2. 启动 Rsync 守护进程三、配置实时同步脚本&…

windows环境下MySQL 8.0 修改或重置密码

windows环境下MySQL 8.0 修改或重置密码 1打开命令窗口cmd&#xff0c;输入命令&#xff1a;net stop mysql&#xff0c; 停止MySQL服务&#xff0c; 开启跳过密码验证登录的MySQL服务 2输入命令 mysqld --console --skip-grant-tables --shared-memory 再打开一个新的cmd&…

基于YOLOP与GAN的图像修复与防御系统设计与实现

基于YOLOP与GAN的图像修复与防御系统设计与实现 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff0c;觉得好请收藏。点击跳转到网站。 1. 引言 1.1 研究背景 随着深度学习技术在计算机视觉领域的…

将目录文件转移到D盘,使之后的下载缓存数据转移,不再存入c盘

将 C:\Users 文件夹&#xff08;用户文件夹&#xff09;转移到其他盘是一个复杂且风险较高的操作。C:\Users 文件夹包含了系统中每个用户的个人数据和配置文件&#xff0c;修改这个路径可能会导致系统出现问题&#xff0c;包括程序无法正常工作或无法登录。因此&#xff0c; 强…

Cesium大气散射效果

由于做全球体积云效果的需要&#xff0c;再来研究下大气散射效果和体积云类似&#xff0c;关于大气散射颜色计算的过程也仅发生在这两个球体之间。如图所示。计算从相机出发的视线与球壳的交点&#xff0c;如果不相交&#xff0c;则该视线方向上不会发生大气散射&#xff0c;直…

预过滤环境光贴图制作教程:第二步 - 生成环境贴图图集

核心目标 本步骤的核心是生成一张包含 6 级分辨率的环境贴图图集(envAtlas),实现: 将第一步的立方体贴图(sourceCube)重新映射为等矩形投影(适合存储和采样); 生成 6 级不同分辨率的等矩形数据(0 级最高清,5 级最模糊); 用 RGBP 编码压缩 HDR 数据(平衡精度与存…

1. ESP开发之实体按键(KEYPADBUTTON)控制LVGL控件

说明LV_INDEV_TYPE_BUTTON的使用LV_INDEV_TYPE_KEYPAD的使用 说明 本实验使用LVGL版本为v9.2 LVGL中有四种输入设备,如下LV_INDEV_TYPE_POINTER, /**< Touch pad, mouse, external button*/ LV_INDEV_TYPE_KEYPAD, /**< Keypad or keyboard*/ LV_INDEV_TYPE_BUTTON, /*…

C++:STL中list的使用和模拟实现

C中的list是标准模板库&#xff08;STL&#xff09;提供的双向链表容器&#xff0c;支持高效的元素插入和删除操作。在上一篇中讲解了vector的使用和模拟实现&#xff0c;vector是具有连续的空间&#xff0c;迭代器是可以随机的&#xff0c;而list却于vector不同&#xff0c;li…

【编号58-61】我国四大高原矢量示意图shp数据

今天分享的是&#xff1a;中国四大高原&#xff0c;分别是青藏高原、内蒙古高原、黄土高原、云贵高原。青藏高原位置与范围&#xff1a;位于中国西南部&#xff0c;包括西藏、青海的全部&#xff0c;川西高原及滇西北高原等部分地区。它的边界&#xff0c;向东是横断山脉&#…

【AI落地应用实战】利用 Amazon Bedrock Claude3 打造个性化 AI Character 应用

目录一、引言&#xff1a;AI Character应用的市场前景与技术基础二、技术架构设计2.1、整体方案概述2.2、核心组件介绍2.3、部署架构图三、系统部署方案3.1、方案总述3.2、实践流程1️⃣. Bedrock 配置2️⃣. 安装 SillyTavern3️⃣. 配置 SillyTavern 使用 Claude3 模型4️⃣.…