C++ OpenCV实战之手写数字识别

目录
  • 前言
  • 一、准备数据集
  • 二、KNN训练
  • 三、模型预测及结果显示
  • 四、源码
  • 总结

前言

本案例通过使用machine learning机器学习模块进行手写数字识别。源码注释也写得比较清楚啦,大家请看源码注释!!!

一、准备数据集

原图如图所示:总共有0~9数字类别,每个数字共20个。现在需要将下面图片切分成训练数据图片、测试数据图片。该图片尺寸为560x280,故将其切割成28x28大小数据图片。具体请看源码注释。

	const int classNum = 10;  //总共有0~9个数字类别
	const int picNum = 20;//每个类别共20张图片
	const int pic_w = 28;//图片宽
	const int pic_h = 28;//图片高

	//将数据集分为训练集、测试集
	double totalNum = classNum * picNum;//图片总数
	double per = 0.8;	//百分比--修改百分比可改变训练集、测试集比重
	double trainNum = totalNum * per;//训练图片数量
	double testNum = totalNum * (1.0 - per);//测试图片数量

下面需要将整张图像一一切割成28x28小尺寸图片作为数据集,填充至训练集与测试集。

	Mat Train_Data, Train_Label;//用于训练
	vector<MyNum>TestData;//用于测试
	for (int i = 0; i < picNum; i++)
	{
		for (int j = 0; j < classNum; j++)
		{
			//将所有图片数据都拷贝到Mat矩阵里
			Mat temp;
			gray(Range(j*pic_w, j*pic_w + pic_w), Range(i*pic_h, i*pic_h + pic_h)).copyTo(temp);
			Train_Data.push_back(temp.reshape(0, 1)); //将temp数字图像reshape成一行数据,然后一一追加到Train_Data矩阵中
			Train_Label.push_back(j);

			//而外用于测试
			if (i * classNum + j >= trainNum)
			{
				TestData.push_back({ temp,Rect(i*pic_w,j*pic_h,pic_w,pic_h),j });
			}
		}
	}

接下来就是要将数据集进行格式转换。

    //准备训练数据集
    Train_Data.convertTo(Train_Data, CV_32FC1); //转化为CV_32FC1类型
    Train_Label.convertTo(Train_Label, CV_32FC1);
    Mat TrainDataMat = Train_Data(Range(0, trainNum), Range::all()); //只取trainNum行训练
    Mat TrainLabelMat = Train_Label(Range(0, trainNum), Range::all());

二、KNN训练

这里使用OpenCV中的KNN算法进行训练。

    //KNN训练
    const int k = 3;  //k值,取奇数,影响最终识别率
    Ptr<KNearest>knn = KNearest::create();  //构造KNN模型
    knn->setDefaultK(k);//设定k值
    knn->setIsClassifier(true);//KNN算法可用于分类、回归。
    knn->setAlgorithmType(KNearest::BRUTE_FORCE);//字符匹配算法
    knn->train(TrainDataMat, ROW_SAMPLE, TrainLabelMat);//模型训练

三、模型预测及结果显示

	//预测及结果显示
	double count = 0.0;
	Scalar color;
	for (int i = 0; i < TestData.size(); i++)
	{
		//将测试图片转成CV_32FC1,单行形式
		Mat data = TestData[i].mat.reshape(0, 1);
		data.convertTo(data, CV_32FC1);
		Mat sample = data(Range(0, data.rows), Range::all());

		float f = knn->predict(sample); //预测
		if (f == TestData[i].label)
		{
			color = Scalar(0, 255, 0); //如果预测正确,绘制绿色,并且结果+1
			count++;
		}
		else
		{
			color = Scalar(0, 0, 255);//如果预测错误,绘制红色
		}

		rectangle(src, TestData[i].rect, color, 2);
	}

	//将绘制结果拷贝到一张新图上
	Mat result(Size(src.cols, src.rows + 50), CV_8UC3, Scalar::all(255));
	src.copyTo(result(Rect(0, 0, src.cols, src.rows)));
	//将得分在结果图上显示
	char text[10];
	int score = (count / testNum) * 100;
	sprintf_s(text, "%s%d%s", "Score:", score, "%");
	putText(result, text, Point((result.cols / 2) - 80, result.rows - 15), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 255, 0), 2);
	

如图为不同比重训练集与测试集识别结果。

四、源码

#include<iostream>
#include<opencv2/opencv.hpp>
#include<opencv2/ml.hpp>
using namespace std;
using namespace cv;
using namespace cv::ml;

//**自定义结构体
struct MyNum
{
	cv::Mat mat; //数字图片
	cv::Rect rect;//相对整张图所在矩形
	int label;//数字标签
};

int main()
{
	Mat src = imread("digit.png");
	if (src.empty())
	{
		cout << "No Image..." << endl;
		system("pause");
		return -1;
	}

	Mat gray;
	cvtColor(src, gray, COLOR_BGR2GRAY);

	const int classNum = 10;  //总共有0~9个数字类别
	const int picNum = 20;//每个类别共20张图片
	const int pic_w = 28;//图片宽
	const int pic_h = 28;//图片高

	//将数据集分为训练集、测试集
	double totalNum = classNum * picNum;//图片总数
	double per = 0.8;	//百分比--修改百分比可改变训练集、测试集比重
	double trainNum = totalNum * per;//训练图片数量
	double testNum = totalNum * (1.0 - per);//测试图片数量

	Mat Train_Data, Train_Label;//用于训练
	vector<MyNum>TestData;//用于测试
	for (int i = 0; i < picNum; i++)
	{
		for (int j = 0; j < classNum; j++)
		{
			//将所有图片数据都拷贝到Mat矩阵里
			Mat temp;
			gray(Range(j*pic_w, j*pic_w + pic_w), Range(i*pic_h, i*pic_h + pic_h)).copyTo(temp);
			Train_Data.push_back(temp.reshape(0, 1)); //将temp数字图像reshape成一行数据,然后一一追加到Train_Data矩阵中
			Train_Label.push_back(j);

			//额外用于测试
			if (i * classNum + j >= trainNum)
			{
				TestData.push_back({ temp,Rect(i*pic_w,j*pic_h,pic_w,pic_h),j });
			}
		}
	}

	//准备训练数据集
	Train_Data.convertTo(Train_Data, CV_32FC1); //转化为CV_32FC1类型
	Train_Label.convertTo(Train_Label, CV_32FC1);
	Mat TrainDataMat = Train_Data(Range(0, trainNum), Range::all()); //只取trainNum行训练
	Mat TrainLabelMat = Train_Label(Range(0, trainNum), Range::all());

	//KNN训练
	const int k = 3;  //k值,取奇数,影响最终识别率
	Ptr<KNearest>knn = KNearest::create();  //构造KNN模型
	knn->setDefaultK(k);//设定k值
	knn->setIsClassifier(true);//KNN算法可用于分类、回归。
	knn->setAlgorithmType(KNearest::BRUTE_FORCE);//字符匹配算法
	knn->train(TrainDataMat, ROW_SAMPLE, TrainLabelMat);//模型训练

	//预测及结果显示
	double count = 0.0;
	Scalar color;
	for (int i = 0; i < TestData.size(); i++)
	{
		//将测试图片转成CV_32FC1,单行形式
		Mat data = TestData[i].mat.reshape(0, 1);
		data.convertTo(data, CV_32FC1);
		Mat sample = data(Range(0, data.rows), Range::all());

		float f = knn->predict(sample); //预测
		if (f == TestData[i].label)
		{
			color = Scalar(0, 255, 0); //如果预测正确,绘制绿色,并且结果+1
			count++;
		}
		else
		{
			color = Scalar(0, 0, 255);//如果预测错误,绘制红色
		}

		rectangle(src, TestData[i].rect, color, 2);
	}

	//将绘制结果拷贝到一张新图上
	Mat result(Size(src.cols, src.rows + 50), CV_8UC3, Scalar::all(255));
	src.copyTo(result(Rect(0, 0, src.cols, src.rows)));
	//将得分在结果图上显示
	char text[10];
	int score = (count / testNum) * 100;
	sprintf_s(text, "%s%d%s", "Score:", score, "%");
	putText(result, text, Point((result.cols / 2) - 80, result.rows - 15), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 255, 0), 2);
	imshow("test", result);
	imwrite("result.jpg", result);
	waitKey(0);
	system("pause");
	return 0;
}

总结

本文使用OpenCV C++ 利用ml模块进行手写数字识别,源码注释也比较详细,主要操作有以下几点。

1、数据集划分为训练集与测试集

2、进行KNN训练

3、进行模型预测以及结果显示

以上就是C++ OpenCV实战之手写数字识别的详细内容,更多关于C++ OpenCV手写数字识别的资料请关注我们其它相关文章!

(0)

相关推荐

  • 如何基于opencv实现简单的数字识别

    目录 前言 要解决的问题 解决问题的思路 总结 前言 由于自己学识尚浅,不能用python深度学习来识别这里的数字,所以就完全采用opencv来识别数字,然后在这里分享.记录一下自己在学习过程中的一些所见所得和所想 要解决的问题 这是一个要识别的数字,我这里首先是对图像进行一个ROI的提取,提取结果就仅仅剩下数字,把其他的一些无关紧要的要素排除在外, 这是ROI图片,我们要做的就是识别出该照片中的数字, 解决问题的思路 1.先把这个图片中的数字分割,分割成为5张小图片,每张图片包含一个数字,为啥

  • Python-OpenCV实战:利用 KNN 算法识别手写数字

    目录 前言 手写数字数据集 MNIST 介绍 基准模型--利用 KNN 算法识别手写数字 改进模型1--参数 K 对识别手写数字精确度的影响 改进模型2--训练数据量对识别手写数字精确度的影响 改进模型3--预处理对识别手写数字精确度的影响 改进模型4--使用高级描述符作为图像特征提高 KNN 算法准确率 完整代码 相关链接 前言 K-最近邻 (k-nearest neighbours, KNN) 是监督学习中最简单的算法之一,KNN 可用于分类和回归问题,在博文<Python OpenCV实战

  • OpenCV简单标准数字识别的完整实例

    在学习openCV时,看到一个问答做数字识别,里面配有代码,应用到了openCV里面的ml包,很有学习价值. https://stackoverflow.com/questions/9413216/simple-digit-recognition-ocr-in-opencv-python# import sys import numpy as np import cv2 im = cv2.imread('t.png') im3 = im.copy() gray = cv2.cvtColor(im

  • Python+Opencv实现数字识别的示例代码

    一.什么是数字识别?   所谓的数字识别,就是使用算法自动识别出图片中的数字.具体的效果如下图所示: 上图展示了算法的处理效果,算法能够自动的识别到LCD屏幕上面的数字,这在现实场景中具有很大的实际应用价值.下面我们将对它的实现细节进行详细解析. 二.如何实现数字识别?   对于数字识别这个任务而言,它并不是一个新的研究方向,很久之前就有很多的学者们在关注这个问题,并提出了一些可行的解决方案,本小节我们将对这些方案进行简单的总结. 方案一:使用现成的OCR技术. OCR,即文字识别,它是一个比较

  • 详解Python OpenCV数字识别案例

    前言 实践是检验真理的唯一标准. 因为觉得一板一眼地学习OpenCV太过枯燥,于是在网上找了一个以项目为导向的教程学习.话不多说,动手做起来. 一.案例介绍 提供信用卡上的数字模板: 要求:识别出信用卡上的数字,并将其直接打印在原图片上.虽然看起来很蠢,但既然可以将数字打印在图片上,说明已经成功识别数字,因此也可以将其转换为数字文本保存.车牌号识别等项目的思路与此案例类似. 示例: 原图 处理后的图 二.步骤 大致分为如下几个步骤: 1.模板读入 2.模板预处理,将模板数字分开,并排序 3.输入

  • python基于OpenCV模板匹配识别图片中的数字

    前言 本博客主要实现利用OpenCV的模板匹配识别图像中的数字,然后把识别出来的数字输出到txt文件中,如果识别失败则输出"读取失败". 操作环境: OpenCV - 4.1.0 Python 3.8.1 程序目标 单个数字模板:(这些单个模板是我自己直接从图片上截取下来的) 要处理的图片: 终端输出: 文本输出: 思路讲解 代码讲解 首先定义两个会用到的函数 第一个是显示图片的函数,这样的话在显示图片的时候就比较方便了 def cv_show(name, img): cv2.imsh

  • C++ OpenCV实战之手写数字识别

    目录 前言 一.准备数据集 二.KNN训练 三.模型预测及结果显示 四.源码 总结 前言 本案例通过使用machine learning机器学习模块进行手写数字识别.源码注释也写得比较清楚啦,大家请看源码注释!!! 一.准备数据集 原图如图所示:总共有0~9数字类别,每个数字共20个.现在需要将下面图片切分成训练数据图片.测试数据图片.该图片尺寸为560x280,故将其切割成28x28大小数据图片.具体请看源码注释. const int classNum = 10; //总共有0~9个数字类别

  • 机器学习python实战之手写数字识别

    看了上一篇内容之后,相信对K近邻算法有了一个清晰的认识,今天的内容--手写数字识别是对上一篇内容的延续,这里也是为了自己能更熟练的掌握k-NN算法. 我们有大约2000个训练样本和1000个左右测试样本,训练样本所在的文件夹是trainingDigits,测试样本所在的文件夹是testDigits.文本文件中是0~9的数字,但是是用二值图表示出来的,如图.我们要做的就是使用训练样本训练模型,并用测试样本来检测模型的性能. 首先,我们需要将文本文件中的内容转化为向量,因为图片大小是32*32,所以

  • PyTorch CNN实战之MNIST手写数字识别示例

    简介 卷积神经网络(Convolutional Neural Network, CNN)是深度学习技术中极具代表的网络结构之一,在图像处理领域取得了很大的成功,在国际标准的ImageNet数据集上,许多成功的模型都是基于CNN的. 卷积神经网络CNN的结构一般包含这几个层: 输入层:用于数据的输入 卷积层:使用卷积核进行特征提取和特征映射 激励层:由于卷积也是一种线性运算,因此需要增加非线性映射 池化层:进行下采样,对特征图稀疏处理,减少数据运算量. 全连接层:通常在CNN的尾部进行重新拟合,减

  • Python实战小项目之Mnist手写数字识别

    目录 程序流程分析图: 传播过程: 代码展示: 创建环境 准备数据集 下载数据集 下载测试集 绘制图像 搭建神经网络 训练模型 测试模型 保存训练模型 运行结果展示: 程序流程分析图: 传播过程: 代码展示: 创建环境 使用<pip install+包名>来下载torch,torchvision包 准备数据集 设置一次训练所选取的样本数Batch_Sized的值为512,训练此时Epochs的值为8 BATCH_SIZE = 512 EPOCHS = 8 device = torch.devi

  • Python实战之MNIST手写数字识别详解

    目录 数据集介绍 1.数据预处理 2.网络搭建 3.网络配置 关于优化器 关于损失函数 关于指标 4.网络训练与测试 5.绘制loss和accuracy随着epochs的变化图 6.完整代码 数据集介绍 MNIST数据集是机器学习领域中非常经典的一个数据集,由60000个训练样本和10000个测试样本组成,每个样本都是一张28 * 28像素的灰度手写数字图片,且内置于keras.本文采用Tensorflow下Keras(Keras中文文档)神经网络API进行网络搭建. 开始之前,先回忆下机器学习

  • Python(TensorFlow框架)实现手写数字识别系统的方法

    手写数字识别算法的设计与实现 本文使用python基于TensorFlow设计手写数字识别算法,并编程实现GUI界面,构建手写数字识别系统.这是本人的本科毕业论文课题,当然,这个也是机器学习的基本问题.本博文不会以论文的形式展现,而是以编程实战完成机器学习项目的角度去描述. 项目要求:本文主要解决的问题是手写数字识别,最终要完成一个识别系统. 设计识别率高的算法,实现快速识别的系统. 1 LeNet-5模型的介绍 本文实现手写数字识别,使用的是卷积神经网络,建模思想来自LeNet-5,如下图所示

  • C++学习贝叶斯分类器实现手写数字识别示例解析

    大家好啊!这次的文章是上一个文章的后续,与上一次不同的是,这一次对数字识别采用的是贝叶斯(Bayes)分类器.贝叶斯在概率论与数理统计这门课讲过,下面我们简单了解一下: 首先,贝叶斯公式是 具体的解释就不说了,我们说一说把贝叶斯用在数字识别的什么位置.除了识别部分,其他的包括遍历文件夹和图片数字化都不变:0到9共十个数,所以分母有十项,P(Bj)(j是下标)相应的是0到9,则每一个的概率是1/10,分子上的P(Bi)是取到0到9中的一个,所以概率也是1/10. (小伙伴如果看不明白建议去看看贝叶

  • python实现基于SVM手写数字识别功能

    本文实例为大家分享了SVM手写数字识别功能的具体代码,供大家参考,具体内容如下 1.SVM手写数字识别 识别步骤: (1)样本图像的准备. (2)图像尺寸标准化:将图像大小都标准化为8*8大小. (3)读取未知样本图像,提取图像特征,生成图像特征组. (4)将未知测试样本图像特征组送入SVM进行测试,将测试的结果输出. 识别代码: #!/usr/bin/env python import numpy as np import mlpy import cv2 print 'loading ...'

  • 详解PyTorch手写数字识别(MNIST数据集)

    MNIST 手写数字识别是一个比较简单的入门项目,相当于深度学习中的 Hello World,可以让我们快速了解构建神经网络的大致过程.虽然网上的案例比较多,但还是要自己实现一遍.代码采用 PyTorch 1.0 编写并运行. 导入相关库 import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torchvision import datasets, t

  • Python使用gluon/mxnet模块实现的mnist手写数字识别功能完整示例

    本文实例讲述了Python使用gluon/mxnet模块实现的mnist手写数字识别功能.分享给大家供大家参考,具体如下: import gluonbook as gb from mxnet import autograd,nd,init,gluon from mxnet.gluon import loss as gloss,data as gdata,nn,utils as gutils import mxnet as mx net = nn.Sequential() with net.nam

随机推荐