C++版OpenCV使用支持向量机svm进行mnist手写数字识别

C++版OpenCV使用支持向量机svm进行mnist手写数字识别支持向量机svm也是一种机器学习算法,采用空间超平面进行数据分割,在这篇博客中我们将使用svm进行手写数字的识别,使用该算法,识别率可以达到100%。环境准备:vs2015OpenCV4.5.0下面的代码为svm模型训练代码:#include<iostream>#include<opencv.hpp>#include<string>#include<fstream>usingnamespacestd;usingnamespace

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

支持向量机svm也是一种机器学习算法,采用空间超平面进行数据分割,在这篇博客中我们将使用svm进行手写数字的识别,使用该算法,识别率可以达到96.72%。
环境准备:
vs2015
OpenCV4.5.0
下面的代码为svm模型训练代码:

#include<iostream>
#include<opencv.hpp>
#include <string>
#include <fstream>
using namespace std;
using namespace cv;


//小端存储转换
int reverseInt(int i);
//读取image数据集信息
Mat read_mnist_image(const string fileName);
//读取label数据集信息
Mat read_mnist_label(const string fileName);

string train_images_path = "G:/vs2015_opencv_ml/mnist/train-images.idx3-ubyte";
string train_labels_path = "G:/vs2015_opencv_ml/mnist/train-labels.idx1-ubyte";
string test_images_path = "G:/vs2015_opencv_ml/mnist/t10k-images.idx3-ubyte";
string test_labels_path = "G:/vs2015_opencv_ml/mnist/t10k-labels.idx1-ubyte";

int main()
{ 
   
	/* ---------第一部分:训练数据准备----------- */
	//读取训练标签数据 (60000,1) 类型为int32
	Mat train_labels = read_mnist_label(train_labels_path);

	//读取训练图像数据 (60000,784) 类型为float32 数据未归一化
	Mat train_images = read_mnist_image(train_images_path);
	//将图像数据归一化
	train_images = train_images / 255.0;

	//读取测试数据标签(10000,1) 类型为int32
	Mat test_labels = read_mnist_label(test_labels_path);

	//读取测试数据图像 (10000,784) 类型为float32 数据未归一化
	Mat test_images = read_mnist_image(test_images_path);
	//归一化
	test_images = test_images / 255.0;

	/* ---------第二部分:构建svm训练模型并进行训练----------- */
	cv::Ptr<cv::ml::SVM> svm = cv::ml::SVM::create();
	//设置类型为C_SVC代表分类
	svm->setType(cv::ml::SVM::C_SVC);
	//设置核函数
	svm->setKernel(cv::ml::SVM::POLY);
	//设置其它属性
	svm->setGamma(3.0);
	svm->setDegree(3.0);
	//设置迭代终止条件 
	svm->setTermCriteria(cv::TermCriteria(cv::TermCriteria::MAX_ITER | cv::TermCriteria::EPS, 300, 0.0001));

	//开始训练
	cv::Ptr<cv::ml::TrainData> train_data = cv::ml::TrainData::create(train_images, cv::ml::ROW_SAMPLE, train_labels);
	cout << "开始进行训练..." << endl;
	svm->train(train_data);
	cout << "训练完成" << endl;

	/* ---------第三部分:在测试数据集上预测计算准确率----------- */
	Mat pre_out;
	//返回值为第一个图像的预测值 pre_out为整个batch的预测值集合
	cout << "开始进行预测..." << endl;
	float ret = svm->predict(test_images, pre_out);
	cout << "预测完成" << endl;

	//计算准确率必须将两种标签化为同一数据类型
	pre_out.convertTo(pre_out, CV_8UC1);
	test_labels.convertTo(test_labels, CV_8UC1);

	int equal_nums = 0;
	for (int i = 0; i <pre_out.rows; i++)
	{ 
   
		if (pre_out.at<uchar>(i, 0) == test_labels.at<uchar>(i, 0))
		{ 
   
			equal_nums++;
		}
	}
	float acc = float(equal_nums) / float(pre_out.rows);
	cout << "测试数据集上的准确率为:" << acc * 100 << "%" << endl;

	//保存模型
	svm->save("mnist_svm.xml");


	getchar();
	return 0;
}


;

int reverseInt(int i) { 
   
	unsigned char c1, c2, c3, c4;

	c1 = i & 255;
	c2 = (i >> 8) & 255;
	c3 = (i >> 16) & 255;
	c4 = (i >> 24) & 255;

	return ((int)c1 << 24) + ((int)c2 << 16) + ((int)c3 << 8) + c4;
}

Mat read_mnist_image(const string fileName) { 
   
	int magic_number = 0;
	int number_of_images = 0;
	int n_rows = 0;
	int n_cols = 0;

	Mat DataMat;

	ifstream file(fileName, ios::binary);
	if (file.is_open())
	{ 
   
		cout << "成功打开图像集 ..." << endl;

		file.read((char*)&magic_number, sizeof(magic_number));//幻数(文件格式)
		file.read((char*)&number_of_images, sizeof(number_of_images));//图像总数
		file.read((char*)&n_rows, sizeof(n_rows));//每个图像的行数
		file.read((char*)&n_cols, sizeof(n_cols));//每个图像的列数

		magic_number = reverseInt(magic_number);
		number_of_images = reverseInt(number_of_images);
		n_rows = reverseInt(n_rows);
		n_cols = reverseInt(n_cols);
		cout << "幻数(文件格式):" << magic_number
			<< " 图像总数:" << number_of_images
			<< " 每个图像的行数:" << n_rows
			<< " 每个图像的列数:" << n_cols << endl;

		cout << "开始读取Image数据......" << endl;

		DataMat = Mat::zeros(number_of_images, n_rows * n_cols, CV_32FC1);
		for (int i = 0; i < number_of_images; i++) { 
   
			for (int j = 0; j < n_rows * n_cols; j++) { 
   
				unsigned char temp = 0;
				file.read((char*)&temp, sizeof(temp));
				//可以在下面这一步将每个像素值归一化
				float pixel_value = float(temp);
				//按照行将像素值一个个写入Mat中
				DataMat.at<float>(i, j) = pixel_value;
			}
		}

		cout << "读取Image数据完毕......" << endl;

	}
	file.close();
	return DataMat;
}

Mat read_mnist_label(const string fileName) { 
   
	int magic_number;
	int number_of_items;

	Mat LabelMat;

	ifstream file(fileName, ios::binary);
	if (file.is_open())
	{ 
   
		cout << "成功打开标签集 ... " << endl;

		file.read((char*)&magic_number, sizeof(magic_number));
		file.read((char*)&number_of_items, sizeof(number_of_items));
		magic_number = reverseInt(magic_number);
		number_of_items = reverseInt(number_of_items);

		cout << "幻数(文件格式):" << magic_number << " ;标签总数:" << number_of_items << endl;

		cout << "开始读取Label数据......" << endl;
		//CV_32SC1代表32位有符号整型 通道数为1
		LabelMat = Mat::zeros(number_of_items, 1, CV_32SC1);
		for (int i = 0; i < number_of_items; i++) { 
   
			unsigned char temp = 0;
			file.read((char*)&temp, sizeof(temp));
			LabelMat.at<unsigned int>(i, 0) = (unsigned int)temp;
		}
		cout << "读取Label数据完毕......" << endl;

	}
	file.close();
	return LabelMat;
}

执行上述代码,运行结果如下:

成功打开标签集 ...
幻数(文件格式):2049  ;标签总数:60000
开始读取Label数据......
读取Label数据完毕......
成功打开图像集 ...
幻数(文件格式):2051 图像总数:60000 每个图像的行数:28 每个图像的列数:28
开始读取Image数据......
读取Image数据完毕......
成功打开标签集 ...
幻数(文件格式):2049  ;标签总数:10000
开始读取Label数据......
读取Label数据完毕......
成功打开图像集 ...
幻数(文件格式):2051 图像总数:10000 每个图像的行数:28 每个图像的列数:28
开始读取Image数据......
读取Image数据完毕......
开始进行训练...
训练完成
开始进行预测...
预测完成
测试数据集上的准确率为:96.72%

可见svm模型对手写数字的准确率高达96.72%,下面调用该模型进行图片读取的识别。

#include<iostream>
#include<opencv.hpp>
using namespace std;
using namespace cv;

int main()
{ 
   
	//读取一张手写数字图片(28,28)
	Mat image = cv::imread("shuzi1.jpg", 0);
	Mat img_show = image.clone();
	//更换数据类型有uchar->float32
	image.convertTo(image, CV_32F);
	//归一化
	image = image / 255.0;
	//(1,784)
	image = image.reshape(1, 1);
	
	//加载svm模型
	cv::Ptr<cv::ml::SVM> svm = cv::ml::StatModel::load<cv::ml::SVM>("mnist_svm.xml");
	//预测图片
	float ret = svm->predict(image);
	cout << ret << endl;

	cv::imshow("img", img_show);
	cv::waitKey(0);
	getchar();
	return 0;
}

执行程序,运行结果如下:
在这里插入图片描述
由图所示,数字9能够正确识别。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/193947.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Depix从像素化屏幕快照中恢复密码

    Depix从像素化屏幕快照中恢复密码​Depix是一个从像素化屏幕截图中恢复密码的工具。此实现适用于使用线性盒过滤器创建的像素化图https://www.linkedin.com/pulse/recovering-passwords-from-pixelized-screenshots-sipke-mellema)介绍了像素化和类似研究的背景信息。##用法*将屏幕截图中的像素块剪成一个矩形。*粘贴DeBruijn序列在编辑器中具有相同字体设置(文本大小、字体、颜色、hsl)的预期字符。*制作序列的截图。如果可能,使用与创建像素化

    2022年6月18日
    24
  • 数据结构—完全二叉树「建议收藏」

    数据结构—完全二叉树「建议收藏」上篇博客介绍了一种非线性结构—普通树的含义以及一些特性,本文将介绍二叉树、满二叉树以及完全二叉树的一些特性及实现。首先,什么是二叉树?二叉树,是度为二的树,二叉树的每一个节点最多只有二个子节点,

    2022年6月30日
    25
  • TS 索引类型

    TS 索引类型interfacep{name:string;age:number;}consta:<P,Textendskeyofp>(P:p,T[p]);//说明T的取值受限于pkeyofp相当于’name’|’age’;

    2022年5月20日
    142
  • springboot实现拦截器_springmvc自定义拦截器

    springboot实现拦截器_springmvc自定义拦截器集成拦截器登录验证为例添加拦截器public class LoginInterceptor implements HandlerInterceptor { private Logger log = LoggerFactory.getLogger(getClass()); //Controller逻辑执行之前 @Override public boolean preHandle(HttpServletRequest request, HttpServletRe

    2022年8月8日
    5
  • 零散学习笔记(一)—-单相逆变电路设计

    零散学习笔记(一)—-单相逆变电路设计这几天帮别人设计然后画一个电路图,只设计电路图,没有具体实现功能。这题是一道电赛题,大家都知道设计一个电路简单,但是要具体实现功能可不是那么简单的。而本文章是最简单的一部分—电路部分,不涉及程序部分和调试。AC-DC电路设计电源输入电压为220V交流电压,在一般设计中只要是输入为220V交流电肯定需要将交流电转换成直流电压。一般有两个方法:模电方法:使用转换电路——整流(几个二极管组合起来把正负电压变成单向)–滤波(使波形平滑)–稳压(固定输出)–直流电压数电方法:使用DC-AC芯片进行转换(博

    2022年6月9日
    38
  • tomcat重启会重新解压war包吗_tomcat解压版

    tomcat重启会重新解压war包吗_tomcat解压版tomcat解压war包的一点例外

    2022年9月27日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号