当前位置: 首页 > backend >正文

基于 OpenCV 与 sklearn 的数字识别:KNN 算法实践

在计算机视觉领域,数字识别是一个经典问题,广泛应用于邮政编码识别、车牌识别等场景。本文将介绍如何使用 OpenCV 进行图像处理,并结合 KNN(K 近邻)算法实现数字识别,同时对比 OpenCV 内置 KNN 与 scikit-learn 库中 KNN 的实现差异。

准备工作

首先,我们需要导入所需的库:

import numpy as np
import cv2
from sklearn.neighbors import KNeighborsClassifier

其中,numpy用于数值计算,cv2(OpenCV)用于图像处理,KNeighborsClassifier则是 scikit-learn 库中的 KNN 分类器。

图像读取与预处理

我们需要读取两张图像:一张包含大量数字样本的训练图像,另一张作为测试图像。

# 读取训练图像和测试图像
img = cv2.imread(r'D:\pythonProject11\class\aa.png')
c_img = cv2.imread(r'D:\pythonProject11\class\ccc.png')# 将彩色图像转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
c_gray = cv2.cvtColor(c_img, cv2.COLOR_BGR2GRAY)

彩色图像包含 RGB 三个通道,转换为灰度图像可以减少计算量,同时保留图像的主要特征。cv2.cvtColor函数用于颜色空间转换,COLOR_BGR2GRAY参数表示从 BGR 格式(OpenCV 默认的彩色图像格式)转换为灰度格式。

数据准备

图像分割

我们假设训练图像是一个包含 50 行 100 列数字的网格图像,每个数字占据一个 20×20 像素的区域。我们需要将这个大图像分割成多个小图像,每个小图像对应一个数字样本。

python

运行

# 先垂直分割成50行,再对每行水平分割成100列
cell = np.array([np.hsplit(row, 100) for row in np.split(gray, 50)])

这里使用了np.splitnp.hsplit两个函数:

  • np.split(gray, 50)将灰度图像垂直分割成 50 个等高度的子数组
  • np.hsplit(row, 100)将每个子数组水平分割成 100 个等宽度的子数组

最终得到的cell是一个形状为 (50, 100, 20, 20) 的数组,表示 50 行 100 列,每个元素是 20×20 像素的数字图像。

训练集和测试集划分

我们将前 50 列作为训练集,后 50 列作为测试集:

python

运行

# 划分训练集和测试集
train_ma = cell[:, :50]  # 前50列作为训练集
test_ma = cell[:, 50:100]  # 后50列作为测试集# 转换为二维数组(样本数×特征数)
train_ma = train_ma.reshape(-1, 400).astype(np.float32)  # 50×50=2500个样本,每个样本20×20=400个特征
test_ma = test_ma.reshape(-1, 400).astype(np.float32)

reshape(-1, 400)将每个 20×20 的图像转换为一个长度为 400 的一维数组,便于作为机器学习算法的输入。-1表示自动计算该维度的大小,这里计算结果为 2500(50×50)。

标签生成

我们需要为每个样本生成对应的标签(即该样本对应的数字)。假设图像中的数字是按 0-9 的顺序重复排列的:

python

运行

# 生成标签
kernel = np.arange(10)  # 生成0-9的数字
train_la = np.repeat(kernel, 250)[:, np.newaxis]  # 每个数字重复250次,形成2500个标签
test_la = np.repeat(kernel, 250)[:, np.newaxis]

np.repeat(kernel, 250)将 0-9 每个数字重复 250 次,得到一个长度为 2500 的数组,与我们的样本数量一致。[:, np.newaxis]将一维数组转换为二维列向量,以满足 OpenCV 中 KNN 算法对标签格式的要求。

测试图像预处理

我们需要对测试图像进行同样的预处理:

python

运行

# 预处理测试图像
c_test = np.array(c_gray).reshape(-1, 400).astype(np.float32)

使用 OpenCV 的 KNN 进行识别

OpenCV 库中内置了 KNN 算法的实现:

python

运行

# 创建并训练OpenCV的KNN模型
knn = cv2.ml.KNearest_create()
knn.train(train_ma, cv2.ml.ROW_SAMPLE, train_la)  # ROW_SAMPLE表示每行是一个样本# 预测
ret, results, neigh, dist = knn.findNearest(c_test, 4)  # 寻找4个最近邻
print("OpenCV KNN预测结果:", results)

cv2.ml.KNearest_create()创建一个 KNN 模型实例,train方法用于训练模型,findNearest方法用于预测。findNearest的第二个参数表示要寻找的最近邻数量 K。

使用 scikit-learn 的 KNN 进行识别

我们也可以使用 scikit-learn 库中的 KNN 实现:

python

运行

# 为scikit-learn准备标签(一维数组)
train_la = np.repeat(kernel, 250)
test_la = np.repeat(kernel, 250)# 创建并训练scikit-learn的KNN模型
knnl = KNeighborsClassifier(n_neighbors=5)  # K=5
knnl.fit(train_ma, train_la)# 评估模型准确率
a = knnl.score(test_ma, test_la)
print("模型准确率:", a)# 预测
b = knnl.predict(c_test)
print("scikit-learn KNN预测结果:", b)

scikit-learn 的 KNN 使用起来更加简洁,KNeighborsClassifiern_neighbors参数指定 K 值,fit方法用于训练,score方法用于评估模型准确率,predict方法用于预测。

总代码

import numpy as np
import cv2
from sklearn.neighbors import KNeighborsClassifier
img = cv2.imread(r'D:\pythonProject11\class\aa.png')
c_img = cv2.imread(r'D:\pythonProject11\class\ccc.png')
# c_img = cv2.imread('img_1.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转化为灰度图像
c_gray = cv2.cvtColor(c_img,cv2.COLOR_BGR2GRAY)
c_test = np.array(c_gray).reshape(-1,400).astype(np.float32)cell =np.array([np.hsplit(row,100) for row innp.split(gray,50)])
train_ma = cell[:,:50]
test_ma = cell[:,50:100]
train_ma = train_ma.reshape(-1,400).astype(np.float32)
test_ma = test_ma.reshape(-1,400).astype(np.float32)
kernel = np.arange(10)
train_la = np.repeat(kernel,250)[:,np.newaxis]#cv2的方法
test_la = np.repeat(kernel,250)[:,np.newaxis]
knn = cv2.ml.KNearest_create()
knn.train(train_ma,cv2.ml.ROW_SAMPLE,train_la)#cv2.mL.ROW_SAMPLE:这是一个标志,告诉0pencv训练数据是按行组织的,即每一行是一个样本。
ret, results, neigh, dist = knn.findNearest(c_test,4)
print(results)
train_la = np.repeat(kernel,250)#sklearn的方法
test_la = np.repeat(kernel,250)
knnl = KNeighborsClassifier(n_neighbors=5)
knnl.fit(train_ma,train_la)
a=knnl.score(test_ma,test_la)
b=knnl.predict(c_test)
print(a,b)

两种实现的对比

  1. 接口设计:OpenCV 的 KNN 接口更偏向于计算机视觉领域的使用习惯,而 scikit-learn 的接口则更符合机器学习的通用范式。

  2. 输入格式:OpenCV 的 KNN 要求标签是列向量,而 scikit-learn 的 KNN 要求标签是一维数组。

  3. 功能:scikit-learn 的 KNN 提供了更多的评估方法和参数设置,而 OpenCV 的 KNN 则更轻量,与图像处理功能结合更紧密。

  4. 结果:在相同的 K 值设置下,两种实现的预测结果应该是相似的,但可能会因为具体实现细节的不同而略有差异。

总结

本文介绍了如何使用 OpenCV 进行图像预处理,以及如何使用 KNN 算法实现数字识别。通过对比 OpenCV 和 scikit-learn 中 KNN 的实现,我们可以看到不同库在接口设计和使用方式上的差异。

在实际应用中,我们可以根据具体需求选择合适的库和算法。如果需要处理图像并进行简单的分类,OpenCV 的 KNN 可能是一个不错的选择;如果需要更复杂的机器学习功能和更全面的评估方法,scikit-learn 则更为适合。

此外,KNN 算法虽然简单易懂,但在处理大规模数据集时效率较低。在实际应用中,我们可能需要考虑使用更高效的算法,如 SVM、神经网络等,以获得更好的性能。

http://www.xdnf.cn/news/16504.html

相关文章:

  • 123页PPT麦肯锡49个思维工具和方法论PPT
  • 一个典型的微控制器MCU包含哪些模块?
  • Java Collections工具类
  • 达梦有多少个模式
  • 页面性能优化
  • Java基础-IO流
  • 【灰度实验】——图像预处理(OpenCV)
  • 商用车的自动驾驶应用场景主要包括七大领域
  • 开发指南125-HTML DOM事件
  • 1.gradle安装(mac)
  • RocketMQ入门实战详解
  • clock_getres系统调用及示例
  • 智慧社区项目开发(二)——基于 JWT 的登录验证功能实现详解
  • 分布式高可用架构核心:复制、冗余与生死陷阱——从主从灾难到无主冲突的避坑指南
  • 【Linux篇】进程间通信:进程IPC
  • 负载均衡算法中的加权随机算法
  • kafka开启Kerberos使用方式
  • uniapp_微信小程序_根据胶囊按钮计算出的导航栏高度为什么不是44px?
  • 【Linux】Ubuntu上安装.NET 9运行时与ASP.NET Core项目部署入门
  • 复杂人流场景口罩识别漏检率↓76%:陌讯动态特征融合算法实战解析
  • 开源智能体-JoyAgent集成ollama私有化模型
  • ATF 运行时服务
  • 标准解读——2024 数据资产价值评估指南(正式版)【附全文阅读】
  • ICDC自动化部署方案概述
  • 7.28 错题(zz)史纲 第五章新道路
  • Qt_Gif_Creator 基于Qt的屏幕gif录制工具
  • 灵动画布:快手可灵 AI 推出的多人协作 AI 创意工作台
  • PostgreSQL日志配置全解析:从基础设置到进阶策略
  • 墨者:SQL手工注入漏洞测试(MySQL数据库-字符型)
  • LangGraph智能体(天气和新闻助手)开发与部署