【OpenCV/C++】KNN算法识别数字的实现原理与代码详解
KNN算法识别数字
- 一、KNN原理
- 1.1 KNN原理介绍
- 1.2 KNN的关键参数
- 二、KNN算法识别手写数字
- 2.1 训练过程代码详解
- 2.2 预测分类的实现过程
- 三、KNN算法识别印刷数字
- 2.1 训练过程
一、KNN原理
1.1 KNN原理介绍
KNN算法,即K最近邻算法,顾名思义其原理是当要预测一个新的值x的时候,根据离他最近的K个点大多属于什么类别来判断x属于哪个类别。
zzzzMing -大数据技术-深入浅出KNN算法 K=3时,x最近的三个图形包括两个三角形、一个圆形,因为2>1,所以x更有可能是三角形。
K=5时,x最近的五个图形包括两个三角形、三个圆形,因为3>2,所以x更有可能是圆形。
同理类比到图像识别方面,使用KNN算法前我们需要有大量的训练样本,并且知道每个样本所属的类别。(例如大量的数字图片,并且知道每个图片代表数字几)。当我们要识别数字时,本质上就是在训练样本中找与要识别的图像最接近的K个样本,然后统计出K个样本中出现最多的数字是哪个,那就是要识别的数字。
1.2 KNN的关键参数
① 寻找多少最近邻样本 - K的选择
K值决定着图像识别过程中,寻找的最近邻的图像个数,由上面的例子可以看出,选择不同的K,识别结果可能完全不同,因此K值是KNN算法中最关键的参数之一,它直接影响着模型的性能。
K值如果过小,那么此时识别结果就会很受样本质量的影响。如果训练样本存在某些错误或噪音,而寻找最近邻样本时正好找到了这些项,那么识别结果一定是错的,而增大K值,多寻找样本,会有效降低样本噪音的影响。
K值如果过大,假设K值等于训练样本数,那么无论要识别的图片是什么,识别结果都是样本中最多的那个类别。
那么K值应该如何选择呢?理论上来说K值与识别准确率的关系是存在一个极值的,可以通过多次实验,根据结果选择一个最好的K值。(例如K=3时准确率72;K=5时准确率91;K=8时准确率81,那么选择K=5会是一个相对较好的选择)
② 如何判断“接近”程度 - 距离的计算
距离计算函数一般使用曼哈顿距离或欧氏距离。
曼哈顿距离就是样本特征每一个维度的差值之合。(对应于图像,就是两图像每个像素做差)
欧式距离是样本特征在每一个维度上差值的平方和的根。
二、KNN算法识别手写数字
KNN算法识别手写数字的源程序 - 点此下载
注:只包括KNN算法部分,关于图片ROI区域截取请参考《一文详解opencv摄像头数字识别》
2.1 训练过程代码详解
首先,我们要获得训练样本。OpenCV安装目录中给我们提供了手写数字的样本图片opencv\sources\samples\data\digits.png
。这个图片中每个数字有5x100个样本,并且每个数字所占的像素均为20x20,因此可以从这个图片中提取我们需要的训练样本。
我们按列裁剪样本图片,每裁剪一个样本,就将其添加到data中,并同时将对应的数字添加到lable中。这样一来,我们就获得了图片和数字一一对应的data和lable数据。
Mat img = imread("E:/Program/OpenCV/vcworkspaces/knn_test/images/data/digits.png");Mat gray;cvtColor(img, gray, COLOR_BGR2GRAY);int b = 20;int m = gray.rows / b; //原图为1000*2000int n = gray.cols / b; //裁剪为5000个20*20的小图块Mat data, labels; //特征矩阵for (int i = 0; i < n; i++){int offsetCol = i * b; //列上的偏移量for (int j = 0; j < m; j++){int offsetRow = j * b; //行上的偏移量//截取20*20的小块Mat tmp;gray(Range(offsetRow, offsetRow + b), Range(offsetCol, offsetCol + b)).copyTo(tmp);//reshape 0:通道不变 其他数字,表示要设置的通道数//reshape 表示矩阵行数,如果设置为0,则表示保持原有行数不变,如果设置为其他数字,表示要设置的行数data.push_back(tmp.reshape(0, 1)); //序列化后放入特征矩阵labels.push_back((int)j / 5); //对应的标注}}
利用这个训练样本就可以创建KNN模型了。
如果需要测试模型的识别准确度,可以从刚才获得的5000个样本中,选择前3000个样本作为训练数据,后2000个作为测试数据。用KNN模型计算测试数据的在样本中的识别正确情况。
data.convertTo(data, CV_32F); //uchar型转换为cv_32fint samplesNum = data.rows;int trainNum = 500;Mat trainData, trainLabels;trainData = data(Range(0, trainNum), Range::all()); //前3000个样本为训练数据trainLabels = labels(Range(0, trainNum), Range::all());//使用KNN算法int K = 5;Ptr<TrainData> tData = TrainData::create(trainData, ROW_SAMPLE, trainLabels);model = KNearest::create();model->setDefaultK(K);model->setIsClassifier(true);model->train(tData);//预测分类double train_hr = 0, test_hr = 0;Mat response;// compute prediction error on train and test datafor (int i = 0; i < samplesNum; i++){Mat sample = data.row(i);float r = model->predict(sample); //对所有行进行预测//预测结果与原结果相比,相等为1,不等为0r = std::abs(r - labels.at<int>(i)) <= FLT_EPSILON ? 1.f : 0.f;if (i < trainNum)train_hr += r; //累积正确数elsetest_hr += r;}test_hr /= samplesNum - trainNum;train_hr = trainNum > 0 ? train_hr / trainNum : 1.;printf("accuracy: train = %.1f%%, test = %.1f%%\n",train_hr * 100., test_hr * 100.);
2.2 预测分类的实现过程
训练样本制作完毕后,预测分类就非常简单了,将要识别的图像读取进来,进行二值化处理,然后调整大小到与样本图片一样大(20x20)。将处理好的图片push到test中,就可以直接使用刚才创建的KNN模型进行预测了。
//预测分类Mat img = imread("E:/Program/OpenCV/vcworkspaces/knn_test/images/test/4.jpg");cvtColor(img, img, COLOR_BGR2GRAY);//threshold(src, src, 0, 255, CV_THRESH_OTSU);imshow("Image", img);resize(img, img, Size(20, 20));Mat test;test.push_back(img.reshape(0, 1));test.convertTo(test, CV_32F);int result = model->predict(test);cout << "识别数字:" << result << endl;
三、KNN算法识别印刷数字
KNN算法识别印刷数字的源程序 -点此下载
注:只包括KNN算法部分,关于图片ROI区域截取请参考《一文详解opencv摄像头数字识别》
2.1 训练过程
识别印刷体数字与识别手写数字的原理相同,只是训练样本有区别。这里我制作了1000张不同字体的训练样本,加载方式例如:
//训练结果不存在,重新训练int add_image_num = 1000; //扩充训练数据的文件夹个数int filenum = 0;Mat data, labels; //特征矩阵for (int i = 0; i < add_image_num; i++){Mat addimg = imread("E:/Program/OpenCV/vcworkspaces/knn_test/images/data/" + to_string(filenum) + ".jpg");cvtColor(addimg, addimg, COLOR_BGR2GRAY);//threshold(src, src, 0, 255, CV_THRESH_OTSU);resize(addimg, addimg, Size(20, 20));data.push_back(addimg.reshape(0, 1)); //序列化后放入特征矩阵labels.push_back((int)((filenum++) % 10)); //对应的标注}
训练样本加载完毕后,使用与上面相同的方式创建KNN模型,然后进行预测识别即可。
【OpenCV/C++】KNN算法识别数字的实现原理与代码详解相关推荐
- 人脸识别SeetaFace2原理与代码详解
人脸识别SeetaFace2原理与代码详解 前言 一.人脸识别步骤 二.SeetaFace2基本介绍 三.seetaFace2人脸注册.识别代码详解 3.1 人脸注册 3.1.1 人脸检测 3.1.2 ...
- BilSTM 实体识别_NLP-入门实体命名识别(NER)+Bilstm-CRF模型原理Pytorch代码详解——最全攻略
最近在系统地接触学习NER,但是发现这方面的小帖子还比较零散.所以我把学习的记录放出来给大家作参考,其中汇聚了很多其他博主的知识,在本文中也放出了他们的原链.希望能够以这篇文章为载体,帮助其他跟我一样 ...
- BilSTM 实体识别_NLP入门实体命名识别(NER)+BilstmCRF模型原理Pytorch代码详解——最全攻略...
来自 | 知乎 作者 | seven链接 | https://zhuanlan.zhihu.com/p/79552594编辑 | 机器学习算法与自然语言处理公众号本文仅作学术分享,如有侵权,请联系 ...
- 干货 | OpenCV看这篇就够了,9段代码详解图像变换基本操作
作者 | 王天庆,长期从事分布式系统.数据科学与工程.人工智能等方面的研究与开发,在人脸识别方面有丰富的实践经验.现就职某世界100强企业的数据实验室,从事数据科学相关技术领域的预研工作. 来源 | ...
- 读书笔记-深度学习入门之pytorch-第五章(含循环实现手写数字识别)(LSTM、GRU代码详解)
目录 1.RNN优点:(记忆性) 2.循环神经网络结构与原理 3.LSTM(长短时记忆网络) 4.GRU 5.LSTM.RNN.GRU区别 6.收敛性问题 7.循环神经网络Pytorch实现 (1)R ...
- KNN算法原理和代码详解
原理 有这样一条河流like that,河流的左边是rich 人家,河流的右边是poor 人家,这时新搬来一家小甲,这个算法是看小甲是有钱人家还是没钱人家. 要解决这个问题,那么就可以说立着他最近的几 ...
- 【MATLAB】Parzen窗与K近邻算法原理与代码详解
文章目录 1.非参数估计原理 2.Parzen窗 2.1.算法原理 2.2.Matlab实现与参数探究 3.K近邻 3.1.算法原理 3.2.Matlab实现与参数探究 1.非参数估计原理 \qqua ...
- 高能干货:OpenCV看这篇就够了,9段代码详解图像变换基本操作
导读:OpenCV是一个以BSD许可证开源的.跨平台的计算机视觉库.它提供了Python.C++.Java.Matlab等多种编程语言接口.它集成了很多计算机视觉算法,具有非常强大的功能,是计算机视觉 ...
- K均值(K-means)聚类算法原理与代码详解
0. 算法原理: 上述过程简单描述: a: 初始数据 b: 选择质点 c: 根据质点划分 d: 求均值,更新质心点 e: 划分 f: 更新质心点 1. 代码实现: # K means 教程# 0. 引 ...
最新文章
- Python标准库threading模块Condition原理浅析
- 我十年学习编程的历史
- 下载python后怎样打开-下载python后如何启动
- Streaming的算法Reservoir Sampling
- Java – 2012年回顾和未来预测
- LeetCode 97. 交错字符串(DP)
- 12.12 带触发器按钮的输入框
- php fpm 平滑重启,nginx、php-fpm平滑重启和重载配置
- 自动服务器批量装机,PXE高效批量网络装机
- 6月第二周国内域名解析商Top10:万网份额突破21%
- android自定义View之曲线图
- android View使用shape作为背景不能指定单边圆角的xml
- NonEmpty和Hierarchize嵌套的bug
- MTK平台上电话黑名单功能总结
- 联想Y7000装双系统win10+Ubuntu16.04后在Ubuntu上Wifi被禁用的解决办法
- JS编写 简易网页音乐播放器
- 网站速度和性能测试工具
- 积分商城开发及小程序积分商城功能介绍
- MFC中关于char[]转换成LPCWSTR的问题
- 【XSY2808】董先生的休闲方案 组合数学
热门文章
- bzoj 4443: [Scoi2015]小凸玩矩阵(二分+二分匹配)
- opencv 图像基本操作 像素值的获取、图像大小、ROI、通道分割与合并等
- C++ STL vector容器的插入和删除
- [bug解决] Ubantu打不开Typora:typora error while loading shared libraries libXss.so.1
- [高光谱] 在开源项目Hyperspectral-Classification Pytorch中加入自己的网络
- c#软件操作-cmd命令全解
- Python:Numpy库中的invert()函数的用法
- A1136 | 字符串处理、大整数运算
- C#多线程之线程池篇1
- SQL2005安装及链接