我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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

前言

本案例通过使用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(class="lazy" data-src, TestData[i].rect, color, 2);
	}

	//将绘制结果拷贝到一张新图上
	Mat result(Size(class="lazy" data-src.cols, class="lazy" data-src.rows + 50), CV_8UC3, Scalar::all(255));
	class="lazy" data-src.copyTo(result(Rect(0, 0, class="lazy" data-src.cols, class="lazy" data-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 class="lazy" data-src = imread("digit.png");
	if (class="lazy" data-src.empty())
	{
		cout << "No Image..." << endl;
		system("pause");
		return -1;
	}

	Mat gray;
	cvtColor(class="lazy" data-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(class="lazy" data-src, TestData[i].rect, color, 2);
	}

	//将绘制结果拷贝到一张新图上
	Mat result(Size(class="lazy" data-src.cols, class="lazy" data-src.rows + 50), CV_8UC3, Scalar::all(255));
	class="lazy" data-src.copyTo(result(Rect(0, 0, class="lazy" data-src.cols, class="lazy" data-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手写数字识别的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

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

这篇文章主要为大家详细介绍了如何使用machinelearning机器学习模块进行手写数字识别功能,文中的示例代码讲解详细,感兴趣的可以了解一下
2022-11-13

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

看了上一篇内容之后,相信对K近邻算法有了一个清晰的认识,今天的内容——手写数字识别是对上一篇内容的延续,这里也是为了自己能更熟练的掌握k-NN算法。 我们有大约2000个训练样本和1000个左右测试样本,训练样本所在的文件夹是trainin
2022-06-04

Python-OpenCV中如何利用 KNN 算法识别手写数字

手写数字数据集 MNIST 介绍为了保证完整性,从算法所用的训练数据讲起,训练数据是由 MNIST 手写数字组成的,MNIST 数据集来自美国国家标准与技术研究所,由来自 250 个不同人手写的数字构成,其中训练集包含 60000 张图片,
2023-06-22

C++ OpenCV实现之实现红绿灯识别

本文以实现行车过程当中的红绿灯识别为目标,核心的内容包括:OpenCV轮廓识别原理以及OpenCV红绿灯识别的实现具体步骤,感兴趣的可以了解一下
2022-11-13

基于tensorflow实现Android手写数字识别

前段时间训练了mnist手写数字识别的模型,学习后将其移植到Android端 我是参考的大佬https://puke3615.github.io/2017/08/02/Run-Mnist-On-Android/,https://github
2022-06-06

C++中怎么用OpenCV实现手势识别

本篇内容介绍了“C++中怎么用OpenCV实现手势识别”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、手部关键点检测如图所示,为我们的手部
2023-06-29

pytorch如何实现手写数字图片识别

这篇文章给大家分享的是有关pytorch如何实现手写数字图片识别的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。具体内容如下数据集:MNIST数据集,代码中会自动下载,不用自己手动下载。数据集很小,不需要GPU设备
2023-06-15

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录