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

基于 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.dtcms.com/a/302795.html

相关文章:

  • 【CDA干货】金融超市电商App经营数据分析案例
  • 星辰大海的征途:星宸科技的中国芯片突围战
  • 【行测】常识判断1
  • 【Unity笔记03】#if的用法和命名空间
  • EXCEL怎么提取表名
  • 在CentOS上以源码编译的方式安装PostgreSQL
  • 【51单片机2位数码管跑马灯】2022-9-25
  • 时间数字转换器TDC的FPGA方案及核心代码
  • 51单片机如何实现round函数
  • Java 大视界 -- 基于 Java 的大数据实时流处理在智能电网分布式能源接入与电网稳定性保障中的应用(368)
  • 【Linux】重生之从零开始学习运维之mysql用户管理
  • live-server的使用以及离线环境安装
  • CMake、CMakeLists.txt 基础语法
  • Linux系统之Ansible安装与入门
  • WPF,窗口拖动事件与窗口内控件点击事件
  • c++ 中的字符串相关的操作
  • python办自动化--利用vba或者python按需求读取excel文件指定列,更改列名后,按照要求将列排序,最后填充空白单元格
  • k8s中Nvidia节点驱动的配置问题
  • Go 语言-->指针
  • 2025年人工智能三大突破:多模态推理、具身智能与全球治理
  • ATF简介
  • 汽车膨胀水箱(副水箱)液位传感器的作用
  • Linux DNS解析3 -- DNS解析代理配置使用
  • Android 媒体播放开发完全指南
  • 量子计算新势力,微美全息FPGA方案解锁大幅优化与性能提升密码
  • 在Windows下读写Linux EXT文件系统文件
  • 为什么bert是双向transformer
  • vue2 基础学习 day02 (案例、watch侦听器(监视器))
  • API产品升级丨全知科技发布「知影-API风险监测平台」:以AI重构企业数据接口安全治理新范式
  • 深入探索Linux:忙碌的车间“进程”间通信