使用OpenCV的ANN_MLP神经网络实现数字识别

前言

1.OpenCV中的ML模块实现了前馈人工神经网络,具体地说是多层感知器(MLP),是最常用的神经网络类型。 MLP由输入层,输出层和一个或多个隐藏层组成。 MLP的每一层包括一个或多个与来自上一层和下一层的神经元定向连接的神经元。关于ANN_MLP的具体说明可以看opencv的官方文档
2.我这里要是使用ANN_MLP神经网络来实现0到9的印刷数字识别,使用的OpenCV版本是3.30,IDE是VS2015,实现语言是C++,还使用了boost来进行文件读取的相关操作。

样本准备

1.先准备0到9的样本,分别放在相应的文件目录下,这是我保存的格式:
在这里插入图片描述
2.每个目录下放着对的样本,我这里每个字母都有50个样本,对应的文件没有特殊要求。
在这里插入图片描述

代码

1.训练代码

//训练函数
//root_path样本地址
//model_path保存模型路径加文件名,后续为xml
void trainChar(string &root_path, string &model_path)
{
	vector<string> dir_path;
	int dir_number;
	getFileNameFromDir(root_path, dir_path, dir_number);
	//图像的行
	const int image_rows = 8;
	//图像的列
	const int image_cols = 16;
	//要训练的类别
	const int class_sum = 10;
	//每个类别的样本个数
	const int images_sum = 50;

	if (dir_number != class_sum)
	{
		cout << "要训练的种类与当前目录下的种类和差异!" << endl;
		return;
	}
	//每一行一个训练样本
	float trainingData[class_sum*images_sum][image_rows*image_cols] = { { 0 } };

	//训练样本标签
	float labels[class_sum*images_sum][class_sum] = { { 0 } };

	Mat src, resize_img, train_img;

	//这里读文件的方式不是很好,用boost会好一些
	for (int i = 0; i < dir_path.size(); i++)
	{
		//cout << dir_path.at(i) << endl;
		int k = 0;
		fs::directory_iterator begin_iter(dir_path.at(i));
		fs::directory_iterator end_iter;

		//获取该目录下的所有文件名
		for (; begin_iter != end_iter; ++begin_iter)
		{
			string image_path = begin_iter->path().string();
			src = imread(image_path, 0);
			if (src.empty())
			{
				cerr << "can not load image \n" << std::endl;
				exit(0);
			}
			//更改尺寸
			resize(src, resize_img, Size(image_rows, image_cols), (0, 0), (0, 0), INTER_AREA);
			//二值化
			threshold(resize_img, train_img, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);

			for (int j = 0; j < image_rows*image_cols; j++)
			{
				trainingData[i*images_sum + k][j] = (float)resize_img.data[j];
			}
			// 设置标签数据
			for (int j = 0; j < class_sum; j++)
			{
				if (j == i)
				{
					labels[i*images_sum + k][j] = 1;
				}
				else
				{
					labels[i*images_sum + k][j] = 0;
				}
			}
			k++;
		}
		Mat labelsMat(class_sum*images_sum, class_sum, CV_32FC1, labels);
	}

	//训练数据及标签
	Mat trainingDataMat(class_sum*images_sum, image_rows*image_cols, CV_32FC1, trainingData);
	Mat labelsMat(class_sum*images_sum, class_sum, CV_32FC1, labels);

	//设置参数
	Ptr<ANN_MLP>model = ANN_MLP::create();
	Mat layerSizes = (Mat_<int>(1, 5) << image_rows*image_cols, 128, 128, 128, class_sum);
	model->setLayerSizes(layerSizes);
	//训练方法为反向传播(这个跟深度学习的反向转播是一个道理)
	model->setTrainMethod(ANN_MLP::BACKPROP, 0.001, 0.1);
	// 激活函数设置为 sigmoid
	model->setActivationFunction(ANN_MLP::SIGMOID_SYM, 1.0, 1.0);
	model->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS, 10000, 0.0001));

	cout << "开始训练!" << endl;
	Ptr<TrainData> trainData = TrainData::create(trainingDataMat, ROW_SAMPLE, labelsMat);
	model->train(trainData);

	//保存模型
	model->save(model_path);
	
	cout << "训练完成" << endl;
}

//得到路径下第一层的文件夹的绝对路径
void getFileNameFromDir(string &root_path,vector<string> &dir_path, int &class_sum)
{
	class_sum = 0;
	vector<string> dir_name;
	fs::path dir(root_path);
	// 判断路径是否存在
	if (fs::exists(dir))
	{
		fs::directory_iterator itEnd;
		fs::directory_iterator itDir(dir);
		string file_name;
		// 遍历路径下所有文件
		
		for (; itDir != itEnd; itDir++)
		{
			file_name = itDir->path().string();
			// 判断文件是否是文件夹
			if (boost::filesystem::is_directory(file_name.c_str()))
			{
				dir_path.push_back(file_name);
				class_sum++;		
			}
		}
	}
}

训练代码调用方式:

//保存字符集的主目录
string char_path = "C:/code/DigitalRecognition/DigitalRecognition/numberChar/";
//训练好的模型保存的路径和文件名
string model_path = "C:/code/DigitalRecognition/DigitalRecognition/numberCharModel.xml";
trainChar(char_path,model_path);

2.测试代码

//测试模型
//src是要识别的图像
//model_path模型的路径
void useModel(Mat &src, string &model_path)
{
	if (src.empty())
	{
		cout << "当前传入的图像为空!" << endl;
		return;
	}
	if (src.channels() > 1)
	{
		cvtColor(src, src, CV_BGR2GRAY);
	}
	Mat dst;
	//图像的行
	const int image_rows = 8;
	//图像的列
	const int image_cols = 16;
	Ptr<ANN_MLP>model = ANN_MLP::create();
	model = cv::Algorithm::load<cv::ml::ANN_MLP>(model_path);

	//将测试图像转化为1*128的向量
	resize(src, src, Size(image_rows, image_cols), (0, 0), (0, 0), INTER_AREA);
	threshold(src, src, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
	Mat_<float> testMat(1, image_rows*image_cols);

	for (int i = 0; i < image_rows*image_cols; i++)
	{
		testMat.at<float>(0, i) = (float)src.at<uchar>(i / 8, i % 8);
	}
	//使用训练好的MLP model预测测试图像,把预测到的值放到dst里面
	model->predict(testMat, dst);

	cout << "dst:" << dst << endl;
	//选出最大值
	double maxVal = 0;
	Point maxLoc;
	minMaxLoc(dst, NULL, &maxVal, NULL, &maxLoc);
	cout << "测试结果:" << maxLoc.x << "置信度:" << maxVal * 100 << "%" << endl;
}

测试代码调用方式:

//训练好的模型保存的路径和文件名
string model_path = "C:/code/DigitalRecognition/DigitalRecognition/numberCharModel.xml";
//读取图像
Mat src = imread("src.png");
useModel(src,model_path);

运行结果:
在这里插入图片描述
在这里插入图片描述

结语

1.上面的所用到的样本,可以从我的资源上传那里得到。
2.如果在运行中有什么bug,可以找我之前的博客,下面有推荐的群,互相讨论学习。

  • 4
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
好的,下面是一个简单的实现步骤: 1. 收集字母图片数据集,并将其转换成灰度图像。 2. 提取图像特征,这里可以使用 OpenCV 中的 HOG 特征或者 SIFT 特征。 3. 将图像特征作为输入,字母标签作为输出,训练一个 MLP(多层感知器)神经网络。这里可以使用 scikit-learn 库中的 MLPClassifier 类。 4. 使用训练好的 MLP 神经网络对新的字母图像进行识别。 下面给出一个简单的代码示例,其中使用的是 HOG 特征和 MLPClassifier 类: ```python import cv2 from sklearn.neural_network import MLPClassifier from sklearn.metrics import classification_report, confusion_matrix # 读取数据集 data = cv2.imread("data.jpg", cv2.IMREAD_GRAYSCALE) labels = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"] # 提取特征 hog = cv2.HOGDescriptor((24, 24), (8, 8), (4, 4), (4, 4), 9) features = [] for i in range(len(data)): feature = hog.compute(data[i]) features.append(feature) # 训练 MLP 神经网络 mlp = MLPClassifier(hidden_layer_sizes=(100,)) mlp.fit(features, labels) # 测试 MLP 神经网络 test_data = cv2.imread("test.jpg", cv2.IMREAD_GRAYSCALE) test_feature = hog.compute(test_data) predicted_label = mlp.predict([test_feature]) print("Predicted label:", predicted_label) # 输出分类报告和混淆矩阵 predicted_labels = mlp.predict(features) print(classification_report(labels, predicted_labels)) print(confusion_matrix(labels, predicted_labels)) ``` 注意,这只是一个简单的示例,实际应用中可能需要更多的数据预处理和特征提取技巧,以及更复杂的神经网络架构。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知来者逆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值