opencv——基于SVM的数字识别(2)

上篇文章我们用的特征是训练样本的所有像素点值,虽然方便但不准确。

这篇文章主要介绍用SVM+HOG特征对数字进行识别。

详细请看上篇文章,它们主要区别在于训练样本HOG特征的提取,其他基本一样,所以我直接附上代码。

下面代码是opencv3和C++

可以根据自己需要修改训练样本类别,数目,尺寸。oss的训练样本路径,src的检测图片路径。


#include <stdio.h>  
#include <time.h>  
#include <opencv2/opencv.hpp>  
#include <opencv/cv.h>  
#include <iostream> 
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/ml/ml.hpp>  
#include <io.h> //查找文件相关函数


using namespace std;
using namespace cv;
using namespace ml;
ostringstream oss;//结合字符串和数字
int num = -1;
Mat dealimage;
Mat src;
Mat yangben_gray;
Mat yangben_thresh;
void feature(Mat dealimage);

////===============================读取训练数据===============================////
const int classsum = 10;//训练图片共有10类,可修改
const int imagesSum = 500;//每类有500张图片,可修改	
int yangben_data_position = -1;
Mat data_mat = Mat(classsum*imagesSum, 8100, CV_32FC1);
//data_mat用来保存所有训练样本的HOG特征,每一列为一副图像的HOG特征
//每一行为每一幅训练图像
//必须为CV_32FC1的类型
//行、列、类型;第二个参数,即矩阵的列是由下面的descriptors的大小决定的,
//可以由descriptors.size()得到,且对于不同大小的输入训练图片,这个值是不同的 
//descriptors为提取到的HOG特征
int main()
{


	//训练数据,每一行一个训练图片
	Mat trainingData;
	//训练样本标签
	Mat labels;
	//最终的训练样本标签
	Mat clas;
	//最终的训练数据
	Mat traindata;

	//////////////////////从指定文件夹下提取图片//////////////////
	for (int p = 0; p < classsum; p++)//依次提取0到9文件夹中的图片
	{
		oss << "C:/Users/zhang/Desktop/opencv——实例/小案例/车牌检测/基于机器学习/模版匹配样本/";
		num += 1;//num从0到9
		int label = num;
		oss << num << "/*.jpg";//图片名字后缀,oss可以结合数字与字符串
		string pattern = oss.str();//oss.str()输出oss字符串,并且赋给pattern
		oss.str("");//每次循环后把oss字符串清空
		vector<Mat> input_images;
		vector<String> input_images_name;
		glob(pattern, input_images_name, false);
		//为false时,仅仅遍历指定文件夹内符合模式的文件,当为true时,会同时遍历指定文件夹的子文件夹
		//此时input_images_name存放符合条件的图片地址
		int all_num = input_images_name.size();
		//文件下总共有几个图片
		//cout << num << ":总共有" << all_num << "个图片待测试" << endl;

		for (int i = 0; i < imagesSum; i++)//依次循环遍历每个文件夹中的图片
		{
			cvtColor(imread(input_images_name[i]), yangben_gray, COLOR_BGR2GRAY);//灰度变换
			threshold(yangben_gray, yangben_thresh, 0, 255, THRESH_OTSU);//二值化
																		 //循环读取每张图片并且依次放在vector<Mat> input_images内
			input_images.push_back(yangben_thresh);
			dealimage = input_images[i];

			//选择了HOG的方式完成特征提取工作
			yangben_data_position += 1;//代表为第几幅图像
			feature(dealimage);//图片特征提取
			labels.push_back(label);//把每个图片对应的标签依次存入
			cout << "第" << yangben_data_position << "样本正在提取HOG特征" << endl;
		}
	}


	cout << "样本特征提取完毕,等待创建SVM模型" << endl;
	////===============================创建SVM模型===============================////
	// 创建分类器并设置参数
	Ptr<SVM> SVM_params = SVM::create();
	SVM_params->setType(SVM::C_SVC);//C_SVC用于分类,C_SVR用于回归
	SVM_params->setKernel(SVM::LINEAR);  //LINEAR线性核函数。SIGMOID为高斯核函数

	SVM_params->setDegree(0);//核函数中的参数degree,针对多项式核函数;
	SVM_params->setGamma(1);//核函数中的参数gamma,针对多项式/RBF/SIGMOID核函数; 
	SVM_params->setCoef0(0);//核函数中的参数,针对多项式/SIGMOID核函数;
	SVM_params->setC(1);//SVM最优问题参数,设置C-SVC,EPS_SVR和NU_SVR的参数;
	SVM_params->setNu(0);//SVM最优问题参数,设置NU_SVC, ONE_CLASS 和NU_SVR的参数; 
	SVM_params->setP(0);//SVM最优问题参数,设置EPS_SVR 中损失函数p的值. 
						//结束条件,即训练1000次或者误差小于0.01结束
	SVM_params->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 1000, 0.01));

	//训练数据和标签的结合
	Ptr<TrainData> tData = TrainData::create(data_mat, ROW_SAMPLE, labels);

	// 训练分类器
	SVM_params->train(tData);//训练

	//保存模型
	SVM_params->save("C:/Users/zhang/Desktop/opencv——实例/小案例/车牌检测/基于机器学习/字符识别svm.xml");
	cout << "训练好了!!!" << endl;


	cout << "等待识别" << endl;
	////===============================预测部分===============================////
	Mat src = imread("C:/Users/zhang/Desktop/opencv——实例/小案例/车牌检测/基于机器学习/检测到的车牌字符/字符7.jpg");
	cvtColor(src, src, COLOR_BGR2GRAY);
	threshold(src, src, 0, 255, CV_THRESH_OTSU);
	imshow("原图像", src);

	//输入图像取特征点
	Mat trainTempImg = Mat::zeros(Size(128, 128), CV_8UC1);
	resize(src, trainTempImg, trainTempImg.size());

	HOGDescriptor *hog = new HOGDescriptor(Size(128, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);
	vector<float>descriptors;//结果数组         
	hog->compute(trainTempImg, descriptors, Size(1, 1), Size(0, 0));
	//cout << "HOG描述子向量维数    " << descriptors.size() << endl;
	Mat SVMtrainMat = Mat(1, descriptors.size(), CV_32FC1);

	int  number1 = descriptors.size();
	//将计算好的HOG描述子复制到样本特征矩阵SVMtrainMat  
	for (int i = 0; i < number1; i++)
	{
		//把一幅图像的HOG描述子向量依次存入data_mat矩阵的同一列
		//因为输入图像只有一个,即SVMtrainMat只有一列,则为0
		SVMtrainMat.at<float>(0, i) = descriptors[i];  									  //  n++;
	}

	SVMtrainMat.convertTo(SVMtrainMat, CV_32FC1);//更改图片数据的类型,必要,不然会出错
	int ret = (int)SVM_params->predict(SVMtrainMat);//检测结果  
	cout << "识别的数字为:" << ret << endl;
	waitKey(0);
	return 0;
}



void feature(Mat dealimage)
{
	//把训练样本放大到128,128。便于HOG提取特征 
	Mat trainImg = Mat(Size(128, 128), CV_8UC1); 
	resize(dealimage, trainImg, trainImg.size());
	//处理HOG特征 
	//检测窗口(64,128),块尺寸(16,16),块步长(8,8),cell尺寸(8,8),直方图bin个数9  ,需要修改
	HOGDescriptor *hog = new HOGDescriptor(Size(128, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);
	vector<float>descriptors;//存放结果    为HOG描述子向量    
	hog->compute(trainImg, descriptors, Size(1, 1), Size(0, 0)); //Hog特征计算,检测窗口移动步长(1,1)     

	//cout << "HOG描述子向量维数    : " << descriptors.size() << endl;


	for (vector<float>::size_type j = 0; j < descriptors.size(); j++)
	{
		//把一幅图像的HOG描述子向量依次存入data_mat矩阵的同一列
		data_mat.at<float>(yangben_data_position, j) = descriptors[j];
	}
}

识别结果:

猜你喜欢

转载自blog.csdn.net/weixin_41721222/article/details/84978343