OpenCV训练SVM模型并预测的完整过程

1 批量读取一个文件夹中的所有照片

1、当文件中的图片命名有一定规则时:

for (int i = 1; i < 100; i++)   //100
	{
		stringstream ss;
		string str;
		ss << i;   // 将int输入流中
		ss >> str; // 将ss中的数值输出到str中
		string fileName = "E:\\test_opencv\\EasyPR-master\\resources\\train\\svm\\has\\train\\plate_" + str + ".jpg";
		files.push_back(fileName);
		Mat srcImage = imread(fileName);
		imshow("srcImage",srcImage);
		image.push_back(srcImage);
		labels.push_back(1);

	}

2、使用OpenCV的glob函数:

	fileName = "E:\\test_opencv\\EasyPR-master\\resources\\train\\svm\\no\\train\\*.jpg";
	glob(fileName,nofiles,false);
	for (int i = 0; i < nofiles.size(); i++) {
		Mat src = imread(nofiles[i]);
		image.push_back(src);
		labels.push_back(0);
	}

通过使用glob可以将pattern路径下的所用文件名存进result中.

void cv::glob ( String pattern, std::vector< String > & result, bool recursive = false 
)

 2 完整过程:

#include
#include
#include
#include

using namespace cv;
using namespace std;

void convert_to_ml(const vector< Mat > & train_samples, Mat& trainData)
{
	//--Convert data
	const int rows = (int)train_samples.size();
	const int cols = (int)train_samples[0].cols*train_samples[0].rows;
	trainData = Mat(rows, cols, CV_32FC1);//一定要类型转换32FC1
	for (int i = 0; i < train_samples.size(); ++i)
	{
		Mat p = train_samples[i].reshape(1, 1);//一行向量
		p.copyTo(trainData.row(i));//trainData.row(i)返回Mat类型
	}
}
int main() {
	string file;
	vector files;
	vector nofiles,testnofiles;
	vector image, testimage;
	vector labels;
	string fileName; 
	Mat srcImage,dst;
	for (int i = 1; i < 601; i++)   //600
	{
		stringstream ss;
		string str;
		ss << 1;
		ss >> str;
		fileName = "E:\\test_opencv\\EasyPR-master\\resources\\train\\svm\\has\\train\\plate_" + str + ".jpg";
		files.push_back(fileName);
		srcImage = imread(fileName);
		cvtColor(srcImage, dst, CV_RGB2GRAY);
		resize(dst, dst, Size(120, 30)); //30*120
		image.push_back(dst);
		labels.push_back(1);
	}
	fileName = "E:\\test_opencv\\EasyPR-master\\resources\\train\\svm\\no\\train\\*.jpg";
	glob(fileName,nofiles,false);
	for (int i = 0; i < 600; i++) {//nofiles.size()
		Mat src = imread(nofiles[i]);
		cvtColor(src, dst, CV_RGB2GRAY);//36*136
		resize(dst,dst,Size(120,30)); //30*120
		image.push_back(dst); 
		labels.push_back(0);
	}
	Mat traindata,testdata;
	convert_to_ml(image, traindata);
	Mat label = cv::Mat(labels);

	
	Ptr svm = ml::SVM::create();
	svm->setCoef0(0.0);
	svm->setKernel(ml::SVM::LINEAR);//RBF
	svm->setType(ml::SVM::C_SVC);
	svm->setTermCriteria(cv::TermCriteria(cv::TermCriteria::MAX_ITER, 100, 1e-6));
	svm->train(traindata, 0, label);
	cout << "train final" << endl;
	Mat supportvector=svm->getSupportVectors();

//////////////////////////////test//////////////////////////////////

	//单个样本预测
	Mat sample = traindata.row(3);
	float repon=svm->predict(sample);
	
	//多个样本预测
	Mat classa;
	Mat row = traindata.rowRange(1, 50).clone();
	svm->predict(row, classa);
	vector re;
	for (int i = 0; i < 49; i++) {
		float a = classa.at(i, 0);
		re.push_back(a);   //证明我们的预测器是可以正常工作的,只是追确率堪忧!!
	}

	//单个测试样本
	Mat src = imread("E:\\test_opencv\\EasyPR-master\\resources\\train\\svm\\has\\train\\plate_36.jpg");
	cvtColor(src, dst, CV_RGB2GRAY);//36*136
	resize(dst, dst, Size(120, 30));
	Mat s = dst.reshape(1, 1);
	s.convertTo(s, CV_32FC1);
	float r = svm->predict(s);

	//多个测试样本预测
	fileName = "E:\\test_opencv\\EasyPR-master\\resources\\train\\svm\\has\\test\\*.jpg";
	glob(fileName, testnofiles, false);
	for (int i = 0; i < 100; i++) {//nofiles.size()
		Mat src = imread(testnofiles[i]);
		cvtColor(src, dst, CV_RGB2GRAY);//36*136
		resize(dst, dst, Size(120, 30)); //30*120
		testimage.push_back(dst);
	}
	convert_to_ml(testimage, testdata);
	Mat class1;
	svm->predict(testdata, class1);
	vector reponse;
	for (int i = 0; i < 100; i++) {
		float a = class1.at(i, 0);
		reponse.push_back(a);
	}
 	waitKey(0);

}

有几点注意:

1、svm->train(traindata, 0, label);

原型:svm->train(trainingDataMat, cv::ml::ROW_SAMPLE, labelsMat));

traindata必须是  Mat(rows, cols, CV_32FC1)类型,label可以是Mat,也可以是vector.类型转换很简单:Mat label = cv::Mat(labels);

2、svm->predict(row, classa);既可以预测一个样本,也可以同时预测多个样本,预测多个样本时,row是一个n行的Mat。

3、reshape函数既可以改变矩阵的通道数,又可以对矩阵元素进行序列化,

函数原型:   C++: Mat Mat::reshape(int cn, int rows=0) const

  1. cn: 表示通道数(channels), 如果设为0,则表示保持通道数不变,否则则变为设置的通道数。
  2. rows: 表示矩阵行数。 如果设为0,则表示保持原有的行数不变,否则则变为设置的行数

你可能感兴趣的:(机器学习,opencv)