opencv进阶06-基于K邻近算法识别手写数字示例

opencv 中 K 近邻模块的基本使用说明及示例

在 OpenCV 中,不需要自己编写复杂的函数实现 K 近邻算法,直接调用其自带的模块函数即可。本节通过一个简单的例子介绍如何使用 OpenCV 自带的 K 近邻模块。

本例中有两组位于不同位置的用于训练的数据集,如图 20-14 所示。两组数据集中,一组位于左下角;另一组位于右上角。随机生成一个数值,用 OpenCV 中的 K 近邻模块判断该随机数属于哪一个分组。

在这里插入图片描述
上述两组数据中,位于左下角的一组数据,其 x、y 坐标值都在(0, 30)范围内。位于右上角的数据,其 x、y 坐标值都在(70, 100)范围内。

根据上述分析,创建两组数据,每组包含 20 对随机数(20 个随机数据点):

rand1 = np.random.randint(0, 30, (20, 2)).astype(np.float32)
rand2 = np.random.randint(70, 100, (20, 2)).astype(np.float32)
  • 第 1 组随机数 rand1 中,其 x、y 坐标值均位于(0, 30)区间内。
  • 第 2 组随机数 rand2 中,其 x、y 坐标值均位于(70, 100)区间内。
    接下来,为两组随机数分配标签:
  • 将第 1 组随机数对划分为类型 0,标签为 0。
  • 将第 2 组随机数对划分为类型 1,标签为 1。

然后,生成一对值在(0, 100)内的随机数对:

test = np.random.randint(0, 100, (1, 2)).astype(np.float32)

示例:使用 OpenCV 自带的 K 近邻模块判断生成的随机数对 test 是属于 rand1 所在的类型0,还是属于 rand2 所在的类型 1。

import cv2
import numpy as np
import matplotlib.pyplot as plt
# 用于训练的数据
# rand1 数据位于(0,30)
rand1 = np.random.randint(0, 30, (20, 2)).astype(np.float32)
# rand2 数据位于(70,100)
rand2 = np.random.randint(70, 100, (20, 2)).astype(np.float32)
# 将 rand1 和 rand2 拼接为训练数据
trainData = np.vstack((rand1, rand2))
# 数据标签,共两类:01
# r1Label 对应着 rand1 的标签,为类型 0
r1Label=np.zeros((20,1)).astype(np.float32)
# r2Label 对应着 rand2 的标签,为类型 1
r2Label=np.ones((20,1)).astype(np.float32)
tdLable = np.vstack((r1Label, r2Label))
# 使用绿色标注类型 0
g = trainData[tdLable.ravel() == 0]
plt.scatter(g[:,0], g[:,1], 80, 'g', 'o')
# 使用蓝色标注类型 1
b = trainData[tdLable.ravel() == 1]
plt.scatter(b[:,0], b[:,1], 80, 'b', 's')
# plt.show()
# test 为用于测试的随机数,该数在 0100 之间
test = np.random.randint(0, 100, (1, 2)).astype(np.float32)
plt.scatter(test[:,0], test[:,1], 80, 'r', '*')
# 调用 OpenCV 内的 K 近邻模块,并进行训练
knn = cv2.ml.KNearest_create()
knn.train(trainData, cv2.ml.ROW_SAMPLE, tdLable)
# 使用 K 近邻算法分类
ret, results, neighbours, dist = knn.findNearest(test, 5)
# 显示处理结果
print("当前随机数可以判定为类型:", results)
print("距离当前点最近的 5 个邻居是:", neighbours)
print("5 个最近邻居的距离: ", dist)
# 可以观察一下显示,对比上述输出
plt.show()

运行结果:

当前随机数可以判定为类型: [[1.]]
距离当前点最近的 5 个邻居是: [[1. 1. 1. 1. 1.]]
5 个最近邻居的距离:  [[  5.  17. 113. 136. 178.]]

在这里插入图片描述
从图中可以看出,随机点(星号点)距离右侧小方块(类型为 1)的点更近,因此被判定为属于小方块的类型 1。

示例:使用 OpenCV 自带的函数完成对手写数字的识别

图片集在05 节中有下载地址

import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取样本(特征)图像的值
s='image_number\\' # 图像所在的路径
num=100 # 共有的样本数量row=240 # 特征图像的行数
col=240 # 特征图像的列数
a=np.zeros((num,row,col)) # 存储所有样本的数值n=0 # 用来存储当前图像的编号for i in range(0,10):for j in range(1,11):a[n,:,:]=cv2.imread(s+str(i)+'\\'+str(i)+'-'+str(j)+'.bmp',0)n=n+1# 提取样本图像的特征
feature=np.zeros((num,round(row/5),round(col/5))) # 用来存储所有样本的特征值
#print(feature.shape) # 看看特征值的形状是什么样子
#print(row) # 看看 row 的值,有多少个特征值(100
# 从 0 开始,到 num-1 结束,每次加 1,
for ni in range(0,num):for nr in range(0,row):for nc in range(0,col):if a[ni,nr,nc]==255:feature[ni,int(nr/5),int(nc/5)]+=1
f = feature  #简化变量名称
# 将 feature 处理为单行形式,并转换为 float32 类型,以便后面的 kNN 算法使用
train = feature[:,:].reshape(-1,round(row/5)*round(col/5)).astype(np.float32)print(train.shape)
# 贴标签,要注意,是 range(0,100)而非 range(0,101)
train_labels = [int(i/10) for i in range(0,100)]
train_labels = np.asarray(train_labels)
test_labels = train_labels.copy()
#print(*trainLabels) # 打印测试看看标签值
##读取图像值,并提取特征,以便后面的 kNN 算法使用,这里只读取一个图像,即待识别图像,所以只有一个特征值,即 test
o=cv2.imread('image_number\\test\\5.bmp',0) # 读取待识别图像
of=np.zeros((round(row/5),round(col/5))) # 用来存储待识别图像的特征值
for nr in range(0,row):for nc in range(0,col):if o[nr,nc]==255:of[int(nr/5),int(nc/5)]+=1
# 将 of 处理为单行形式,并转换为 float32 类型,以便后面的 kNN 算法使用
test=of.reshape(-1,round(row/5)*round(col/5)).astype(np.float32)# 调用函数识别图像
knn=cv2.ml.KNearest_create()
knn.train(train,cv2.ml.ROW_SAMPLE, train_labels)ret,result,neighbours,dist = knn.findNearest(test,k=5)print("当前随机数可以判定结果是:", str(result[0][0]))
print("距离当前点最近的 5 个邻居是:", neighbours)
print("5 个最近邻居的距离: ", dist)

运行结果:

当前随机数可以判定结果是: 5.0
距离当前点最近的 5 个邻居是: [[5. 3. 5. 3. 5.]]
5 个最近邻居的距离:  [[77185. 78375. 79073. 79948. 82151.]]

咂一看,哎呦!结果还挺准,然后再测试下其他的数字图片呢?

o=cv2.imread('image_number\\test\\6.bmp',0) # 读取待识别图像

再看下效果,

当前随机数可以判定结果是: 1.0
距离当前点最近的 5 个邻居是: [[6. 1. 1. 1. 1.]]
5 个最近邻居的距离:  [[90739. 92107. 92312. 92652. 93016.]]

连续改了几个,发现识别准备度还是很低的。

示例:接下来我们借用MNIST数据集再次来验证下。

第一步:下载数据集,训练模型,保存模型到本地

代码如下:

import cv2
import numpy as np
from keras.datasets import mnistif __name__ == '__main__':# 直接使用Keras载入的训练数据(60000, 28, 28) (60000,)(train_images, train_labels), (test_images, test_labels) = mnist.load_data()# 变换数据的形状并归一化train_images = train_images.reshape(train_images.shape[0], -1)  # (60000, 784)train_images = train_images.astype('float32') / 255test_images = test_images.reshape(test_images.shape[0], -1)test_images = test_images.astype('float32') / 255print(test_images)# 将标签数据转为float32train_labels = train_labels.astype(np.float32)test_labels = test_labels.astype(np.float32)# 传入knn的训练数据形状为(60000, 784) 训练标签为(60000,)# 创建knn对象knn = cv2.ml.KNearest_create()# 设置k值 默认的k=10knn.setDefaultK(5)# 设置是分类还是回归knn.setIsClassifier(True)# 开始训练,训练数据的形状为(60000, 784) 训练标签为(60000,),训练数据必须是float32类型,标签必须是int32类型,并且标签必须是单通道,不能是多通道,否则会报错knn.train(train_images, cv2.ml.ROW_SAMPLE, train_labels)# 手写数字识别保存的knn模型非常大 有两百多兆knn.save('mnist_knn.xml')# 进行模型准确率的测试 结果是一个元组 第一个值为数据1的结果test_pre = knn.predict(test_images)test_ret = test_pre[1]# 计算准确率test_ret = test_ret.reshape(-1, )test_sum = (test_ret == test_labels)print(test_sum)acc = test_sum.mean()print(acc)

验证模型:

import cv2
import numpy as npif __name__=='__main__':#读取图片img=cv2.imread('D:\\ai\\test\\6.png', 0)  # 读取待识别图像#重新设置图片大小img=cv2.resize(img,(28,28))cv2.imshow('img',img)img_sw=img.copy()#将数据类型由uint8转为float32img=img.astype(np.float32)#图片形状由(28,28)转为(784,)img=img.reshape(-1,)#增加一个维度变为(1,784)img=img.reshape(1,-1)#图片数据归一化img=img/255#载入knn模型knn=cv2.ml.KNearest_load('mnist_knn.xml')#进行预测img_pre=knn.predict(img)print('img_pre:',img_pre)print(img_pre[0])cv2.waitKey()cv2.destroyAllWindows()

运行结果:

在这里插入图片描述
这里测试的图片是mnist 数据集中的,这个数据集下载的是压缩的,如要验证需要从下面的图片中去截图单独保存下来自己验证。总体准确率还是比较高的。**但是如果是自己随便画个数字再来验证 准备率就比较低了。**感兴趣的朋友可以自己多试试。

显示下面图片的代码

import cv2
import numpy as np
from keras.datasets import mnist
from matplotlib import pyplot as plt# 加载数据
(train_dataset, train_labels), (test_dataset, test_labels) = mnist.load_data()
train_labels = np.array(train_labels, dtype=np.int32)
# 打印数据集形状
print(train_dataset.shape, test_dataset.shape)
# 图像预览
for i in range(40):plt.subplot(4, 10, i+1)plt.imshow(train_dataset[i], cmap='gray')plt.title(train_labels[i], fontsize=10)plt.axis('off')
plt.show()

在这里插入图片描述

缺点:模型文件大,识别速度慢

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

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

相关文章

人工智能学习框架—飞桨Paddle人工智能

1.人工智能框架 机器学习的三要素:模型、学习策略、优化算法。 当我们用机器学习来解决一些模式识别任务时,一般的流程包含以下几个步骤: 1.1.浅层学习和深度学习 浅层学习(Shallow Learning):不涉及特征学习,其特征…

没学C++,如何从C语言丝滑过度到python【python基础万字详解】

大家好,我是纪宁。 文章将从C语言出发,深入介绍python的基础知识,也包括很多python的新增知识点详解。 文章目录 1.python的输入输出,重新认识 hello world,重回那个激情燃烧的岁月1.1 输出函数print的规则1.2 输入函…

工厂方法模式【Factory Method Pattern】

前言 1.工厂模式概念 实例化对象,用工厂方法代替new操作(重点) 工厂模式包括工厂方法模式和抽象工厂模式 抽象工厂模式是工厂方法模式的扩展 2.什么情况下适合工厂模式 有一组类似的对象需要创建 在编码时不能预见需要创建哪种类的实例 系统需要考虑扩展性&#xff…

Markdown编辑器 Mac版Typora功能介绍

Typora mac是一款跨平台的Markdown编辑器,支持Windows、MacOS和Linux操作系统。它具有实时预览功能,能够自动将Markdown文本转换为漂亮的排版效果,让用户专注于写作内容而不必关心格式调整。 Typora Mac版除了支持常见的Markdown语法外&#…

ARM-M0内核MCU,内置24bit ADC,采样率4KSPS,传感器、电子秤、体脂秤专用,国产IC

ARM-M0内核MCU 内置24bit ADC ,采样率4KSPS flash 64KB,SRAM 32KB 适用于传感器,电子秤,体脂秤等等

关于视频监控平台EasyCVR视频汇聚平台建设“明厨亮灶”具体实施方案以及应用

一、方案背景 近几年来,餐饮行业的食品安全、食品卫生等新闻频频发生,比如某火锅店、某网红奶茶,食材以次充好、后厨卫生被爆堪忧,种种问题引起大众关注和热议。这些负面新闻不仅让餐饮门店的品牌口碑暴跌,附带的连锁…

DRF 缓存

应用环境 django4.2.3 ,python3.10 由于对于服务而言,有些数据查询起来比较费时,所以,对于有些数据,我们需要将其缓存。 最近做了一个服务,用的时 DRF 的架构,刚好涉及缓存,特此记…

瓴羊发布All in One 产品,零售SaaS的尽头是DaaS?

“打破烟囱、化繁为简,让丰富的能力、数据和智能All in One”,这是瓴羊新发布的产品瓴羊One承担的使命,也意味着瓴羊DaaS事业迈入了一个新阶段。 成立伊始,瓴羊就打出了“Not SaaS,But DaaS”旗号,将自己的…

《论文阅读14》FAST-LIO

一、论文 研究领域:激光雷达惯性测距框架论文:FAST-LIO: A Fast, Robust LiDAR-inertial Odometry Package by Tightly-Coupled Iterated Kalman Filter IEEE Robotics and Automation Letters, 2021 香港大学火星实验室 论文链接论文github 二、论文概…

vue组件封装——类似bootstraptable的模糊搜索功能,支持语音搜索

插件地址 懒得写了,直接上插件地址去看吧

Hyperledger Fabric的使用及开发

Hyperledger Fabric是Linux基金会发起的一种跨行业的区块链技术,目前在多家大型公司有着应用,这里就不多做HF本身的介绍了,有兴趣可关注其官网。 1. 准备工作: 开始前需要一定的准备工作,安装各类中间件:…

安防监控视频云存储平台EasyCVRH.265转码功能更新:新增分辨率配置

安防视频集中存储EasyCVR视频监控综合管理平台可以根据不同的场景需求,让平台在内网、专网、VPN、广域网、互联网等各种环境下进行音视频的采集、接入与多端分发。在视频能力上,视频云存储平台EasyCVR可实现视频实时直播、云端录像、视频云存储、视频存储…