Python手写数字识别进阶:从预处理到KNN分类算法详解

半杯拿铁
半杯拿铁
发布时间:2026-10-13 | 3人浏览过
原创

本文详细解析使用Python进行手写数字识别的进阶方案。内容涵盖图像预处理步骤,包括自适应裁剪、灰度转换及二值化处理,以应对任意大小和非白底背景。核心算法采用基于“洞数”特征的分类与K近邻(KNN)向量距离计算相结合的策略,通过训练集CSV文件管理实现动态更新。文章旨在为具备Python基础的开发者提供逻辑清晰、通俗易懂的实战思路,探讨如何提升识别准确率并处理常见手写差异问题。

写在前面

此前我曾编写过一个简易的手写数字识别程序,但由于逻辑较为简单且对输入条件要求苛刻——仅支持50x50像素大小、白底黑字的图像,且训练样本不足,导致最终准确率仅在50%左右徘徊。因此,本次计划开发一个功能更强大的升级版程序,借此机会深入提升使用Python处理文件与图像数据的能力。

本次升级旨在增加识别难度,具体改进点如下:

  • 支持识别任意尺寸的输入图片;
  • 不再局限于白底图像,只要数字为黑色且背景为浅色即可识别;
  • 优化手写数字识别的核心逻辑,以显著提升整体准确率。

由于目前尚未开始正式编码,加之近期专业课程任务繁重,更新进度可能较为缓慢。但请放心,代码质量绝不会因此降低,我将尽力确保逻辑清晰、易于理解。

因此,本文的目标读者是那些已经掌握一定Python基础,并对数学算法(特别是图像识别相关算法)有初步了解的开发者。

需要说明的是,我并非专业研究人员,也未深入研读大量学术论文,此处采用的算法仅基于个人初步思考,主要用于练习和探索。若该方案与实际工业应用存在差距,敬请谅解。

如果您有更好的想法或优化建议,欢迎在评论区留言或私信交流,我们可以共同探讨,互相促进,共同进步。

整体思路

大纲

对图片的预处理

在初始阶段,我们假设系统仅拥有一个训练库,其中包含若干组从0到9的手写数字图案。

因此,首要步骤是将这些图案读取到程序中,并通过某种方式妥善保存,以便后续用于识别新图片。

考虑到图案大小不一且手写数字尺寸各异,我们可以先提取包围手写数字图案的最小矩形区域进行裁剪,然后将裁剪后的图像统一拉伸至相同尺寸。

经过上述操作,我们得到一个表示图案灰度值的矩阵。无论是训练用图片还是待检测图片,均按此方式进行处理。

图像识别的算法处理

为了提高数字识别的准确度,我计划结合两种方法:

  • 计算所写数字的“洞数”特征;
  • 将图片转换为1xN维向量,并根据训练图片划分好的类别,对待识别图片进行分类。

所谓“洞数”,即数字中是否存在闭合曲线。例如,数字7没有洞,6有一个洞,8有两个洞。根据洞数,我们可以将数字初步分为以下三类:

0洞:1, 2, 3, 4, 5, 7 1洞:6, 9, 0 2洞:8

然而,由于手写风格的差异,例如6、9、8可能未完全闭合,或者4的上部闭合方式不同,这可能导致分类出现以下情况:

0洞:1, 2, 3, 4, 5, 6, 7, 9 1洞:6, 8, 9, 0 2洞:8

尽管这种分类下0洞类别的样本占多数,但这一特征仍具有一定的区分价值。

将图片转为向量的含义,即将图片原本的二维矩阵展开为一维向量。利用NumPy库的相关函数,可以非常简便地实现这一操作。

关于这一分类策略,下面简要阐述其原理。

假设在二维平面上有两个点A=(1,1)和B=(5,5),此时再引入一个点C=(2,2),请问C点距离哪一个点更近?

具备初中数学知识的人都会知道,C点显然离A点更近。因此,我们可以换一种表述:假设现在有两个类别,A类包含点(1,1),B类包含点(5,5),那么对于点(2,2),它更可能属于哪一类?

由于该点距离A类中的点更近,因此它更可能属于A类。这就是基本结论。同理,在三维空间中,若A类点为(1,1,1),B类点为(5,5,5),那么点(2,2,2)同样属于A类。

由此可见,我们这里是以两点间的距离作为判断类别归属的标准。对于我们将图片拉伸成的1xN维向量,它在N维空间中实际上投影为一个点。因此,我们将训练向量划分为10个类别,分别代表0到9这十个数字。若被识别的数字向量靠近某一类,则说明它可能属于该类别。

具体而言,我们可以假设对于被识别向量,列出距离它最近的前十个训练向量及其所属类别,然后根据名次赋予相应的权重,计算出一个综合值。该值代表了最可能的类别,从而得出最终结果——被识别手写数字图片的值。

难点

保存已训练图片的向量。这一点我打算直接将其保存在CSV文件中。每次运算时,先判断是否有新的训练图片加入;如果有,则将新图片的向量也存入CSV文件;若没有,则直接读取所有向量并保存到一个大矩阵中用于计算。

将手写数字从背景中分离。由于我设定手写数字为黑色(灰度值为0),而背景色尽量为浅色,因此可以设定一个灰度值阈值(如50),将灰度值大于该阈值的点全部设为255(白色),其余保持不变。这样,只要像素值不为255,即可判定为手写数字的点。

识别手写数字的洞。这一部分有现成的算法,参与过程序设计竞赛的人应该比较熟悉。具体细节此处不再赘述,大致思路是利用递归等方式进行搜索。

求向量距离。这一步相对简单,只需计算每一个训练向量与识别向量之间的距离即可。不过,当训练向量维度较大时,计算过程可能会比较耗时。

总结

以上就是全部思路。如果您有更好的想法,欢迎评论或私信交流,让我们一起互相学习,共同进步,谢谢。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表